// The chapter-path check, checked. // // Same rule as the rename check's own suite: a check written when the thing it // guards is already clean never fires again, and nothing distinguishes "still // checking" from "quietly broken" without cases it is required to reject. Every // "must not catch" case below is a real span that appears in the book. // // No filesystem — `problems()` takes `exists` as an argument precisely so it can // be tested this way, and `claimedPaths()` is pure. const test = require('node:test') const assert = require('node:assert') const { ANCHORS, claimedPaths, problems } = require('./checkChapterPaths') /** `problems()` over a fixture set of paths that exist. */ const check = (claims, present) => problems({ claims, exists: (p) => new Set([...present, ...ANCHORS.map((a) => a.replace(/\/$/, ''))]).has(p) }) test('a claim that resolves is not a problem', () => { assert.deepStrictEqual(check([{ file: 'book/01.md', line: 3, path: 'template/module.json' }], ['template/module.json']), []) }) test('a claim that does not resolve fails, naming the file and line', () => { const found = check([{ file: 'book/02-website-module.md', line: 41, path: 'template/server/gone.js' }], []) assert.strictEqual(found.length, 1) assert.match(found[0], /book\/02-website-module\.md:41.*template\/server\/gone\.js/) }) test('a missing anchor fails on its own', () => { // The half that keeps this check honest: if `template/` is renamed, every // template path in the book is wrong AND the check would stop looking at them. const found = problems({ claims: [], exists: (p) => p !== 'template' }) assert.strictEqual(found.length, 1) assert.match(found[0], /template\/ is listed as an anchor and does not exist/) }) test('paths are read only from inline code spans', () => { const md = 'Open the entry point and read it: template/server/index.js, then stop.' assert.deepStrictEqual(claimedPaths(md), []) }) test('a code span inside a fenced block is not a claim', () => { // A fence is usually the reader's own future tree, and their files are not ours. const md = ['```', '`template/nope.js`', 'template/also-nope.js', '```'].join('\n') assert.deepStrictEqual(claimedPaths(md), []) }) test('a path in another repo is not this check\'s business', () => { const md = 'The store is `sidecar/src/store.rs`, and the plugin is `overlay/Scripts/Custom/Bridge/BridgeLink.cs`.' assert.deepStrictEqual(claimedPaths(md), []) }) test('a placeholder shape is not a path', () => { const md = 'Your copy lands at `template//module.json`, and the checks are `scripts/*.js`.' assert.deepStrictEqual(claimedPaths(md), []) }) test('a command line is not a path', () => { // The first token is an anchor in neither case, but a span that BEGINS with one // and carries arguments would otherwise be read as a filename with spaces in it. const md = 'Run `npm ci --prefix template/server`, or `template/server && npm test` if you must.' assert.deepStrictEqual(claimedPaths(md), []) }) test('trailing sentence punctuation is stripped, not skipped', () => { const md = 'It all lives under `template/`.' assert.deepStrictEqual(claimedPaths(md), [{ path: 'template/', line: 1 }]) }) test('a claim on a later line reports that line', () => { const md = ['# Title', '', 'See `template/server/boot.js`.'].join('\n') assert.deepStrictEqual(claimedPaths(md), [{ path: 'template/server/boot.js', line: 3 }]) }) test('every anchor is a directory of this repo', () => { // Stated, not derived (see the header) — so this asserts the stated list is // still the real one at the moment it is written down. assert.ok(ANCHORS.every((a) => a.endsWith('/')), 'anchors are directory prefixes') })