refactor: remove legacy seams and consolidate resource ownership (#10349)

This commit is contained in:
morluto authored and GitHub committed 2026-11-13 04:45:16 -05:00
1 parent 5cddc69c51
commit bbe2bcc979
301 files changed
+3148 -2804

No files matched your search

@@ -172,7 +172,7 @@ const electronModuleReferencedBy = ({
};
/** Whether any analyzed source loads an Electron module. */
export const electronModuleReferenced = (
const electronModuleReferenced = (
analysis: JavaScriptArtifactAnalysis,
): boolean => analysis.files.some(electronModuleReferencedBy);
@@ -1,8 +1,5 @@
import { expect, it } from "vitest";
import {
analyzeAndAdoptJavaScriptArtifactFiles,
javaScriptAnalysisOrder,
} from "./JavaScriptArtifactAnalysis.js";
import { analyzeAndAdoptJavaScriptArtifactFiles } from "./JavaScriptArtifactAnalysis.js";
import { createJavaScriptSemanticGraphProjection } from "./JavaScriptSemanticGraphBuilder.js";
import { AnalysisResourceConstraintError } from "../../domain/analysisErrorCore.js";
import { analyzeJavaScriptStaticSource } from "../../../tests/fixtures/javascriptStaticAnalysis.js";
@@ -37,24 +34,6 @@ const inventory = [
manifest("package.json"),
];
it("offers application JavaScript before dependency JavaScript", () => {
expect(javaScriptAnalysisOrder(inventory).map(({ path }) => path)).toEqual([
"node_modules/a/package.json",
"out-global-online/main/index.js",
"out-global-online/preload/index.js",
"package.json",
"node_modules/a/index.js",
"node_modules/b/lib/yaml.js",
]);
// A package merely named like a dependency directory is not one.
expect(
javaScriptAnalysisOrder([
source("node_modules.js"),
source("src/node_modules_shim.js"),
]).map(({ path }) => path),
).toEqual(["node_modules.js", "src/node_modules_shim.js"]);
});
it("spends a limited result budget on first-party sources and keeps inventory order", async () => {
const javascript = analyzeJavaScriptStaticSource("export const x = 1;");
const analyzed: string[] = [];
@@ -107,6 +86,38 @@ it("spends a limited result budget on first-party sources and keeps inventory or
expect(outcome.interruption).toBeNull();
});
it("does not treat files merely named like dependency directories as dependencies", async () => {
const files = [
source("node_modules/dep/index.js"),
source("node_modules.js"),
source("src/node_modules_shim.js"),
];
const analyzed: string[] = [];
const javascript = analyzeJavaScriptStaticSource("export const x = 1;");
await analyzeAndAdoptJavaScriptArtifactFiles(
{
files,
unavailable_relevant_files: [],
containers: [],
text_bytes_read: 60,
invalid_utf8_files: 0,
},
{
analyze: async (file) => {
analyzed.push(file.path);
return ok({ javascript, module: null, projection: null });
},
},
createJavaScriptSemanticGraphProjection(),
async () => {},
);
expect(analyzed).toEqual([
"node_modules.js",
"src/node_modules_shim.js",
"node_modules/dep/index.js",
]);
});
it("spends capacity in the caller's requested order for explicitly selected sources", async () => {
const files = [
source("node_modules/selected/index.js"),
@@ -329,7 +329,7 @@ const dependencySourcePath = (path: string): boolean =>
* preloads, and Electron windows are examined. Offer application JavaScript
* first and dependency JavaScript last; metadata files keep their position.
*/
export const javaScriptAnalysisOrder = (
const javaScriptAnalysisOrder = (
files: readonly JavaScriptArtifactFile[],
): JavaScriptArtifactFile[] => {
const application: JavaScriptArtifactFile[] = [];
@@ -17,7 +17,6 @@ import { javascriptArtifactAnalysisScopes } from "./JavaScriptArtifactAnalysisTy
import { completeJavaScriptAnalysisSteps } from "./JavaScriptAnalysisControl.js";
import { buildImmutableJavaScriptArtifactGraphSteps as buildGraph } from "./JavaScriptArtifactGraphBuilder.js";
import { JavaScriptJsonDocuments } from "./JavaScriptJsonDocuments.js";
import { electronModuleReferenced } from "./ElectronBoundaryAnalysis.js";
const SHA256 = "a".repeat(64);
const PATH = "main.js";
@@ -178,25 +177,14 @@ describe("Electron semantic coverage", () => {
expect(electronSemantics).toBeUndefined();
});
it("does not count a type-only Electron import as boundary coverage", () => {
// A `.js` fixture cannot carry `import type`, so the module predicate is
// exercised directly here.
const analysisWith = (
kind: "require" | "type-import",
): JavaScriptArtifactAnalysis =>
({
files: [
{
file: fileFor(""),
javascript: null,
semantic: {
ir: { moduleLinks: [{ kind, specifier: "electron" }] },
},
},
],
}) as unknown as JavaScriptArtifactAnalysis;
expect(electronModuleReferenced(analysisWith("require"))).toBe(true);
expect(electronModuleReferenced(analysisWith("type-import"))).toBe(false);
it("does not count a type-only Electron import as boundary coverage", async () => {
const result = await graphFor(
'import type { BrowserWindow } from "electron";\nexport type Window = BrowserWindow;\n',
undefined,
"main.ts",
);
expect(result.electronSemantics).toBeUndefined();
expect(result.limitations).not.toContain(EMPTY_COVERAGE);
});
it("matches a supported Electron subpath and ignores an unrelated package", async () => {
@@ -9,6 +9,10 @@ import type { NextAppSourceContext } from "../../domain/javascript/javascriptRou
import { compositeKey } from "../../domain/unicodeCodePointOrder.js";
import type { JavaScriptJsonDocuments } from "./JavaScriptJsonDocuments.js";
/** Identify a package directory within its owning container. */
const packageDirectoryKey = (container: string, directory: string): string =>
compositeKey([container, directory]);
/** Package declarations and inventoried directories own source-router applicability. */
export const createJavaScriptNextAppContext = (
fileSet: Pick<
@@ -25,7 +29,7 @@ export const createJavaScriptNextAppContext = (
fileSet.files
.filter(({ kind }) => kind === "package-json")
.map((file) => [
compositeKey([file.container_sha256, posix.dirname(file.path)]),
packageDirectoryKey(file.container_sha256, posix.dirname(file.path)),
file,
]),
);
@@ -33,7 +37,7 @@ export const createJavaScriptNextAppContext = (
fileSet.unavailable_relevant_files
.filter(({ kind }) => kind === "package-json")
.map((file) => [
compositeKey([file.container_sha256, posix.dirname(file.path)]),
packageDirectoryKey(file.container_sha256, posix.dirname(file.path)),
file,
]),
);
@@ -44,7 +48,7 @@ export const createJavaScriptNextAppContext = (
;
directory = posix.dirname(directory)
) {
const key = compositeKey([file.container_sha256, directory]);
const key = packageDirectoryKey(file.container_sha256, directory);
const unavailable = unavailablePackages.get(key);
if (unavailable !== undefined)
return {
@@ -1,3 +1,4 @@
import { JAVASCRIPT_ANALYSIS_RESOURCE_DEFAULTS } from "../../domain/javascript/javascriptAnalysisResourceControls.js";
import { javaScriptSemanticQueryInputSchema } from "../../domain/javascript/javascriptSemanticQuerySchemas.js";
import {
primitiveByteExpansionSource,
@@ -9,8 +10,6 @@ import { expect, it } from "vitest";
import { aliasSelectionBudgetSource } from "../../../tests/fixtures/javascriptAliasSelectionBudget.js";
import {
SEMANTIC_GRAPH_FILE_NODE_CEILING,
SEMANTIC_GRAPH_NODE_CEILING,
createJavaScriptSemanticGraphProjection,
projectJavaScriptSemanticFileSteps,
} from "./JavaScriptSemanticGraphBuilder.js";
@@ -972,7 +971,9 @@ it("bounds semantic node projection and reports the ceiling in coverage", () =>
).join("\n");
const graph = graphFor(statements);
expect(graph.nodes.length).toBeLessThanOrEqual(SEMANTIC_GRAPH_NODE_CEILING);
expect(graph.nodes.length).toBeLessThanOrEqual(
JAVASCRIPT_ANALYSIS_RESOURCE_DEFAULTS.semanticNodes,
);
expect(graph.coverage.truncated).toBe(true);
expect(graph.coverage.status).toBe("partial");
expect(graph.coverage.omitted_nodes).toBeNull();
@@ -1136,9 +1137,13 @@ it("leaves a small application complete and untruncated", () => {
it("does not mark a file truncated when it exactly fills its budget", () => {
// Each unbound reference projects one expression, plus the module root.
const graph = graphFor(
"external;\n".repeat(SEMANTIC_GRAPH_FILE_NODE_CEILING - 1),
"external;\n".repeat(
JAVASCRIPT_ANALYSIS_RESOURCE_DEFAULTS.semanticNodesPerFile - 1,
),
);
expect(graph.nodes).toHaveLength(
JAVASCRIPT_ANALYSIS_RESOURCE_DEFAULTS.semanticNodesPerFile,
);
expect(graph.nodes).toHaveLength(SEMANTIC_GRAPH_FILE_NODE_CEILING);
expect(graph.coverage).toMatchObject({
truncated: false,
omitted_nodes: 0,
@@ -1160,7 +1165,9 @@ it("only records node loss when the budget rejects a new identity", () => {
expect(state.fileNodeBudget).toBe(0);
expect(state.fileNodesDropped).toBe(false);
expect(addSemanticGraphNode(state, semanticNodeFor("first"))).toBe(first);
expect(addSemanticGraphNode(state, semanticNodeFor("first"))).toEqual(first);
expect(state.nodes.size).toBe(2);
expect(state.fileNodeBudget).toBe(0);
expect(state.fileNodesDropped).toBe(false);
const blocked = addSemanticGraphNode(state, semanticNodeFor("third"));
@@ -111,36 +111,6 @@ interface FileContext extends SemanticFlowProjectionContext {
>;
}
/**
* Resource-safety ceiling on retained semantic nodes.
*
* The semantic projection emits one node per AST expression, call site, binding
* and property slot. That is unbounded in input size. A small tree of five files
* already yields on the order of 170,000 nodes, and larger trees yield millions,
* exhausting the heap before the result can be serialized.
*
* This is a real resource-safety constraint, not a presentation preference, so
* the ceiling is applied and reported through the graph's own `coverage` fields
* (`truncated`, `omitted_nodes`, `omitted_relations`, `limits`) rather than
* silently dropping data.
*
* Defaults bound work even when ample heap is available. Callers may raise the
* capacities explicitly; isolated worker heap, bounded record transport and
* parent result admission independently constrain actual retained memory. The
* result uses incremental serialization rather than a single JSON string.
*/
export const SEMANTIC_GRAPH_NODE_CEILING =
JAVASCRIPT_ANALYSIS_RESOURCE_DEFAULTS.semanticNodes;
/**
* Per-file share of the semantic node budget.
*
* Bound each source file independently so one large bundled library cannot
* consume the whole tree's budget and starve the application's own modules.
*/
export const SEMANTIC_GRAPH_FILE_NODE_CEILING =
JAVASCRIPT_ANALYSIS_RESOURCE_DEFAULTS.semanticNodesPerFile;
/** File-local semantic projection that does not retain consumed source IR. */
export interface JavaScriptSemanticGraphProjection {
/** Node capacity offered to the next independently analyzed source file. */
@@ -216,8 +186,12 @@ export const createJavaScriptSemanticGraphProjection = (
readonly fileUnknowns?: number;
} = {},
): JavaScriptSemanticGraphProjection => {
const nodeCeiling = limits.totalNodes ?? SEMANTIC_GRAPH_NODE_CEILING;
const fileNodeCeiling = limits.fileNodes ?? SEMANTIC_GRAPH_FILE_NODE_CEILING;
// Bound total and per-file work so a large dependency cannot starve the graph.
const nodeCeiling =
limits.totalNodes ?? JAVASCRIPT_ANALYSIS_RESOURCE_DEFAULTS.semanticNodes;
const fileNodeCeiling =
limits.fileNodes ??
JAVASCRIPT_ANALYSIS_RESOURCE_DEFAULTS.semanticNodesPerFile;
const unknownCeiling =
limits.totalUnknowns ??
JAVASCRIPT_ANALYSIS_RESOURCE_DEFAULTS.semanticUnknowns;