mirror of
https://github.com/morluto/rea.git
synced 2026-10-27 09:55:46 +00:00
fix(javascript): bound semantic expansion and resolve lexical receivers
This commit is contained in:
1 parent
eaf5734083
commit
16f4609d68
26 files changed
+868
-78
No files matched your search
@@ -1,3 +1,4 @@
|
||||
import * as t from "@babel/types";
|
||||
import { expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
@@ -13,7 +14,12 @@ import {
|
||||
import type { JavaScriptArtifactAnalysis } from "./JavaScriptArtifactAnalysisTypes.js";
|
||||
import type { JavaScriptArtifactFile } from "../../domain/javascript/javascriptArtifactFiles.js";
|
||||
import { queryJavaScriptSemanticGraph } from "../../domain/javascript/javascriptSemanticQuery.js";
|
||||
import { analyzeJavaScriptSemantics } from "../../domain/javascript/javascriptSemanticAnalysis.js";
|
||||
import {
|
||||
analyzeJavaScriptSemantics,
|
||||
analyzeParsedJavaScriptSemantics,
|
||||
} from "../../domain/javascript/javascriptSemanticAnalysis.js";
|
||||
import { parseJavaScriptSource } from "../../domain/javascript/javascriptSourceParser.js";
|
||||
import { semanticCoverageResourceLimits } from "../../domain/javascript/javascriptSemanticCoverage.js";
|
||||
|
||||
const SHA256 = "a".repeat(64);
|
||||
const GRAPH_ID = `jag_${"b".repeat(64)}`;
|
||||
@@ -86,6 +92,70 @@ it("keeps dynamic calls explicit and returns complete deterministic results", ()
|
||||
expect(repeated).toEqual(first);
|
||||
});
|
||||
|
||||
it("preserves primitive candidate budget unknowns in semantic graph coverage", () => {
|
||||
const term = '(true ? "a" : "b")';
|
||||
const source = `const answer = ${Array.from({ length: 20 }, () => term).join(" + ")};`;
|
||||
const ir = analyzeJavaScriptSemantics(source);
|
||||
const graph = graphFor(source, ir);
|
||||
|
||||
expect(ir.coverage).toMatchObject({
|
||||
status: "partial",
|
||||
resourceLimits: ["primitive-candidates"],
|
||||
});
|
||||
expect(graph.unknowns).toContainEqual(
|
||||
expect.objectContaining({
|
||||
family: "data-flow",
|
||||
reason: "resource-limit",
|
||||
detail: expect.stringMatching(/primitive candidate budget exceeded/i),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("retains resource-limit reasons at nested object property slots", () => {
|
||||
const term = '(true ? "a" : "b")';
|
||||
const source = `const answer = { nested: { value: ${Array.from({ length: 20 }, () => term).join(" + ")} } };`;
|
||||
const ir = analyzeJavaScriptSemantics(source);
|
||||
const graph = graphFor(source, ir);
|
||||
|
||||
expect(semanticCoverageResourceLimits(ir.coverage)).toEqual([
|
||||
"primitive-candidates",
|
||||
]);
|
||||
expect(graph.unknowns).toContainEqual(
|
||||
expect.objectContaining({
|
||||
family: "object-flow",
|
||||
reason: "resource-limit",
|
||||
detail: expect.stringMatching(/Unknown value at property:value/u),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("preserves deep expression resource reasons through graph projection", () => {
|
||||
const source = "const answer = true;";
|
||||
const parsed = parseJavaScriptSource(source);
|
||||
const declaration = parsed?.program.body[0];
|
||||
const declarator = t.isVariableDeclaration(declaration)
|
||||
? declaration.declarations[0]
|
||||
: undefined;
|
||||
if (parsed === null || !t.isVariableDeclarator(declarator))
|
||||
throw new Error("Expected parsed binding initializer");
|
||||
let expression: t.Expression = t.booleanLiteral(true);
|
||||
for (let index = 0; index < 5_000; index += 1)
|
||||
expression = t.unaryExpression("!", expression, true);
|
||||
declarator.init = expression;
|
||||
const ir = analyzeParsedJavaScriptSemantics(parsed);
|
||||
const graph = graphFor(source, ir);
|
||||
|
||||
expect(semanticCoverageResourceLimits(ir.coverage)).toEqual([
|
||||
"expression-depth",
|
||||
]);
|
||||
expect(graph.unknowns).toContainEqual(
|
||||
expect.objectContaining({
|
||||
reason: "resource-limit",
|
||||
detail: expect.stringMatching(/expression depth budget exceeded/i),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps ambiguous interprocedural flow out of the default traversal", () => {
|
||||
const graph = graphFor(`
|
||||
function left(value) { return value; }
|
||||
@@ -257,7 +327,7 @@ it("keeps duplicate function fingerprints ambiguous", () => {
|
||||
expect(query.summary.total_seed_matches).toBe(2);
|
||||
});
|
||||
|
||||
const graphFor = (source: string) => {
|
||||
const graphFor = (source: string, ir = analyzeJavaScriptSemantics(source)) => {
|
||||
const file: JavaScriptArtifactFile = {
|
||||
path: "app.js",
|
||||
container_sha256: SHA256,
|
||||
@@ -273,9 +343,7 @@ const graphFor = (source: string) => {
|
||||
{
|
||||
file,
|
||||
javascript: null,
|
||||
semantic: {
|
||||
ir: analyzeJavaScriptSemantics(source),
|
||||
},
|
||||
semantic: { ir },
|
||||
},
|
||||
],
|
||||
packages: [],
|
||||
|
||||
Reference in new issue
Block a user