Public: anyone can read this; the crew can change it.
Zero dependencies, kept: a test fails the moment a package or a remote asset is added #25
Check · Review · Land · Live done — Landed and live in production.
mason/listing-launch:mason/23-zero-dependencies-kept-a-test-fails-the → main 2 commits fork 2 threads · 2 unresolved
2 files
changed +95
−0
README.md +4
| @@ -117,6 +117,10 @@ every open pull gets a preview at its own address with its own copy of the | ||
| 117 | 117 | data. Everything the app keeps lives under `FORGE_APP_DATA`, which is what |
| 118 | 118 | makes "production data" and "preview data" two different things. |
| 119 | 119 | |
| 120 | There are no packages to install: `package.json` declares none, every | |
| 121 | import is relative, `bun:` or `node:`, and no page loads anything from | |
| 122 | another host. `src/deps.test.ts` fails the moment that stops being true. | |
| 123 | ||
| 120 | 124 | sh |
| 121 | 125 | PORT=8080 FORGE_APP_DATA=./data bun run src/server.ts # run it here |
| 122 | 126 | bun test # what `forge.json`'s app.test runs on every push |
src/deps.test.ts added +91
| @@ -0,0 +1,91 @@ | ||
| 1 | import { expect, test } from "bun:test"; | |
| 2 | import { existsSync, readdirSync, readFileSync, statSync } from "node:fs"; | |
| 3 | import { join } from "node:path"; | |
| 4 | ||
| 5 | const root = join(import.meta.dir, ".."); | |
| 6 | ||
| 7 | const walk = (dir: string): string[] => | |
| 8 | readdirSync(dir).flatMap((name) => { | |
| 9 | const path = join(dir, name); | |
| 10 | return statSync(path).isDirectory() ? walk(path) : [path]; | |
| 11 | }); | |
| 12 | ||
| 13 | const read = (path: string) => readFileSync(path, "utf8"); | |
| 14 | ||
| 15 | test("package.json declares no packages", () => { | |
| 16 | const pkg = JSON.parse(read(join(root, "package.json"))); | |
| 17 | for (const key of ["dependencies", "devDependencies", "peerDependencies"]) { | |
| 18 | expect(pkg[key], key).toBeUndefined(); | |
| 19 | } | |
| 20 | }); | |
| 21 | ||
| 22 | test("every import in src/ and scripts/ is relative, bun: or node:", () => { | |
| 23 | const files = [...walk(join(root, "src")), ...walk(join(root, "scripts"))].filter((f) => f.endsWith(".ts") && !f.endsWith("deps.test.ts")); // its samples are bad on purpose | |
| 24 | const spec = /^\s*(?:import|export)\b[^"'`;]*?\bfrom\s*["']([^"']+)["']|^\s*import\s*["']([^"']+)["']|\bimport\(\s*["']([^"']+)["']\s*\)/gm; | |
| 25 | const bad: string[] = []; | |
| 26 | for (const file of files) { | |
| 27 | for (const m of read(file).matchAll(spec)) { | |
| 28 | const s = m[1] ?? m[2] ?? m[3]!; | |
| 29 | if (!(s.startsWith("./") || s.startsWith("../") || s.startsWith("bun:") || s.startsWith("node:"))) { | |
| 30 | bad.push(`${file.slice(root.length + 1)}: ${s}`); | |
| 31 | } | |
| 32 | } | |
| 33 | } | |
| 34 | expect(bad).toEqual([]); | |
| 35 | }); | |
| 36 | ||
| 37 | // Markup attributes, CSS and network calls only: https:// in prose or in typed | |
| 38 | // links is fine. The app's own links are relative paths, so any remote href is a violation. | |
| 39 | const REMOTE = String.raw`(?:https?:|wss?:)?//`; | |
| 40 | const remoteRefs: RegExp[] = [ | |
| 41 | new RegExp(String.raw`\b(?:src|srcset|poster|action|data|href)\s*=\s*["']?\s*${REMOTE}`, "gi"), | |
outdated
No pattern covers fetch/WebSocket/EventSource/import to a remote URL in static/*.js or src. Add one. Also add a positive-control test that these regexes flag a known-bad sample, so a broken regex can't pass silently. |
||
| 42 | new RegExp(String.raw`@import\s+(?:url\(\s*)?["']?\s*${REMOTE}`, "gi"), | |
| 43 | new RegExp(String.raw`\burl\(\s*["']?\s*${REMOTE}`, "gi"), | |
| 44 | new RegExp(String.raw`\b(?:fetch|import|importScripts|sendBeacon|open)\s*\(\s*(?:[^,)"'\x60]+,\s*)?["'\x60]\s*${REMOTE}`, "gi"), | |
| 45 | new RegExp(String.raw`\bnew\s+(?:WebSocket|EventSource|Worker|SharedWorker)\s*\(\s*["'\x60]\s*${REMOTE}`, "gi"), | |
| 46 | ]; | |
| 47 | ||
| 48 | const findRemote = (text: string): string[] => remoteRefs.flatMap((re) => [...text.matchAll(re)].map((m) => m[0])); | |
| 49 | ||
| 50 | test("the remote-reference scan flags bad samples and passes good ones", () => { | |
| 51 | for (const bad of [ | |
| 52 | '<script src="https://x/y.js">', | |
| 53 | '<link href="//cdn.x/a.css">', | |
| 54 | '@import "//x";', | |
| 55 | "@import url(https://x/a.css);", | |
| 56 | "a { background: url(https://x) }", | |
| 57 | 'fetch("https://x/api")', | |
| 58 | 'fetch("/ok"); fetch(`https://x/${id}`)', | |
| 59 | 'new WebSocket("wss://x/live")', | |
| 60 | 'new EventSource("http://x/stream")', | |
| 61 | 'await import("https://x/m.js")', | |
| 62 | ]) { | |
| 63 | expect(findRemote(bad), bad).not.toEqual([]); | |
| 64 | } | |
| 65 | for (const good of [ | |
| 66 | '<script src="/static/live.js">', | |
| 67 | '<a href="/listings/1">', | |
| 68 | "a { background: url(/static/a.svg) }", | |
| 69 | '@import "/static/b.css";', | |
| 70 | 'fetch("/listings/1")', | |
| 71 | 'new EventSource("/live")', | |
| 72 | "<p>See https://example.com for details</p>", | |
| 73 | ]) { | |
| 74 | expect(findRemote(good), good).toEqual([]); | |
| 75 | } | |
| 76 | }); | |
| 77 | ||
| 78 | test("no page, CSS or JS reaches a remote URL", () => { | |
| 79 | const files = [...walk(join(root, "src")), ...walk(join(root, "static"))].filter( | |
| 80 | (f) => /\.(ts|js|css|html)$/.test(f) && !f.endsWith(".test.ts"), | |
| 81 | ); | |
| 82 | expect(files.length).toBeGreaterThan(0); | |
| 83 | const found = files.flatMap((f) => findRemote(read(f)).map((m) => `${f.slice(root.length + 1)}: ${m}`)); | |
| 84 | expect(found).toEqual([]); | |
| 85 | }); | |
| 86 | ||
| 87 | test("no lockfile or node_modules: nothing is installed", () => { | |
| 88 | for (const name of ["bun.lock", "bun.lockb", "package-lock.json", "yarn.lock", "pnpm-lock.yaml", "node_modules"]) { | |
| 89 | expect(existsSync(join(root, name)), name).toBe(false); | |
| 90 | } | |
| 91 | }); |
new above
offline
Scope too narrow: this misses markup built in src/routes.ts, src/photos.ts, src/generate.ts, src/server.ts. Walk all non-test .ts under src/ as well as static/.