const contributionPhaseModulePathPrefix = "resolution/contribution-phase/"; export function isContributionPhaseModulePath(modulePath: string): boolean { return modulePath.startsWith(contributionPhaseModulePathPrefix); } export const schemaOnlyContributionMaterializers = Object.freeze( [ "contributions/canvas-behavior-contributions.ts", "contributions/media-policy-contributions.ts", "contributions/panel-surface-contributions.ts", "contributions/persistence-contributions.ts", ] as const, ); const schemaOnlyContributionMaterializerLookup = new Set( schemaOnlyContributionMaterializers, ); export const publicModuleAllowedTargetRuntimePaths = Object.freeze([ "modules/built-ins/canvas-editing/canvas-editing-module.ts", "modules/built-ins/image-export/image-export-module.ts", "modules/built-ins/layers/layers-module.ts", "modules/built-ins/media-source/media-source-module.ts", "modules/built-ins/model-3d/model-3d-module.ts", "modules/built-ins/spatial-view/spatial-view-module.ts", "modules/built-ins/svg-export/svg-export-module.ts", "modules/built-ins/timeline/timeline-module.ts", "modules/built-ins/video-export/video-export-module.ts", "modules/contract/capability.ts", "modules/contract/integration-port.ts", "modules/contract/module-definition.ts", "modules/contract/module-plan.ts", ] as const); const publicModuleAllowedTargetRuntimePathLookup = new Set( publicModuleAllowedTargetRuntimePaths, ); type ProductionModuleLayer = | "built-in" | "catalog" | "contract" | "contribution" | "graph" | "public" | "resolution"; type ResolvedTargetLayer = | ProductionModuleLayer | "other-runtime" | "schema" | "test-support"; export function isTestSupportModulePath(modulePath: string): boolean { const segments = modulePath.split("/"); const fileName = segments.at(-1) ?? ""; return ( segments.includes("testing") || segments.includes("__tests__") || segments.includes("fixtures") || segments.includes("__fixtures__") || segments.includes("test-support") || fileName.includes(".test.") || fileName.includes(".spec.") || fileName.includes(".fixture.") ); } export function getProductionLayerMatches( modulePath: string, ): readonly ProductionModuleLayer[] { if (isTestSupportModulePath(modulePath)) { return []; } const firstSegment = modulePath.split("/")[0]; const matches: ProductionModuleLayer[] = []; if (modulePath === "built-in-catalog.ts") matches.push("catalog"); if (firstSegment === "built-ins") matches.push("built-in"); if (firstSegment === "contract") matches.push("contract"); if (firstSegment === "contributions") matches.push("contribution"); if (firstSegment === "graph") matches.push("graph"); if (modulePath === "public.ts") matches.push("public"); if (firstSegment === "resolution") matches.push("resolution"); return matches; } export function getProductionLayer( modulePath: string, ): ProductionModuleLayer | undefined { const matches = getProductionLayerMatches(modulePath); return matches.length === 1 ? matches[0] : undefined; } function classifyResolvedTarget(runtimePath: string): ResolvedTargetLayer { if (!runtimePath.startsWith("modules/")) { return runtimePath.startsWith("schema/") ? "schema" : "other-runtime"; } const modulePath = runtimePath.slice("modules/".length); if (isTestSupportModulePath(modulePath)) return "test-support"; return getProductionLayer(modulePath) ?? "other-runtime"; } function isAllowedContributionPhaseTarget(runtimePath: string): boolean { if (runtimePath.startsWith("schema/")) return true; if (!runtimePath.startsWith("modules/")) return false; const modulePath = runtimePath.slice("modules/".length); if (isTestSupportModulePath(modulePath)) return false; return ( modulePath.startsWith("contract/") || modulePath.startsWith("contributions/") || isContributionPhaseModulePath(modulePath) ); } function getBuiltInDirectory(modulePath: string): string | undefined { const segments = modulePath.split("/"); return segments[0] === "built-ins" && segments.length >= 3 ? segments.slice(0, 2).join("/") : undefined; } const allowedTargetLayers: Readonly< Record> > = { "built-in": new Set(["contract", "schema"]), catalog: new Set(["built-in", "contract"]), contract: new Set(["contract", "schema"]), contribution: new Set(["contract", "graph", "schema"]), graph: new Set(["graph"]), public: new Set(), resolution: new Set([ "contract", "contribution", "graph", "resolution", "schema", ]), }; export function getBoundaryViolation( importerModulePath: string, targetRuntimePath: string, ): string | undefined { const importerLayer = getProductionLayer(importerModulePath); if (importerLayer === undefined) { return `${importerModulePath} -> ${targetRuntimePath}`; } if (isContributionPhaseModulePath(importerModulePath)) { return isAllowedContributionPhaseTarget(targetRuntimePath) ? undefined : `${importerModulePath} -> ${targetRuntimePath}`; } if (importerLayer === "public") { return publicModuleAllowedTargetRuntimePathLookup.has(targetRuntimePath) ? undefined : `${importerModulePath} -> ${targetRuntimePath}`; } const targetLayer = classifyResolvedTarget(targetRuntimePath); if (schemaOnlyContributionMaterializerLookup.has(importerModulePath)) { return targetLayer === "contract" || targetLayer === "schema" ? undefined : `${importerModulePath} -> ${targetRuntimePath}`; } if (targetLayer === "test-support") { return `${importerModulePath} -> ${targetRuntimePath}`; } if (importerLayer === "built-in" && /^built-ins\/[^/]+\/contracts\.ts$/.test(importerModulePath) && targetRuntimePath === "state/types.ts") return undefined; if (importerLayer === "built-in" && /\/core\//.test(importerModulePath) && /^(?:state|source-assets|model-import|export|scene|rendering)\//.test(targetRuntimePath)) return undefined; if (importerLayer === "built-in" && /\/react\//.test(importerModulePath) && /^(?:react|state|scene|rendering)\//.test(targetRuntimePath)) return undefined; if (importerLayer === "built-in" && targetLayer === "built-in") { const importerDirectory = getBuiltInDirectory(importerModulePath); const targetModulePath = targetRuntimePath.slice("modules/".length); return importerDirectory !== undefined && (importerDirectory === getBuiltInDirectory(targetModulePath) || /^built-ins\/[^/]+\/contracts\.ts$/.test(targetModulePath)) ? undefined : `${importerModulePath} -> ${targetRuntimePath}`; } return allowedTargetLayers[importerLayer].has(targetLayer) ? undefined : `${importerModulePath} -> ${targetRuntimePath}`; }