/** * The public package surface, and the one promise it makes. * * `src/index.ts` is what `package.json`'s `"."` export points at, so it is the * thing a verifier, a training harness or a Node service `import`s. The promise * is that everything reachable from it runs **with no renderer, no DOM and no * network** — because the consumers who want the arena and the simulators are * precisely the consumers who have none of the three. * * That is not a property you can assert by importing the file and seeing it * work: `import * as THREE from "three"` succeeds perfectly well under Node and * costs a consumer half a megabyte for nothing. So this walks the static import * graph and reads it. A single `from "three"` anywhere in the closure fails, * and names the file and the chain that reached it, which is the only form of * this failure anybody can act on. */ import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; import test from "node:test"; import * as barrel from "../../index.ts"; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../.."); const ENTRY = path.join(ROOT, "src/index.ts"); /** * Every relative specifier in a file, `import` and `export` alike. * * `export * from "./x.ts"` is the form the barrel itself is written in, and a * matcher that only looked at `import` would walk none of it. */ const SPECIFIER = /(?:^|\n)\s*(?:import|export)\b[^;\n]*?from\s+["']([^"']+)["']/g; /** `await import("./x.ts")`, which is how a renderer would sneak in lazily. */ const DYNAMIC = /\bimport\s*\(\s*["']([^"']+)["']\s*\)/g; /** Walk the graph from `entry`, returning every file reached and how. */ function closure(entry: string): Map { const reached = new Map([[entry, []]]); const queue = [entry]; while (queue.length > 0) { const file = queue.shift() as string; const source = readFileSync(file, "utf8"); const chain = reached.get(file) ?? []; for (const pattern of [SPECIFIER, DYNAMIC]) { pattern.lastIndex = 0; let match: RegExpExecArray | null; while ((match = pattern.exec(source)) !== null) { const specifier = match[1]; if (specifier === undefined || !specifier.startsWith(".")) continue; const resolved = path.resolve(path.dirname(file), specifier); if (reached.has(resolved)) continue; reached.set(resolved, [...chain, path.relative(ROOT, file)]); queue.push(resolved); } } } return reached; } /** Bare specifiers a module in the closure is allowed to depend on. */ const ALLOWED_PACKAGES = new Set([]); test("the barrel exports the renderer-independent surfaces this build added", () => { for (const name of [ "ARENA_ENVIRONMENTS", "flattenObservation", "structureAction", "observationWidth", "rollout", "createSimulatedDevices", "createSimulatedVehicleTelemetry", "normalizeDeviceCommand", "normalizeVehicleTelemetryCommand", "exteriorVehicleAppearance", "DEVICE_RANGES", "Plan", ]) { assert.ok( name in barrel, `src/index.ts no longer exports ${name}; a consumer's import just broke`, ); } }); test("nothing reachable from the barrel imports three.js", () => { const offenders: string[] = []; for (const [file, chain] of closure(ENTRY)) { const source = readFileSync(file, "utf8"); if (/from\s+["']three(?:\/|["'])/.test(source) || /import\s*\(\s*["']three/.test(source)) { offenders.push(`${path.relative(ROOT, file)} (via ${chain.join(" → ") || "the barrel itself"})`); } } assert.deepEqual( offenders, [], "three.js is on the public package surface. The render layer for a simulation " + "(interiors/devices.ts, engine/officeExterior.ts, interiors/officeScene.ts) is " + "never exported; the state machine behind it is.", ); }); test("nothing reachable from the barrel takes a bare dependency at all", () => { const offenders: string[] = []; for (const [file] of closure(ENTRY)) { const source = readFileSync(file, "utf8"); for (const pattern of [SPECIFIER, DYNAMIC]) { pattern.lastIndex = 0; let match: RegExpExecArray | null; while ((match = pattern.exec(source)) !== null) { const specifier = match[1]; if (specifier === undefined) continue; if (specifier.startsWith(".") || specifier.startsWith("node:")) continue; if (ALLOWED_PACKAGES.has(specifier)) continue; offenders.push(`${path.relative(ROOT, file)} → ${specifier}`); } } } assert.deepEqual(offenders, [], "an unvetted runtime dependency reached the package surface"); }); test("nothing reachable from the barrel reaches for a browser global", () => { // Read as source rather than executed, because a `document` reference inside a // branch nobody takes is still a module that cannot be loaded in a worker // whose global object does not have one. const globals = /\b(?:document|localStorage|sessionStorage|navigator|requestAnimationFrame)\b/; const offenders: string[] = []; for (const [file] of closure(ENTRY)) { const source = readFileSync(file, "utf8") // Comments talk about the DOM constantly and correctly; only code counts. .replace(/\/\*[\s\S]*?\*\//g, "") .replace(/(^|\n)\s*\/\/[^\n]*/g, "$1"); if (globals.test(source)) offenders.push(path.relative(ROOT, file)); } assert.deepEqual(offenders, [], "a DOM global is reachable from the package surface"); });