refactor(javascript): remove superseded full-IR analysis pipeline

This commit is contained in:
morluto committed 2026-10-24 23:49:25 +08:00
1 parent cc7cc8155a
commit e9abf39848
21 files changed
+410 -479

No files matched your search

@@ -1,17 +1,8 @@
import { createHash } from "node:crypto";
import { moduleResolutionModeForJavaScriptReference } from "../../domain/javascript/javascriptModuleResolutionMode.js";
import { setImmediate } from "node:timers/promises";
import { resolveJavaScriptSourceMapReferences } from "../../domain/javascript/javascriptSourceMapPaths.js";
import { analyzeParsedJavaScriptStaticSourceSteps } from "../../domain/javascript/javascriptStaticAnalysis.js";
import { analyzeParsedJavaScriptSemanticsSteps } from "../../domain/javascript/javascriptSemanticAnalysis.js";
import type { JavaScriptSemanticIr } from "../../domain/javascript/javascriptSemanticIr.js";
import {
type JavaScriptModuleSemanticIr,
projectJavaScriptModuleSemantics,
} from "../../domain/javascript/javascriptModuleSemanticIr.js";
import { parseJavaScriptSource } from "../../domain/javascript/javascriptSourceParser.js";
import { hasValidSourceMapContents } from "../../domain/sourceMapContents.js";
import {
inspectSourceMapEnvelope,
@@ -20,7 +11,6 @@ import {
} from "../../domain/sourceMapEnvelope.js";
import type { SourceMapLeaf } from "../../domain/sourceMapEnvelope.js";
import type { JavaScriptStaticAnalysis } from "../../domain/javascript/javascriptStaticAnalysisTypes.js";
import { failedJavaScriptStaticAnalysis } from "../../domain/javascript/javascriptStaticAnalysisHelpers.js";
import type {
JavaScriptArtifactFile,
JavaScriptArtifactFileSet,
@@ -34,7 +24,6 @@ import type {
JavaScriptArtifactAnalysisFailure,
JavaScriptArtifactAnalysisScope,
JavaScriptArtifactAnalysis,
JavaScriptModuleArtifactAnalysis,
JavaScriptHtmlInlineScriptsObservation,
JavaScriptHtmlScriptObservation,
JavaScriptJsonModuleObservation,
@@ -48,7 +37,7 @@ import {
JavaScriptJsonDocuments,
type JavaScriptJsonDocumentFacts,
} from "./JavaScriptJsonDocuments.js";
import { completeJavaScriptAnalysisSteps } from "./JavaScriptAnalysisControl.js";
import { assertJavaScriptAnalysisActive } from "./JavaScriptAnalysisControl.js";
import { htmlArtifactReferences } from "../../domain/javascript/htmlArtifactReferences.js";
import type { JavaScriptSourceAnalysisPort } from "../../domain/javascript/javascriptSourceAnalysis.js";
import type { JavaScriptSemanticGraphProjection } from "./JavaScriptSemanticGraphBuilder.js";
@@ -62,11 +51,9 @@ import {
AnalysisTimeoutError,
} from "../../domain/analysisErrorCore.js";
interface MutableArtifactAnalysis<
SemanticIr extends JavaScriptModuleSemanticIr,
> {
interface MutableArtifactAnalysis {
readonly jsonDocuments: JavaScriptJsonDocuments;
readonly files: AnalyzedJavaScriptArtifactFile<SemanticIr>[];
readonly files: AnalyzedJavaScriptArtifactFile[];
readonly packages: JavaScriptPackageObservation[];
readonly jsonModules: JavaScriptJsonModuleObservation[];
readonly htmlScripts: JavaScriptHtmlScriptObservation[];
@@ -78,26 +65,6 @@ interface MutableArtifactAnalysis<
parseFailures: number;
}
interface ArtifactAnalysisContext<
SemanticIr extends JavaScriptModuleSemanticIr,
> {
readonly state: MutableArtifactAnalysis<SemanticIr>;
readonly projectSemantics: (
file: JavaScriptArtifactFile,
ir: JavaScriptSemanticIr,
) => Generator<void, SemanticIr>;
}
/** Analyze every text source from the artifact without a result quota. */
export const analyzeJavaScriptArtifactFiles = (
fileSet: JavaScriptArtifactFileSet,
): JavaScriptArtifactAnalysis =>
analyzeArtifactFiles(fileSet, function* (_file, ir) {
// The full IR needs no projection; one step keeps the shared protocol.
yield;
return ir;
});
/** Analyze sources behind a hard heap boundary, retaining collected facts on interruption. */
export const analyzeAndAdoptJavaScriptArtifactFiles = async (
fileSet: JavaScriptArtifactFileSet,
@@ -111,10 +78,10 @@ export const analyzeAndAdoptJavaScriptArtifactFiles = async (
signal?: AbortSignal,
onPhase?: (file: JavaScriptArtifactFile, phase: string) => Promise<void>,
): Promise<{
readonly analysis: JavaScriptModuleArtifactAnalysis;
readonly analysis: JavaScriptArtifactAnalysis;
readonly interruption: AnalysisError | null;
}> => {
const state = emptyArtifactAnalysis<JavaScriptModuleSemanticIr>();
const state = emptyArtifactAnalysis();
let interruption: AnalysisError | null = null;
const selectedFileCount =
fileSet.files.length - (fileSet.source_selection?.unselected_files ?? 0);
@@ -140,14 +107,9 @@ export const analyzeAndAdoptJavaScriptArtifactFiles = async (
await beforeFile(file, selectedFileIndex++, selectedFileCount);
analysisStarted = true;
if (file.kind !== "javascript" || !file.text.included) {
const steps = analyzeArtifactFileSteps(file, {
state,
projectSemantics: function* (_file, ir) {
yield;
return projectJavaScriptModuleSemantics(ir);
},
});
await completeJavaScriptAnalysisSteps(steps, signal);
assertJavaScriptAnalysisActive(signal);
analyzeArtifactMetadata(file, state);
assertJavaScriptAnalysisActive(signal);
continue;
}
const result = await worker.analyze(
@@ -317,24 +279,9 @@ export const analyzeAndAdoptJavaScriptArtifactFiles = async (
return { analysis: finalizeArtifactAnalysis(state), interruption };
};
const analyzeArtifactFiles = <SemanticIr extends JavaScriptModuleSemanticIr>(
fileSet: JavaScriptArtifactFileSet,
projectSemantics: ArtifactAnalysisContext<SemanticIr>["projectSemantics"],
): JavaScriptArtifactAnalysis<SemanticIr> => {
const state = emptyArtifactAnalysis<SemanticIr>();
const context = { state, projectSemantics };
for (const file of fileSet.files) {
const steps = analyzeArtifactFileSteps(file, context);
while (steps.next().done !== true);
}
return finalizeArtifactAnalysis(state);
};
const finalizeArtifactAnalysis = <
SemanticIr extends JavaScriptModuleSemanticIr,
>(
state: MutableArtifactAnalysis<SemanticIr>,
): JavaScriptArtifactAnalysis<SemanticIr> => {
const finalizeArtifactAnalysis = (
state: MutableArtifactAnalysis,
): JavaScriptArtifactAnalysis => {
return {
jsonDocuments: state.jsonDocuments,
files: state.files,
@@ -367,14 +314,10 @@ const finalizeArtifactAnalysis = <
};
};
function* analyzeArtifactFileSteps<
SemanticIr extends JavaScriptModuleSemanticIr,
>(
const analyzeArtifactMetadata = (
file: JavaScriptArtifactFile,
context: ArtifactAnalysisContext<SemanticIr>,
): Generator<void, void> {
const { state } = context;
if (classifyUnavailableSource(file, state)) return;
state: MutableArtifactAnalysis,
): void => {
addStructuredObservations(file, state);
if (file.kind === "html" && file.text.included) {
const html = parseHtmlScripts(file.path, file.text.value);
@@ -383,78 +326,23 @@ function* analyzeArtifactFileSteps<
if (html.inlineScripts !== null)
state.htmlInlineScripts.push(html.inlineScripts);
}
if (file.kind === "source-map") addSourceMap(file, context);
if (file.kind !== "javascript" || !file.text.included) {
state.files.push({ file, javascript: null, semantic: null });
return;
}
const parsed = parseJavaScriptSource(file.text.value, file.path);
yield;
if (parsed === null) {
const analysis = failedJavaScriptStaticAnalysis();
state.files.push({ file, javascript: analysis, semantic: null });
state.parseFailures += 1;
return;
}
const analysis = yield* analyzeParsedJavaScriptStaticSourceSteps(
file.text.value,
parsed,
);
const staticFindings = findingCount(analysis);
yield;
const semantics =
analysis.parse_status === "complete" || analysis.parse_status === "partial"
? yield* analyzeParsedJavaScriptSemanticsSteps(
parsed,
moduleResolutionModeForJavaScriptReference(
file.path,
"static-import",
),
)
: null;
const projected =
semantics === null
? null
: yield* context.projectSemantics(file, semantics);
state.files.push({
file,
javascript: analysis,
semantic: projected === null ? null : { ir: projected },
});
state.visitedNodes += analysis.visited_ast_nodes;
state.findings += staticFindings + (semantics?.moduleLinks.length ?? 0);
state.modules += analysis.bundler_registrations.reduce(
(count, registration) => count + registration.modules.length,
0,
);
if (analysis.parse_status === "failed") state.parseFailures += 1;
}
if (file.kind === "source-map") state.sourceMaps.push(parseSourceMap(file));
state.files.push({ file, javascript: null, semantic: null });
};
const classifyUnavailableSource = <
SemanticIr extends JavaScriptModuleSemanticIr,
>(
const classifyUnavailableSource = (
file: JavaScriptArtifactFile,
state: MutableArtifactAnalysis<SemanticIr>,
projection?: JavaScriptSemanticGraphProjection,
state: MutableArtifactAnalysis,
projection: JavaScriptSemanticGraphProjection,
): boolean => {
const reason = javaScriptArtifactTextExclusion(file);
if (reason === null) return false;
state.files.push({ file, javascript: null, semantic: null });
projection?.recordUnavailableFile(file, reason, null, "incomplete-module");
projection.recordUnavailableFile(file, reason, null, "incomplete-module");
return true;
};
const addSourceMap = (
file: JavaScriptArtifactFile,
context: ArtifactAnalysisContext<JavaScriptModuleSemanticIr>,
): void => {
const sourceMap = parseSourceMap(file);
context.state.sourceMaps.push(sourceMap);
};
const emptyArtifactAnalysis = <
SemanticIr extends JavaScriptModuleSemanticIr,
>(): MutableArtifactAnalysis<SemanticIr> => ({
const emptyArtifactAnalysis = (): MutableArtifactAnalysis => ({
jsonDocuments: new JavaScriptJsonDocuments(),
files: [],
packages: [],
@@ -470,7 +358,7 @@ const emptyArtifactAnalysis = <
const addStructuredObservations = (
file: JavaScriptArtifactFile,
state: MutableArtifactAnalysis<JavaScriptModuleSemanticIr>,
state: MutableArtifactAnalysis,
): void => {
if (file.kind === "package-json")
state.packages.push(parsePackage(file, state.jsonDocuments.read(file)));