mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
refactor(javascript): use shared canonical identity primitives
This commit is contained in:
1 parent
719d56ebfe
commit
34aa22d0aa
6 files changed
+51
-107
No files matched your search
@@ -1,9 +1,7 @@
|
||||
import { uniqueSorted } from "../canonicalOrdering.js";
|
||||
import { compareUnicodeCodePoints } from "../unicodeCodePointOrder.js";
|
||||
import {
|
||||
canonicalExportShapeValue,
|
||||
digestExportShapeValue,
|
||||
} from "./javascriptExportShapeComparisonIdentity.js";
|
||||
import { canonicalJson } from "../comparisonSemantics.js";
|
||||
import { digestCanonicalValue } from "../canonicalDigest.js";
|
||||
import {
|
||||
javaScriptExportShapeComparisonResultSchema,
|
||||
type JavaScriptExportShapeComparisonChange,
|
||||
@@ -86,7 +84,7 @@ export const compareJavaScriptExportShapes = (
|
||||
};
|
||||
return javaScriptExportShapeComparisonResultSchema.parse({
|
||||
...semantic,
|
||||
comparison_id: `jesc_${digestExportShapeValue(semantic)}`,
|
||||
comparison_id: `jesc_${digestCanonicalValue(semantic, "JavaScript export shape comparison")}`,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -97,14 +95,17 @@ const sortChanges = (
|
||||
.map((change, index) => ({
|
||||
change,
|
||||
index,
|
||||
sortKey: canonicalExportShapeValue({
|
||||
discriminant: change.discriminant,
|
||||
path: change.path,
|
||||
status: change.status,
|
||||
left_source_range: change.left_source_range,
|
||||
right_source_range: change.right_source_range,
|
||||
change_id: change.change_id,
|
||||
}),
|
||||
sortKey: canonicalJson(
|
||||
{
|
||||
discriminant: change.discriminant,
|
||||
path: change.path,
|
||||
status: change.status,
|
||||
left_source_range: change.left_source_range,
|
||||
right_source_range: change.right_source_range,
|
||||
change_id: change.change_id,
|
||||
},
|
||||
"JavaScript export shape comparison",
|
||||
),
|
||||
}))
|
||||
.sort(
|
||||
(left, right) =>
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import { createHash } from "node:crypto";
|
||||
|
||||
import canonicalize from "canonicalize";
|
||||
|
||||
/**
|
||||
* Canonically encode one export-shape comparison value.
|
||||
*
|
||||
* Comparison identifiers hash the full result semantics, including each
|
||||
* change's presence object and the per-variant property inventories.
|
||||
*/
|
||||
export const canonicalExportShapeValue = (value: unknown): string => {
|
||||
const encoded = canonicalize(value);
|
||||
if (encoded === undefined)
|
||||
throw new TypeError(
|
||||
"JavaScript export shape comparison could not canonicalize data",
|
||||
);
|
||||
return encoded;
|
||||
};
|
||||
|
||||
/** Derive one deterministic SHA-256 comparison identifier component. */
|
||||
export const digestExportShapeValue = (value: unknown): string =>
|
||||
createHash("sha256").update(canonicalExportShapeValue(value)).digest("hex");
|
||||
@@ -1,7 +1,5 @@
|
||||
import {
|
||||
canonicalExportShapeValue,
|
||||
digestExportShapeValue,
|
||||
} from "./javascriptExportShapeComparisonIdentity.js";
|
||||
import { canonicalJson } from "../comparisonSemantics.js";
|
||||
import { digestCanonicalValue } from "../canonicalDigest.js";
|
||||
import type {
|
||||
JavaScriptExportShapeComparisonChange,
|
||||
JavaScriptExportShapeComparisonResult,
|
||||
@@ -195,7 +193,10 @@ const discriminantOccurrences = (
|
||||
const value = literalValue(field);
|
||||
if (!value.found) continue;
|
||||
const discriminant = { path: field.path, value: value.value };
|
||||
const key = canonicalExportShapeValue(discriminant);
|
||||
const key = canonicalJson(
|
||||
discriminant,
|
||||
"JavaScript export shape comparison",
|
||||
);
|
||||
const current = output.get(key);
|
||||
output.set(key, {
|
||||
discriminant,
|
||||
@@ -254,8 +255,8 @@ const compareDiscriminants = (
|
||||
right: Discriminant,
|
||||
): number =>
|
||||
compareUnicodeCodePoints(
|
||||
canonicalExportShapeValue(left),
|
||||
canonicalExportShapeValue(right),
|
||||
canonicalJson(left, "JavaScript export shape comparison"),
|
||||
canonicalJson(right, "JavaScript export shape comparison"),
|
||||
);
|
||||
|
||||
const selectionUnknownChange = (
|
||||
@@ -385,8 +386,8 @@ const fieldChangeStatus = ({
|
||||
if (
|
||||
leftField !== undefined &&
|
||||
rightField !== undefined &&
|
||||
canonicalExportShapeValue(leftField) ===
|
||||
canonicalExportShapeValue(rightField)
|
||||
canonicalJson(leftField, "JavaScript export shape comparison") ===
|
||||
canonicalJson(rightField, "JavaScript export shape comparison")
|
||||
)
|
||||
return null;
|
||||
if (leftPresence === "absent" && rightPresence === "absent") return null;
|
||||
@@ -502,7 +503,7 @@ const changeWithId = (
|
||||
semantic: Omit<JavaScriptExportShapeComparisonChange, "change_id">,
|
||||
): JavaScriptExportShapeComparisonChange => ({
|
||||
...semantic,
|
||||
change_id: `jesc_change_${digestExportShapeValue(semantic)}`,
|
||||
change_id: `jesc_change_${digestCanonicalValue(semantic, "JavaScript export shape comparison")}`,
|
||||
});
|
||||
|
||||
const literalValue = (
|
||||
|
||||
@@ -1,18 +1,9 @@
|
||||
import canonicalize from "canonicalize";
|
||||
import { canonicalJson } from "../comparisonSemantics.js";
|
||||
import {
|
||||
javaScriptSemanticGraphSchema,
|
||||
type JavaScriptSemanticGraph,
|
||||
} from "./javascriptSemanticGraph.js";
|
||||
|
||||
const canonicalJson = (value: unknown): string => {
|
||||
const encoded = canonicalize(value);
|
||||
if (encoded === undefined)
|
||||
throw new TypeError(
|
||||
"JavaScript semantic graph could not canonicalize data",
|
||||
);
|
||||
return encoded;
|
||||
};
|
||||
|
||||
/** Parse a stored semantic graph and reject stale IDs. */
|
||||
export const parseJavaScriptSemanticGraph = (
|
||||
input: unknown,
|
||||
@@ -20,4 +11,7 @@ export const parseJavaScriptSemanticGraph = (
|
||||
|
||||
/** Serialize a verified semantic graph as canonical JSON. */
|
||||
export const serializeJavaScriptSemanticGraph = (input: unknown): string =>
|
||||
canonicalJson(parseJavaScriptSemanticGraph(input));
|
||||
canonicalJson(
|
||||
parseJavaScriptSemanticGraph(input),
|
||||
"JavaScript semantic graph",
|
||||
);
|
||||
@@ -1,6 +1,4 @@
|
||||
import { createHash } from "node:crypto";
|
||||
|
||||
import canonicalize from "canonicalize";
|
||||
import { digestCanonicalValue } from "../canonicalDigest.js";
|
||||
|
||||
import type { JavaScriptSemanticGraph } from "./javascriptSemanticGraph.js";
|
||||
import type { JavaScriptSemanticGraphNode } from "./javascriptSemanticGraphSchemas.js";
|
||||
@@ -8,44 +6,30 @@ import { uniqueSorted } from "../canonicalOrdering.js";
|
||||
import { compareUnicodeCodePoints } from "../unicodeCodePointOrder.js";
|
||||
import type { JavaScriptSemanticQueryInput } from "./javascriptSemanticQuerySchemas.js";
|
||||
|
||||
/** Canonical JSON used by semantic query commitments and ordering. */
|
||||
export const canonicalJavaScriptSemanticQueryJson = (
|
||||
value: unknown,
|
||||
): string => {
|
||||
const encoded = canonicalize(value);
|
||||
if (encoded === undefined)
|
||||
throw new TypeError(
|
||||
"JavaScript semantic query could not canonicalize data",
|
||||
);
|
||||
return encoded;
|
||||
};
|
||||
|
||||
const digest = (value: unknown): string =>
|
||||
createHash("sha256")
|
||||
.update(canonicalJavaScriptSemanticQueryJson(value))
|
||||
.digest("hex");
|
||||
|
||||
/** Derive the stable identity for one graph-bound query. */
|
||||
export const javaScriptSemanticQueryIdentifier = (
|
||||
graph: JavaScriptSemanticGraph,
|
||||
input: JavaScriptSemanticQueryInput,
|
||||
): string => {
|
||||
const semantic = input;
|
||||
return `jsrq_${digest({
|
||||
source_graph_id: graph.graph_id,
|
||||
...semantic,
|
||||
allowed_relations:
|
||||
semantic.allowed_relations === undefined
|
||||
? undefined
|
||||
: uniqueSorted(semantic.allowed_relations),
|
||||
expected:
|
||||
semantic.expected === null
|
||||
? null
|
||||
: {
|
||||
...semantic.expected,
|
||||
classes: uniqueSorted(semantic.expected.classes),
|
||||
},
|
||||
})}`;
|
||||
return `jsrq_${digestCanonicalValue(
|
||||
{
|
||||
source_graph_id: graph.graph_id,
|
||||
...semantic,
|
||||
allowed_relations:
|
||||
semantic.allowed_relations === undefined
|
||||
? undefined
|
||||
: uniqueSorted(semantic.allowed_relations),
|
||||
expected:
|
||||
semantic.expected === null
|
||||
? null
|
||||
: {
|
||||
...semantic.expected,
|
||||
classes: uniqueSorted(semantic.expected.classes),
|
||||
},
|
||||
},
|
||||
"JavaScript semantic query",
|
||||
)}`;
|
||||
};
|
||||
|
||||
/** Resolve deterministic seed candidates without applying traversal limits. */
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { createHash } from "node:crypto";
|
||||
|
||||
import canonicalize from "canonicalize";
|
||||
import { digestCanonicalValue } from "./canonicalDigest.js";
|
||||
import { z } from "zod";
|
||||
|
||||
import { artifactComparisonResultSchema } from "./artifactComparison.js";
|
||||
@@ -238,7 +236,7 @@ const correlate = (
|
||||
hypothesis: mapping.hypothesis,
|
||||
} satisfies JsonValue;
|
||||
return correlationItemSchema.parse({
|
||||
correlation_id: `cor_${sha256(canonicalJson(projection))}`,
|
||||
correlation_id: `cor_${digestCanonicalValue(projection, "Static/runtime correlation")}`,
|
||||
static: { ...mapping.static, ...selectedStatic },
|
||||
runtime: { ...mapping.runtime, status: runtimeStatus },
|
||||
side_alignment: mapping.side_alignment,
|
||||
@@ -411,15 +409,3 @@ const assertUnique = (evidence: readonly Evidence[], label: string): void => {
|
||||
`Static/runtime correlation rejects duplicate ${label}`,
|
||||
);
|
||||
};
|
||||
|
||||
const sha256 = (value: string): string =>
|
||||
createHash("sha256").update(value).digest("hex");
|
||||
|
||||
const canonicalJson = (value: JsonValue): string => {
|
||||
const serialized = canonicalize(value);
|
||||
if (serialized === undefined)
|
||||
throw new TypeError(
|
||||
"RFC 8785 canonicalization rejected correlation mapping",
|
||||
);
|
||||
return serialized;
|
||||
};
|
||||
Reference in new issue
Block a user