import { createHash } from "node:crypto";
export function compareCodepoints(left, right) {
    const leftPoints = Array.from(left);
    const rightPoints = Array.from(right);
    const length = Math.min(leftPoints.length, rightPoints.length);
    for (let index = 0; index < length; index += 1) {
        const leftCode = leftPoints[index]?.codePointAt(0) ?? 0;
        const rightCode = rightPoints[index]?.codePointAt(0) ?? 0;
        if (leftCode !== rightCode)
            return leftCode - rightCode;
    }
    return leftPoints.length - rightPoints.length;
}
export function stableJsonStringify(value) {
    if (value === null)
        return "null";
    if (typeof value === "string")
        return JSON.stringify(value);
    if (typeof value === "number")
        return Number.isFinite(value) ? String(value) : "null";
    if (typeof value === "boolean")
        return value ? "true" : "false";
    if (typeof value === "undefined" || typeof value === "function" || typeof value === "symbol") {
        return "null";
    }
    if (Array.isArray(value)) {
        return `[${value.map((entry) => stableJsonStringify(entry)).join(",")}]`;
    }
    if (typeof value === "object") {
        const objectValue = value;
        const entries = Object.entries(objectValue)
            .filter(([, entryValue]) => entryValue !== undefined)
            .sort(([left], [right]) => compareCodepoints(left, right));
        return `{${entries
            .map(([key, entryValue]) => `${JSON.stringify(key)}:${stableJsonStringify(entryValue)}`)
            .join(",")}}`;
    }
    return "null";
}
export function sha256Hex(value) {
    return createHash("sha256").update(value, "utf8").digest("hex");
}
export function stableValueHash(value) {
    return sha256Hex(stableJsonStringify(value));
}
