import { readFileSync } from "node:fs"; import { dirname, extname, join, normalize, relative, resolve, } from "node:path"; import { describe, expect, it } from "vitest"; const adminRoot = resolve(__dirname); const extensions = [".ts", ".tsx"]; function resolveImport(importer: string, specifier: string): string | null { if (!specifier.startsWith(".")) return null; const target = resolve(dirname(importer), specifier); const candidates = extname(target) ? [target] : [ ...extensions.map((extension) => `${target}${extension}`), ...extensions.map((extension) => join(target, `index${extension}`)), ]; return ( candidates.find((candidate) => { try { readFileSync(candidate); return true; } catch { return false; } }) ?? null ); } function importsFor(file: string): string[] { const source = readFileSync(file, "utf8"); const specifiers = importSpecifiers(source); return specifiers.flatMap((specifier) => { const resolved = resolveImport(file, specifier); return resolved ? [resolved] : []; }); } function importSpecifiers(source: string): string[] { return Array.from( source.matchAll(/(?:from\s+|import\s*(?:\(\s*)?)(["'])([^"']+)\1/g), (match) => match[2], ); } describe("shared admin dependency boundary", () => { it("recognizes static, side-effect, and dynamic imports", () => { expect( importSpecifiers(` import value from "./static"; import "./side-effect"; const lazy = import("./dynamic"); `), ).toEqual(["./static", "./side-effect", "./dynamic"]); }); it("keeps the free entry graph premium-free and acyclic", () => { const entry = join(adminRoot, "main.tsx"); const visited = new Set(); const visiting = new Set(); const cycles: string[] = []; function walk(file: string) { const canonical = normalize(file); if (visiting.has(canonical)) { cycles.push(relative(adminRoot, canonical)); return; } if (visited.has(canonical)) return; visiting.add(canonical); for (const dependency of importsFor(canonical)) { if (normalize(dependency).startsWith(adminRoot)) walk(dependency); } visiting.delete(canonical); visited.add(canonical); } walk(entry); const graph = Array.from(visited, (file) => relative(adminRoot, file).replace(/\\/g, "/"), ); expect(graph).toContain("components/AdminShell.tsx"); expect(graph.some((file) => file.startsWith("extension/"))).toBe(false); expect(cycles).toEqual([]); }); it("has both app entries consume the shared shell without premium imports", () => { const sharedShell = readFileSync( join(adminRoot, "components", "AdminShell.tsx"), "utf8", ); const freeApp = readFileSync(join(adminRoot, "App.tsx"), "utf8"); const extensionApp = readFileSync( join(adminRoot, "extension", "ExtensionApp.tsx"), "utf8", ); expect(freeApp).toContain(" specifier.includes("extension"), ), ).toBe(false); }); });