Files
playbook/antigravity-awesome-skills/tools/lib/aas-v1/canonical-json.js
T
2026-07-18 00:02:59 +00:00

46 lines
1.5 KiB
JavaScript

"use strict";
const crypto = require("node:crypto");
function assertCanonicalValue(value, path = "$") {
if (value === undefined || typeof value === "function" || typeof value === "symbol" || typeof value === "bigint") {
throw new TypeError(`Unsupported canonical JSON value at ${path}`);
}
if (typeof value === "number" && !Number.isFinite(value)) {
throw new TypeError(`Non-finite canonical JSON number at ${path}`);
}
if (Array.isArray(value)) {
value.forEach((entry, index) => assertCanonicalValue(entry, `${path}[${index}]`));
return;
}
if (value && typeof value === "object") {
const prototype = Object.getPrototypeOf(value);
if (prototype !== Object.prototype && prototype !== null) {
throw new TypeError(`Non-plain canonical JSON object at ${path}`);
}
for (const [key, entry] of Object.entries(value)) assertCanonicalValue(entry, `${path}.${key}`);
}
}
function canonicalize(value) {
if (Array.isArray(value)) return value.map(canonicalize);
if (value && typeof value === "object") {
return Object.fromEntries(
Object.keys(value).sort().map((key) => [key, canonicalize(value[key])]),
);
}
return value;
}
function canonicalJson(value) {
assertCanonicalValue(value);
return JSON.stringify(canonicalize(value));
}
function sha256(value) {
const bytes = Buffer.isBuffer(value) ? value : Buffer.from(String(value));
return `sha256-${crypto.createHash("sha256").update(bytes).digest("hex")}`;
}
module.exports = { assertCanonicalValue, canonicalize, canonicalJson, sha256 };