perf(javascript): derive the application graph ID once

createJavaScriptApplicationGraph hashed the whole graph to derive its
graph_id, then parsed it with the public schema, whose invariant check
hashed the same content again to verify that ID. Validate the content
with every other invariant first, then derive graph_id once from the
validated copy. The public schema still verifies graph_id for stored
and untrusted graphs, and created graphs are unchanged.
This commit is contained in:
keemsisi 2026-10-10 08:09:18 +01:00 committed by GitHub
parent 79f6756239
commit 934ffd28d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 31 additions and 6 deletions

View File

@ -547,6 +547,21 @@ describe("JavaScript Application Graph: source maps and observations", () => {
/Edge identifier/u,
);
});
it("creates exactly the graph the public schema accepts", () => {
const graph = buildSyntheticJavaScriptApplicationGraph();
expect(JSON.stringify(graph)).toBe(
JSON.stringify(
javascriptApplicationGraphSchema.parse(structuredClone(graph)),
),
);
const { graph_id: _graphId, ...semantic } = structuredClone(graph);
firstOf(semantic.edges, "edge").edge_id = `jag_edge_${"f".repeat(64)}`;
expect(() => createJavaScriptApplicationGraph(semantic)).toThrow(
/Edge identifier/u,
);
});
});
describe("JavaScript Application Graph: duplicate and orphan rejection", () => {

View File

@ -304,8 +304,8 @@ const checkNode = (
type GraphRecord = z.infer<typeof javascriptApplicationGraphRecordSchema>;
const checkGraphInvariants = (
graph: GraphRecord,
const checkGraphContent = (
graph: JavaScriptApplicationGraphInput,
context: z.RefinementCtx,
): void => {
sortedUniqueIssue(
@ -394,7 +394,13 @@ const checkGraphInvariants = (
context,
);
}
};
const checkGraphInvariants = (
graph: GraphRecord,
context: z.RefinementCtx,
): void => {
checkGraphContent(graph, context);
const { graph_id: identifier, ...semantic } = graph;
if (
identifier !==
@ -411,6 +417,9 @@ const checkGraphInvariants = (
export const javascriptApplicationGraphSchema =
javascriptApplicationGraphRecordSchema.superRefine(checkGraphInvariants);
const javascriptApplicationGraphContentSchema =
javascriptApplicationGraphInputSchema.superRefine(checkGraphContent);
/** Fully validated JavaScript Application Graph. */
export type JavaScriptApplicationGraph = z.infer<
typeof javascriptApplicationGraphSchema
@ -482,10 +491,11 @@ export const createJavaScriptApplicationGraph = (
},
limitations: uniqueSorted(parsed.limitations),
};
return javascriptApplicationGraphSchema.parse({
...semantic,
graph_id: `jag_${digestCanonicalValue(semantic, "JavaScript Application Graph")}`,
});
const content = javascriptApplicationGraphContentSchema.parse(semantic);
return {
...content,
graph_id: `jag_${digestCanonicalValue(content, "JavaScript Application Graph")}`,
};
};
const validatedImmutableApplicationGraphs = new WeakSet<object>();