From 8c6cddcffbdbe5715f31828ff5a7cd98ed913107 Mon Sep 17 00:00:00 2001 From: morluto <76467478+morluto@users.noreply.github.com> Date: Sat, 24 Oct 2026 23:33:09 +0800 Subject: [PATCH] refactor(javascript): retire synchronous artifact graph runner --- .../JavaScriptArtifactGraphBuilder.ts | 20 ------------------- .../javascriptApplicationService.test.ts | 9 +++++---- .../javascriptArtifactGraphEndpoints.test.ts | 10 +++++----- .../javascriptArtifactReconstruction.test.ts | 20 +++++++++---------- .../javascriptModuleRelationships.test.ts | 4 ++-- .../javascriptNonStringPackageMain.test.ts | 6 +++--- ...riptArtifactGraphObservationLookup.test.ts | 10 +++++----- tests/fixtures/javascriptArtifactGraph.ts | 11 ++++++++++ .../javascriptJsonDocumentFailures.test.ts | 4 ++-- 9 files changed, 43 insertions(+), 51 deletions(-) create mode 100644 tests/fixtures/javascriptArtifactGraph.ts diff --git a/src/application/javascript/JavaScriptArtifactGraphBuilder.ts b/src/application/javascript/JavaScriptArtifactGraphBuilder.ts index 6a58932c20..b240be555d 100644 --- a/src/application/javascript/JavaScriptArtifactGraphBuilder.ts +++ b/src/application/javascript/JavaScriptArtifactGraphBuilder.ts @@ -1,7 +1,6 @@ import { ELECTRON_IDENTITY_LIMITATION } from "../../domain/javascript/javascriptElectronMemberWrites.js"; import type { ArtifactInventorySnapshot } from "../../domain/artifactInventorySnapshot.js"; import { - createJavaScriptApplicationGraph, sealTransferredJavaScriptApplicationGraphSteps, type JavaScriptApplicationGraph, } from "../../domain/javascript/javascriptApplicationGraph.js"; @@ -50,18 +49,6 @@ import { collectElectronIpcRecords, } from "./ElectronBoundaryAnalysis.js"; -/** Project artifact and AST facts into JavaScript Application Graph. */ -export const buildJavaScriptArtifactGraph = ( - snapshot: ArtifactInventorySnapshot, - fileSet: JavaScriptArtifactFileSet, - analysis: JavaScriptModuleArtifactAnalysis, -): JavaScriptApplicationGraph => - createJavaScriptApplicationGraph( - completeSynchronously( - buildJavaScriptArtifactGraphInputSteps(snapshot, fileSet, analysis), - ), - ); - /** * Build a validated application graph with cooperative immutable ownership. * Constructing the graph input also runs in steps: projecting every module @@ -81,13 +68,6 @@ export function* buildImmutableJavaScriptArtifactGraphSteps( return yield* sealTransferredJavaScriptApplicationGraphSteps(input); } -const completeSynchronously = (steps: Iterator): Value => { - for (;;) { - const step = steps.next(); - if (step.done === true) return step.value; - } -}; - function* buildJavaScriptArtifactGraphInputSteps( snapshot: ArtifactInventorySnapshot, fileSet: JavaScriptArtifactFileSet, diff --git a/tests/boundary/filesystem/javascript-applications/javascriptApplicationService.test.ts b/tests/boundary/filesystem/javascript-applications/javascriptApplicationService.test.ts index 9bf2f1eecf..9bff3d5f09 100644 --- a/tests/boundary/filesystem/javascript-applications/javascriptApplicationService.test.ts +++ b/tests/boundary/filesystem/javascript-applications/javascriptApplicationService.test.ts @@ -20,7 +20,8 @@ import { createJavaScriptArtifactReader } from "../../../../src/artifacts/javasc import { createJavaScriptSourceAnalysis } from "../../../../src/artifacts/javascript/JavaScriptSourceAnalysis.js"; import { analyzeAndAdoptJavaScriptArtifactFiles } from "../../../../src/application/javascript/JavaScriptArtifactAnalysis.js"; import { createJavaScriptSemanticGraphProjection } from "../../../../src/application/javascript/JavaScriptSemanticGraphBuilder.js"; -import { buildJavaScriptArtifactGraph } from "../../../../src/application/javascript/JavaScriptArtifactGraphBuilder.js"; +import { immutableArtifactGraph } from "../../../fixtures/javascriptArtifactGraph.js"; +import type { JavaScriptApplicationGraph } from "../../../../src/domain/javascript/javascriptApplicationGraph.js"; import { writeFixtureFiles } from "../../../support/javascriptApplicationFixture.js"; describe("JavaScript source selection cancellation boundary", () => { @@ -175,7 +176,7 @@ it("resolves lazy package and JSON facts without completing their skipped observ ), ).toBe(false); - const graph = buildJavaScriptArtifactGraph( + const graph = await immutableArtifactGraph( snapshot, files, outcome.analysis, @@ -226,7 +227,7 @@ it("resolves lazy package and JSON facts without completing their skipped observ }); const unknownScopeObservation = ( - graph: ReturnType, + graph: JavaScriptApplicationGraph, path: string, ) => graph.nodes @@ -235,7 +236,7 @@ const unknownScopeObservation = ( .find(({ properties }) => properties.path === path); const expectSkippedStructuredSource = ( - graph: ReturnType, + graph: JavaScriptApplicationGraph, path: string, operation: string, ): void => { diff --git a/tests/boundary/filesystem/javascript-applications/javascriptArtifactGraphEndpoints.test.ts b/tests/boundary/filesystem/javascript-applications/javascriptArtifactGraphEndpoints.test.ts index f9bc3ed48a..91a1bfc686 100644 --- a/tests/boundary/filesystem/javascript-applications/javascriptArtifactGraphEndpoints.test.ts +++ b/tests/boundary/filesystem/javascript-applications/javascriptArtifactGraphEndpoints.test.ts @@ -8,7 +8,7 @@ import { scanCanonicalArtifactInventory } from "../../../fixtures/artifactInvent import { readJavaScriptArtifactFiles } from "../../../support/javascriptApplicationScope.js"; import { createJavaScriptArtifactReader } from "../../../../src/artifacts/javascript/JavaScriptArtifactReader.js"; import { analyzeJavaScriptArtifactFiles } from "../../../../src/application/javascript/JavaScriptArtifactAnalysis.js"; -import { buildJavaScriptArtifactGraph } from "../../../../src/application/javascript/JavaScriptArtifactGraphBuilder.js"; +import { immutableArtifactGraph } from "../../../fixtures/javascriptArtifactGraph.js"; it("keeps an endpoint uncertain after mutation through a declared inherited field", async () => { const root = await createTestTempDirectory("rea-js-erased-field-"); @@ -28,7 +28,7 @@ it("keeps an endpoint uncertain after mutation through a declared inherited fiel try { const files = await readJavaScriptArtifactFiles(reader, snapshot); const analysis = analyzeJavaScriptArtifactFiles(files); - const graph = buildJavaScriptArtifactGraph(snapshot, files, analysis); + const graph = await immutableArtifactGraph(snapshot, files, analysis); const endpoints = graph.nodes.filter(({ kind }) => kind === "endpoint"); expect(endpoints).toHaveLength(1); expect(endpoints[0]?.observations[0]).toMatchObject({ @@ -52,7 +52,7 @@ it("keeps ambiguous endpoint candidates inferred through artifact graph projecti try { const files = await readJavaScriptArtifactFiles(reader, snapshot); const analysis = analyzeJavaScriptArtifactFiles(files); - const graph = buildJavaScriptArtifactGraph(snapshot, files, analysis); + const graph = await immutableArtifactGraph(snapshot, files, analysis); const endpoints = graph.nodes.filter(({ kind }) => kind === "endpoint"); const candidate = endpoints.find(({ observations }) => observations.some( @@ -122,7 +122,7 @@ it("preserves partial and exact endpoint identity through graph projection", asy try { const files = await readJavaScriptArtifactFiles(reader, snapshot); const analysis = analyzeJavaScriptArtifactFiles(files); - const graph = buildJavaScriptArtifactGraph(snapshot, files, analysis); + const graph = await immutableArtifactGraph(snapshot, files, analysis); const endpoints = graph.nodes.filter(({ kind }) => kind === "endpoint"); const partialNodes = endpoints.filter(({ observations }) => observations.some( @@ -172,7 +172,7 @@ it("projects path data records as inferred route candidates", async () => { try { const files = await readJavaScriptArtifactFiles(reader, snapshot); const analysis = analyzeJavaScriptArtifactFiles(files); - const graph = buildJavaScriptArtifactGraph(snapshot, files, analysis); + const graph = await immutableArtifactGraph(snapshot, files, analysis); const route = (value: string) => graph.nodes .find( diff --git a/tests/boundary/filesystem/javascript-applications/javascriptArtifactReconstruction.test.ts b/tests/boundary/filesystem/javascript-applications/javascriptArtifactReconstruction.test.ts index 1c21f9f21e..fe4866e58f 100644 --- a/tests/boundary/filesystem/javascript-applications/javascriptArtifactReconstruction.test.ts +++ b/tests/boundary/filesystem/javascript-applications/javascriptArtifactReconstruction.test.ts @@ -21,7 +21,7 @@ import { analyzeJavaScriptArtifactFiles, analyzeAndAdoptJavaScriptArtifactFiles, } from "../../../../src/application/javascript/JavaScriptArtifactAnalysis.js"; -import { buildJavaScriptArtifactGraph } from "../../../../src/application/javascript/JavaScriptArtifactGraphBuilder.js"; +import { immutableArtifactGraph } from "../../../fixtures/javascriptArtifactGraph.js"; import { buildJavaScriptSemanticGraph, createJavaScriptSemanticGraphProjection, @@ -212,7 +212,7 @@ it.each([ }, ], }; - const graph = buildJavaScriptArtifactGraph( + const graph = await immutableArtifactGraph( snapshot, partial, analyzeJavaScriptArtifactFiles(partial), @@ -288,7 +288,7 @@ it.each(["unselected", "unavailable"] as const)( }, ], }; - const graph = buildJavaScriptArtifactGraph( + const graph = await immutableArtifactGraph( snapshot, partial, analyzeJavaScriptArtifactFiles(partial), @@ -345,7 +345,7 @@ it("keeps imported loadFile ownership unknown across an application projection o ), ).toBe(true); // Exercise the production omission boundary without bypassing its memory guard. - const graph = buildJavaScriptArtifactGraph(snapshot, files, { + const graph = await immutableArtifactGraph(snapshot, files, { ...analysis, files: analysis.files.map((file) => file.file.path === "shared/main.cjs" @@ -421,7 +421,7 @@ it("keeps a loadFile owner unknown when a sibling manifest is unavailable in the }, ], }; - const graph = buildJavaScriptArtifactGraph( + const graph = await immutableArtifactGraph( snapshot, partial, analyzeJavaScriptArtifactFiles(partial), @@ -491,7 +491,7 @@ it("keeps excluded non-JavaScript files out of both semantic construction paths" "package.json", ]); const analysis = analyzeJavaScriptArtifactFiles(files); - const applicationGraph = buildJavaScriptArtifactGraph( + const applicationGraph = await immutableArtifactGraph( snapshot, files, analysis, @@ -597,8 +597,8 @@ it("preserves graph commitments and export shapes through worker adoption", asyn } if (outcome.interruption !== null) throw outcome.interruption; const compact = outcome.analysis; - const graph = buildJavaScriptArtifactGraph(snapshot, files, full); - expect(buildJavaScriptArtifactGraph(snapshot, files, compact)).toEqual( + const graph = await immutableArtifactGraph(snapshot, files, full); + expect(await immutableArtifactGraph(snapshot, files, compact)).toEqual( graph, ); const semantic = projection.finish(snapshot.manifest.root_sha256, graph); @@ -672,7 +672,7 @@ it("preserves graph commitments and export shapes through worker adoption", asyn rejectedInvalidTransfer = true; } } - const decodedGraph = buildJavaScriptArtifactGraph(snapshot, files, { + const decodedGraph = await immutableArtifactGraph(snapshot, files, { ...compact, files: compact.files.map((analyzed) => { const module = decodedModules.get(analyzed.file.path); @@ -754,7 +754,7 @@ it("reports semantic value resource limits in application graph coverage", async try { const files = await readJavaScriptArtifactFiles(reader, snapshot); const analysis = analyzeJavaScriptArtifactFiles(files); - const graph = buildJavaScriptArtifactGraph(snapshot, files, analysis); + const graph = await immutableArtifactGraph(snapshot, files, analysis); expect(graph.coverage).toMatchObject({ status: "partial", diff --git a/tests/boundary/filesystem/javascript-applications/javascriptModuleRelationships.test.ts b/tests/boundary/filesystem/javascript-applications/javascriptModuleRelationships.test.ts index 70a08c3ca6..4a0fcc7c31 100644 --- a/tests/boundary/filesystem/javascript-applications/javascriptModuleRelationships.test.ts +++ b/tests/boundary/filesystem/javascript-applications/javascriptModuleRelationships.test.ts @@ -14,7 +14,7 @@ import { scanCanonicalArtifactInventory } from "../../../fixtures/artifactInvent import { readJavaScriptArtifactFiles } from "../../../support/javascriptApplicationScope.js"; import { createJavaScriptArtifactReader } from "../../../../src/artifacts/javascript/JavaScriptArtifactReader.js"; import { analyzeJavaScriptArtifactFiles } from "../../../../src/application/javascript/JavaScriptArtifactAnalysis.js"; -import { buildJavaScriptArtifactGraph } from "../../../../src/application/javascript/JavaScriptArtifactGraphBuilder.js"; +import { immutableArtifactGraph } from "../../../fixtures/javascriptArtifactGraph.js"; import { findExportNode, @@ -29,7 +29,7 @@ const relationshipGraph = async (root: string) => { const reader = createJavaScriptArtifactReader(root, "directory"); try { const files = await readJavaScriptArtifactFiles(reader, snapshot); - return buildJavaScriptArtifactGraph( + return await immutableArtifactGraph( snapshot, files, analyzeJavaScriptArtifactFiles(files), diff --git a/tests/boundary/filesystem/javascript-applications/javascriptNonStringPackageMain.test.ts b/tests/boundary/filesystem/javascript-applications/javascriptNonStringPackageMain.test.ts index e3d6dec1f2..bab140aec4 100644 --- a/tests/boundary/filesystem/javascript-applications/javascriptNonStringPackageMain.test.ts +++ b/tests/boundary/filesystem/javascript-applications/javascriptNonStringPackageMain.test.ts @@ -4,7 +4,7 @@ import { join } from "node:path"; import { expect, it } from "vitest"; import { analyzeJavaScriptArtifactFiles } from "../../../../src/application/javascript/JavaScriptArtifactAnalysis.js"; -import { buildJavaScriptArtifactGraph } from "../../../../src/application/javascript/JavaScriptArtifactGraphBuilder.js"; +import { immutableArtifactGraph } from "../../../fixtures/javascriptArtifactGraph.js"; import { resolveArtifactPathByContext } from "../../../../src/application/javascript/JavaScriptArtifactPathResolution.js"; import { createJavaScriptArtifactReader } from "../../../../src/artifacts/javascript/JavaScriptArtifactReader.js"; import { scanCanonicalArtifactInventory } from "../../../fixtures/artifactInventory.js"; @@ -46,7 +46,7 @@ it.each( expect( analysis.packages.find(({ path }) => path === "b/package.json"), ).toMatchObject({ main_status: "invalid", main_entrypoint: "" }); - const graph = buildJavaScriptArtifactGraph(snapshot, files, analysis); + const graph = await immutableArtifactGraph(snapshot, files, analysis); const roles = graph.nodes.filter( ({ kind }) => kind === "electron-renderer", ); @@ -123,7 +123,7 @@ it.each( resolution_status: valid ? "resolved" : "unavailable", resolved_path: valid ? "b/index.js" : null, }); - const graph = buildJavaScriptArtifactGraph(snapshot, files, analysis); + const graph = await immutableArtifactGraph(snapshot, files, analysis); const role = graph.nodes.find(({ kind }) => kind === "electron-renderer"); expect(role?.observations).toEqual( expect.arrayContaining([ diff --git a/tests/boundary/filesystem/javascriptArtifactGraphObservationLookup.test.ts b/tests/boundary/filesystem/javascriptArtifactGraphObservationLookup.test.ts index 4239a643fa..8fc5844810 100644 --- a/tests/boundary/filesystem/javascriptArtifactGraphObservationLookup.test.ts +++ b/tests/boundary/filesystem/javascriptArtifactGraphObservationLookup.test.ts @@ -7,7 +7,7 @@ import { scanCanonicalArtifactInventory } from "../../fixtures/artifactInventory import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js"; import { readJavaScriptArtifactFiles } from "../../support/javascriptApplicationScope.js"; import { analyzeJavaScriptArtifactFiles } from "../../../src/application/javascript/JavaScriptArtifactAnalysis.js"; -import { buildJavaScriptArtifactGraph } from "../../../src/application/javascript/JavaScriptArtifactGraphBuilder.js"; +import { immutableArtifactGraph } from "../../fixtures/javascriptArtifactGraph.js"; import { createJavaScriptArtifactReader } from "../../../src/artifacts/javascript/JavaScriptArtifactReader.js"; import type { JavaScriptJsonModuleObservation, @@ -55,7 +55,7 @@ it("uses the first structured observation when paths repeat", async () => { ) throw new TypeError("Expected structured artifact observations"); - const graph = buildJavaScriptArtifactGraph(snapshot, files, { + const graph = await immutableArtifactGraph(snapshot, files, { ...analysis, packages: [ packageObservation, @@ -138,7 +138,7 @@ it("preserves unknown omitted-key count for unavailable JSON", async () => { try { const files = await readJavaScriptArtifactFiles(reader, snapshot); const analysis = analyzeJavaScriptArtifactFiles(files); - const graph = buildJavaScriptArtifactGraph(snapshot, files, analysis); + const graph = await immutableArtifactGraph(snapshot, files, analysis); const configFile = graph.nodes.find(({ observations }) => observations.some( @@ -183,7 +183,7 @@ it("preserves unknown omitted-key count for unselected JSON", async () => { ); const analysis = analyzeJavaScriptArtifactFiles(files); - const graph = buildJavaScriptArtifactGraph(snapshot, files, analysis); + const graph = await immutableArtifactGraph(snapshot, files, analysis); const configFile = graph.nodes.find(({ observations }) => observations.some( @@ -228,7 +228,7 @@ it("preserves unknown omitted-key count for unselected uppercase JSON", async () ); const analysis = analyzeJavaScriptArtifactFiles(files); - const graph = buildJavaScriptArtifactGraph(snapshot, files, analysis); + const graph = await immutableArtifactGraph(snapshot, files, analysis); const configFile = graph.nodes.find(({ observations }) => observations.some( diff --git a/tests/fixtures/javascriptArtifactGraph.ts b/tests/fixtures/javascriptArtifactGraph.ts new file mode 100644 index 0000000000..fe999410e6 --- /dev/null +++ b/tests/fixtures/javascriptArtifactGraph.ts @@ -0,0 +1,11 @@ +import { completeJavaScriptAnalysisSteps } from "../../src/application/javascript/JavaScriptAnalysisControl.js"; +import { buildImmutableJavaScriptArtifactGraphSteps } from "../../src/application/javascript/JavaScriptArtifactGraphBuilder.js"; +import type { JavaScriptApplicationGraph } from "../../src/domain/javascript/javascriptApplicationGraph.js"; + +/** Drive the production immutable application graph builder for boundary tests. */ +export const immutableArtifactGraph = ( + ...args: Parameters +): Promise => + completeJavaScriptAnalysisSteps( + buildImmutableJavaScriptArtifactGraphSteps(...args), + ); diff --git a/tests/process-global/javascriptJsonDocumentFailures.test.ts b/tests/process-global/javascriptJsonDocumentFailures.test.ts index 44a99abca9..b702f10233 100644 --- a/tests/process-global/javascriptJsonDocumentFailures.test.ts +++ b/tests/process-global/javascriptJsonDocumentFailures.test.ts @@ -2,7 +2,7 @@ import { expect, it, onTestFinished, vi } from "vitest"; import { createJavaScriptArtifactReader } from "../../src/artifacts/javascript/JavaScriptArtifactReader.js"; import { analyzeJavaScriptArtifactFiles } from "../../src/application/javascript/JavaScriptArtifactAnalysis.js"; -import { buildJavaScriptArtifactGraph } from "../../src/application/javascript/JavaScriptArtifactGraphBuilder.js"; +import { immutableArtifactGraph } from "../fixtures/javascriptArtifactGraph.js"; import type { JavaScriptArtifactFile, JavaScriptArtifactFileSet, @@ -121,7 +121,7 @@ it("reuses parsed package and JSON facts while building the public graph", async return originalParse(text); }); - const graph = buildJavaScriptArtifactGraph(snapshot, files, analysis); + const graph = await immutableArtifactGraph(snapshot, files, analysis); expect( graph.edges.find( ({ relation, properties }) =>