Files
rea/src/composition/javascriptAnalysisWorkerProcess.ts
T
morluto c923fb0dc9 fix(javascript): retain compiler-dependent module resolution facts
Compare import and require outcomes for static TypeScript references when compiler options are unknown. Preserve branch facts through worker IR and both graph projections; retain declaration fallbacks as candidates without changing explicitly selected paths.

Validation: 210 focused resolver and semantic tests; 21 production-boundary and source-extension tests. A bounded 2,000-reference probe adds about 16–17 ms wall time for dual resolution; full task token costs and real compiled application behavior remain unmeasured.
2026-10-13 15:58:25 +08:00

98 lines
3.6 KiB
TypeScript

import { moduleResolutionModeForJavaScriptReference } from "../domain/javascript/javascriptModuleResolutionMode.js";
import { parseJavaScriptSource } from "../domain/javascript/javascriptSourceParser.js";
import { analyzeParsedJavaScriptStaticSourceSteps } from "../domain/javascript/javascriptStaticAnalysis.js";
import {
analyzeParsedJavaScriptSemanticsSteps,
classifyParsedJavaScriptOpenReceiversSteps,
} from "../domain/javascript/javascriptSemanticAnalysis.js";
import { failedJavaScriptStaticAnalysis } from "../domain/javascript/javascriptStaticAnalysisHelpers.js";
import { projectJavaScriptModuleSemantics } from "../domain/javascript/javascriptModuleSemanticIr.js";
import {
javaScriptTransferByteBudget,
measureJavaScriptModuleTransfer,
} from "../javascript/analysis/JavaScriptAnalysisTransfer.js";
import { AnalysisResourceConstraintError } from "../domain/analysisErrorCore.js";
import { projectJavaScriptSemanticFileSteps } from "../application/javascript/JavaScriptSemanticGraphBuilder.js";
import { completeJavaScriptAnalysisSteps } from "../application/javascript/JavaScriptAnalysisControl.js";
import {
serveJavaScriptAnalysisWorker,
type JavaScriptSourceWorkerAnalyzer,
} from "../javascript/analysis/JavaScriptAnalysisWorkerServer.js";
const analyze: JavaScriptSourceWorkerAnalyzer = async (
file,
nodeBudget,
callbacks,
) => {
if (!file.text.included)
throw new TypeError("JavaScript worker requires decoded source text");
await callbacks.phase("parse");
let parsed = parseJavaScriptSource(file.text.value, file.path);
if (parsed === null) {
await callbacks.checkpoint(failedJavaScriptStaticAnalysis());
return null;
}
await callbacks.phase("static");
const receivers = await completeJavaScriptAnalysisSteps(
classifyParsedJavaScriptOpenReceiversSteps(parsed),
);
const facts = await completeJavaScriptAnalysisSteps(
analyzeParsedJavaScriptStaticSourceSteps(
file.text.value,
parsed,
receivers,
),
);
const resultBudgetBytes = await callbacks.checkpoint(facts);
if (facts.parse_status === "failed") return null;
if (resultBudgetBytes === 0)
throw new AnalysisResourceConstraintError(
"analyze_javascript_application",
"memory",
`The parent reserved its remaining result capacity for static observations; semantic analysis of ${file.path} was not started`,
{ semantic_result_budget_bytes: 0 },
);
await callbacks.phase("semantic");
const ir = await completeJavaScriptAnalysisSteps(
analyzeParsedJavaScriptSemanticsSteps(
parsed,
moduleResolutionModeForJavaScriptReference(file.path, "static-import"),
),
);
parsed = null;
const module = projectJavaScriptModuleSemantics(ir);
const measured = measureJavaScriptModuleTransfer(
module,
javaScriptTransferByteBudget(resultBudgetBytes),
);
if (measured.retentionBytes > resultBudgetBytes)
throw new AnalysisResourceConstraintError(
"analyze_javascript_application",
"memory",
`Completed module facts for ${file.path} exceed the parent's offered result budget; static facts were retained`,
{
semantic_result_budget_bytes: resultBudgetBytes,
module_transfer_bytes: measured.bytes,
},
);
await callbacks.phase("projection");
const projection = await completeJavaScriptAnalysisSteps(
projectJavaScriptSemanticFileSteps(
file,
ir,
nodeBudget,
facts.electron.call_paths,
),
);
return { module, projection };
};
try {
await serveJavaScriptAnalysisWorker(analyze);
} catch (cause: unknown) {
process.stderr.write(
`${cause instanceof Error ? cause.message : String(cause)}\n`,
);
process.exitCode = 1;
}