import { dirname } from "node:path"; import { fileURLToPath } from "node:url"; import ts from "typescript"; import { describe, expect, it } from "vitest"; import { getBoundaryViolation, getImportBoundaryViolation, getModuleSpecifiers, getProductionGraphBoundaryDiagnostics, getProductionGraphCycleDiagnostic, getProductionLayer, getProductionLayerMatches, getSourceImportBoundaryDiagnostics, getSourceImportGraphCycleDiagnostic, isContributionPhaseModulePath, listProductionModulePaths, listRuntimeSourcePaths, schemaOnlyContributionMaterializers, } from "./testing/module-import-boundary-test-support"; const compilerInventoriedContributionPhaseModulePaths = listProductionModulePaths().filter(isContributionPhaseModulePath); describe("capability module import boundaries", () => { it("classifies contribution normalization and validation as contract peers", () => { for (const modulePath of [ "contract/normalize-module-contribution.ts", "contract/validate-module-contribution.ts", ]) { expect(getProductionLayer(modulePath)).toBe("contract"); expect( getBoundaryViolation(modulePath, "modules/contract/contribution.ts"), ).toBeUndefined(); expect( getBoundaryViolation(modulePath, "schema/types.ts"), ).toBeUndefined(); } }); it("classifies every production module exactly once", () => { const productionModulePaths = listProductionModulePaths(); const invalidInventory = productionModulePaths .map((modulePath) => ({ layers: getProductionLayerMatches(modulePath), modulePath, })) .filter(({ layers }) => layers.length !== 1); expect(productionModulePaths.length).toBeGreaterThan(0); expect(invalidInventory).toEqual([]); }); it("keeps every compiler-inventoried resolution, contribution, and catalog module private", () => { const privateModulePaths = listProductionModulePaths().filter((modulePath) => ["catalog", "contribution", "resolution"].includes( getProductionLayer(modulePath) ?? "", ), ); expect(privateModulePaths.length).toBeGreaterThan(0); expect( privateModulePaths.map((modulePath) => getBoundaryViolation("public.ts", `modules/${modulePath}`), ), ).toEqual( privateModulePaths.map( (modulePath) => `public.ts -> modules/${modulePath}`, ), ); }); it("inventories every contribution phase file exactly once", () => { expect(compilerInventoriedContributionPhaseModulePaths).toEqual([ "resolution/contribution-phase/assemble-module-contributions.ts", "resolution/contribution-phase/preflight-module-contributions.ts", "resolution/contribution-phase/resolve-module-contributions.ts", ]); expect(new Set(compilerInventoriedContributionPhaseModulePaths).size).toBe( compilerInventoriedContributionPhaseModulePaths.length, ); }); it("limits Project B materializers to contracts and canonical schema", () => { const productionModulePaths = new Set(listProductionModulePaths()); const allowedTargets = [ "modules/contract/contribution.ts", "schema/types.ts", ]; const prohibitedTargets = [ "modules/graph/find-shortest-stable-cycle.ts", "modules/contributions/artifact-settings-contributions.ts", "modules/built-in-catalog.ts", "modules/resolution/contribution-phase/resolve-module-contributions.ts", "modules/testing/module-contribution-test-fixtures.ts", "react/app-shell/toolcraft-app.tsx", "model-import/default-model-source-assets.ts", "source-assets/binary-media-hydration.ts", ]; expect(Object.isFrozen(schemaOnlyContributionMaterializers)).toBe(true); expect( schemaOnlyContributionMaterializers.filter( (materializer) => !productionModulePaths.has(materializer), ), "Every protected Project B materializer must exist in production inventory.", ).toEqual([]); for (const materializer of schemaOnlyContributionMaterializers) { expect( allowedTargets.map((target) => getBoundaryViolation(materializer, target), ), ).toEqual([undefined, undefined]); expect( prohibitedTargets.map((target) => getBoundaryViolation(materializer, target), ), ).toEqual( prohibitedTargets.map((target) => `${materializer} -> ${target}`), ); } expect( getBoundaryViolation( "contributions/artifact-settings-contributions.ts", "modules/graph/find-shortest-stable-cycle.ts", ), ).toBeUndefined(); }); it("extracts static and resolvable dynamic imports through the TypeScript AST", () => { const source = [ 'import "./contract/capability";', 'export * from "./contract/module-definition";', 'void import("./graph/find-shortest-stable-cycle");', 'require("./resolution/resolve-product-modules");', 'type Contract = import("./contract/contribution").ToolcraftProductModuleContribution;', "void import(runtimeSpecifier);", "require(runtimeSpecifier);", ].join("\n"); expect(getModuleSpecifiers("fixture.ts", source)).toEqual([ "./contract/capability", "./contract/module-definition", "./graph/find-shortest-stable-cycle", "./resolution/resolve-product-modules", "./contract/contribution", ]); }); it.each([ ['import value from "./contract/capability";', "./contract/capability"], ['export * from "./contract/capability";', "./contract/capability"], [ 'import value = require("./contract/capability");', "./contract/capability", ], ['void import("./contract/capability");', "./contract/capability"], [ 'void import("./contract/capability", { with: { type: "json" } });', "./contract/capability", ], ['require("./contract/capability");', "./contract/capability"], [ 'type Value = import("./contract/capability").Value;', "./contract/capability", ], ])("extracts one static reference from %s", (source, specifier) => { expect(getModuleSpecifiers("fixture.ts", source)).toEqual([specifier]); }); it.each([ ["import value from runtimeOwner;", "nonliteral import declaration"], ["export * from runtimeOwner;", "nonliteral export declaration"], [ "import value = require(runtimeOwner);", "nonliteral import equals", ], ["void import(runtimeOwner);", "nonliteral import()"], ["require(runtimeOwner);", "nonliteral require()"], [ "type Value = import(runtimeOwner).Value;", "nonliteral import type", ], ])("rejects %s", (source, diagnostic) => { expect( getSourceImportBoundaryDiagnostics({ importerModulePath: "contract/capability.ts", importerRuntimePath: "modules/contract/capability.ts", source, }), ).toEqual([`contract/capability.ts -> ${diagnostic}`]); }); it("uses parsed compiler inventory for MTS and CTS sources", () => { expect(listRuntimeSourcePaths()).toEqual( expect.arrayContaining([ "contracts/performance-request-evidence-policy.d.mts", "model-import/formats/vendor/draco/draco_wasm_wrapper.d.cts", ]), ); }); it("rejects unresolved imports from every production module layer", () => { const importers = [ "built-ins/image-export/image-export-module.ts", "built-in-catalog.ts", "contract/capability.ts", "contributions/media-policy-contributions.ts", "graph/find-shortest-stable-cycle.ts", "resolution/resolve-product-modules.ts", ]; expect( importers.map((modulePath) => getImportBoundaryViolation( modulePath, `modules/${modulePath}`, "unresolved-module-owner", ), ), ).toEqual( importers.map( (modulePath) => `${modulePath} -> unresolved-module-owner`, ), ); }); it("fails closed for external, aliased, require, and nonliteral bypasses", () => { const runtimeSourceDirectory = dirname( dirname(fileURLToPath(import.meta.url)), ); const aliasCompilerOptions: ts.CompilerOptions = { baseUrl: runtimeSourceDirectory, module: ts.ModuleKind.ESNext, moduleResolution: ts.ModuleResolutionKind.Bundler, paths: { "@runtime/*": ["*"] }, }; expect( getSourceImportBoundaryDiagnostics({ importerModulePath: "contract/capability.ts", importerRuntimePath: "modules/contract/capability.ts", source: 'import React from "react";', }), ).toEqual(["contract/capability.ts -> react"]); const forbiddenAliasTargets = [ "react/app-shell/toolcraft-app", "model-import/model-import-limits", "source-assets/binary-media-hydration", "state/persistence-shared", ]; for (const importerModulePath of [ "built-ins/canvas-editing/canvas-editing-module.ts", "contract/capability.ts", ]) { expect( forbiddenAliasTargets.map((target) => getSourceImportBoundaryDiagnostics({ compilerOptions: aliasCompilerOptions, importerModulePath, importerRuntimePath: `modules/${importerModulePath}`, source: `import "@runtime/${target}";`, }), ), ).toEqual( forbiddenAliasTargets.map((target) => [ `${importerModulePath} -> ${target}${target.startsWith("react/") ? ".tsx" : ".ts"}`, ]), ); } expect( getSourceImportBoundaryDiagnostics({ importerModulePath: "contract/capability.ts", importerRuntimePath: "modules/contract/capability.ts", source: 'export * from "@repo/toolcraft-runtime/react";', }), ).toEqual(["contract/capability.ts -> react/index.ts"]); expect( getSourceImportBoundaryDiagnostics({ importerModulePath: "contributions/media-policy-contributions.ts", importerRuntimePath: "modules/contributions/media-policy-contributions.ts", source: 'require("react");', }), ).toEqual(["contributions/media-policy-contributions.ts -> react"]); expect( getSourceImportBoundaryDiagnostics({ importerModulePath: "resolution/resolve-product-modules.ts", importerRuntimePath: "modules/resolution/resolve-product-modules.ts", source: [ "void import(runtimeOwner);", "require(runtimeOwner);", ].join("\n"), }), ).toEqual([ "resolution/resolve-product-modules.ts -> nonliteral import()", "resolution/resolve-product-modules.ts -> nonliteral require()", ]); }); it("fails closed for relative, aliased, and package import types", () => { const runtimeSourceDirectory = dirname( dirname(fileURLToPath(import.meta.url)), ); const aliasCompilerOptions: ts.CompilerOptions = { baseUrl: runtimeSourceDirectory, module: ts.ModuleKind.ESNext, moduleResolution: ts.ModuleResolutionKind.Bundler, paths: { "@runtime/*": ["*"] }, }; expect( getSourceImportBoundaryDiagnostics({ compilerOptions: aliasCompilerOptions, importerModulePath: "contract/capability.ts", importerRuntimePath: "modules/contract/capability.ts", source: [ 'type RelativeEscape = import("../../react/index").ToolcraftAppProps;', 'type AliasEscape = import("@runtime/model-import/model-import-limits").ModelImportLimits;', 'type PackageEscape = import("@repo/toolcraft-runtime/react").ToolcraftAppProps;', "type ComputedEscape = import(runtimeOwner).ToolcraftAppProps;", ].join("\n"), }), ).toEqual([ "contract/capability.ts -> react/index.ts", "contract/capability.ts -> model-import/model-import-limits.ts", "contract/capability.ts -> react/index.ts", "contract/capability.ts -> nonliteral import type", ]); }); it.each([ ...compilerInventoriedContributionPhaseModulePaths, "resolution/contribution-phase/future-helper.ts", ])( "isolates contribution phase imports for compiler or future file %s", (importerModulePath) => { const importerRuntimePath = `modules/${importerModulePath}`; expect( getSourceImportBoundaryDiagnostics({ importerModulePath, importerRuntimePath, source: [ 'import { TOOLCRAFT_DEFAULT_PROVIDER_CATALOG } from "../../built-in-catalog";', 'import { layersModule } from "../../built-ins/layers/layers-module";', 'import { resolveToolcraftProductModules } from "../resolve-product-modules";', 'import { resolveToolcraftCanvasBehaviorContributions } from "../../contributions/canvas-behavior-contributions";', 'import { preflightToolcraftModuleContributions } from "./preflight-module-contributions";', ].join("\n"), }), ).toEqual([ `${importerModulePath} -> modules/built-in-catalog.ts`, `${importerModulePath} -> modules/built-ins/layers/layers-module.ts`, `${importerModulePath} -> modules/resolution/resolve-product-modules.ts`, ]); }, ); it("rejects every prohibited layer direction with deterministic diagnostics", () => { const prohibitedDirections = [ ["built-ins/image-export/module.ts", "modules/built-in-catalog.ts"], ["built-ins/image-export/module.ts", "modules/contributions/action.ts"], ["built-ins/image-export/module.ts", "modules/graph/cycle.ts"], ["built-ins/image-export/module.ts", "modules/resolution/resolve.ts"], ["built-ins/image-export/module.ts", "modules/testing/fixture.ts"], [ "built-ins/image-export/module.ts", "modules/built-ins/svg-export/module.ts", ], ["built-ins/image-export/module.ts", "react/app-shell.tsx"], ["built-in-catalog.ts", "modules/contributions/action.ts"], ["built-in-catalog.ts", "modules/graph/cycle.ts"], ["built-in-catalog.ts", "modules/resolution/resolve.ts"], ["built-in-catalog.ts", "modules/testing/fixture.ts"], ["built-in-catalog.ts", "schema/types.ts"], ["built-in-catalog.ts", "react/app-shell.tsx"], ["contributions/action.ts", "modules/built-ins/image-export/module.ts"], ["contributions/action.ts", "modules/built-in-catalog.ts"], ["contributions/action.ts", "modules/contributions/settings.ts"], ["contributions/action.ts", "modules/resolution/resolve.ts"], ["contributions/action.ts", "modules/testing/fixture.ts"], ["contributions/action.ts", "react/app-shell.tsx"], ["contract/capability.ts", "modules/built-ins/image-export/module.ts"], ["contract/capability.ts", "modules/built-in-catalog.ts"], ["contract/capability.ts", "modules/contributions/action.ts"], ["contract/capability.ts", "modules/graph/cycle.ts"], ["contract/capability.ts", "modules/resolution/resolve.ts"], ["contract/capability.ts", "modules/testing/fixture.ts"], ["contract/capability.ts", "react/app-shell.tsx"], ["graph/cycle.ts", "modules/contract/capability.ts"], ["graph/cycle.ts", "modules/built-ins/image-export/module.ts"], ["graph/cycle.ts", "modules/built-in-catalog.ts"], ["graph/cycle.ts", "modules/contributions/action.ts"], ["graph/cycle.ts", "modules/resolution/resolve.ts"], ["graph/cycle.ts", "modules/testing/fixture.ts"], ["graph/cycle.ts", "schema/types.ts"], ["graph/cycle.ts", "react/app-shell.tsx"], ["resolution/resolve.ts", "modules/built-ins/image-export/module.ts"], ["resolution/resolve.ts", "modules/testing/fixture.ts"], ["resolution/resolve.ts", "modules/resolve.test.ts"], ["resolution/resolve.ts", "react/app-shell.tsx"], ] as const; expect( prohibitedDirections.map(([importer, target]) => getBoundaryViolation(importer, target), ), ).toEqual( prohibitedDirections.map( ([importer, target]) => `${importer} -> ${target}`, ), ); }); it("keeps the production module graph within its declared layers", () => { expect( getProductionGraphBoundaryDiagnostics(), "Capability module layer violations (importer -> forbidden target).", ).toEqual([]); }); it.each([ { cycle: "contract/capability.ts -> contract/module-definition.ts -> contract/capability.ts", sources: new Map([ ["contract/capability.ts", 'import "./module-definition";'], ["contract/module-definition.ts", 'import "./capability";'], ]), }, { cycle: "contract/capability.ts -> contract/contribution.ts -> contract/integration-port.ts -> contract/capability.ts", sources: new Map([ ["contract/capability.ts", 'import "./contribution";'], ["contract/contribution.ts", 'import "./integration-port";'], ["contract/integration-port.ts", 'import "./capability";'], ]), }, { cycle: "resolution/contribution-phase/assemble-module-contributions.ts -> resolution/contribution-phase/preflight-module-contributions.ts -> resolution/contribution-phase/assemble-module-contributions.ts", sources: new Map([ [ "resolution/contribution-phase/assemble-module-contributions.ts", 'import "./preflight-module-contributions";', ], [ "resolution/contribution-phase/preflight-module-contributions.ts", 'import "./assemble-module-contributions";', ], ]), }, ])("rejects a synthetic import cycle $cycle", ({ cycle, sources }) => { expect(getSourceImportGraphCycleDiagnostic(sources)).toBe( `Capability module import cycle: ${cycle}.`, ); }); it("keeps the real production import graph acyclic", () => { expect(getProductionGraphCycleDiagnostic()).toBeUndefined(); }); });