import { expect, test } from "bun:test" import { readdirSync, readFileSync, statSync } from "node:fs" import { join } from "node:path" // The engine is the reusable, content-agnostic layer: it must import nothing from // game (content) or app (browser glue). game -> engine and app -> game -> engine are // fine; the reverse is the violation. This freezes the Stage-3 seam so a stray import // can't quietly re-couple the layers. function tsFiles(dir: string): string[] { const out: string[] = [] for (const name of readdirSync(dir)) { const p = join(dir, name) if (statSync(p).isDirectory()) { out.push(...tsFiles(p)) } else if (p.endsWith(".ts")) { out.push(p) } } return out } test("engine imports nothing from game or app", () => { const engineDir = new URL("../engine", import.meta.url).pathname const offenders = tsFiles(engineDir).filter((f) => /from\s+["'][^"']*\/(?:game|app)\//.test(readFileSync(f, "utf8"))) expect(offenders).toEqual([]) }) test("game imports nothing from app", () => { const gameDir = new URL("../game", import.meta.url).pathname const offenders = tsFiles(gameDir).filter((f) => /from\s+["'][^"']*\/app\//.test(readFileSync(f, "utf8"))) expect(offenders).toEqual([]) })