feedback5 WW: split DESIGN.md into docs/design/ (the current rules) and docs/history/ (the per-release revisions), section numbers kept — a pure move: every ## N. block (heading, text, the --- after it) moves verbatim, each part file only gains a title line and a pointer to the index; docs/DESIGN.md keeps its header and becomes the index (a § → file table). design/overview.md §0 §1 §2 §11 §12, geometry-time.md §3 §4, engine.md §5 §7, match.md §6 §16, network.md §8 §14, client.md §9 §10 §13 §15; history/v2.2-playtest3.md §17, v2.3-playtest4.md §18, v2.4-playtest5.md §19, v2.5-playtest6.md §20, 0.1.1.md §21, 0.1.2.md §22, 0.1.3.md §23, 0.1.4.md §24, 0.2.0.md §25. Round trip: the index header plus the blocks in § order reproduce the pre-split DESIGN.md byte for byte (813 785 bytes, sha256 fe81884c…). Tests: test/helpers/designDocs.js designText() (the split script's splitBlocks / designText) reassembles the text in § order; docs-consistency and feedback1-gaps read it instead of docs/DESIGN.md (every pin unchanged); docs-paths guards the split (each § exactly once in docs/design/ or docs/history/, the index row of every file names its sections, every "DESIGN §N(.M)" cited in the repository is a heading — 779 in 327 files today); package.test keeps docs/design/ and docs/history/ out of the zips; golden unchanged
This commit is contained in:
1 parent
0f9009954d
commit
da1f5830ca
21 files changed
+3517
-3325
No files matched your search
@@ -0,0 +1,59 @@
|
||||
// test/helpers/designDocs.js — the design document as one text, for the tests that pin its sentences.
|
||||
//
|
||||
// import { designText } from '../helpers/designDocs.js';
|
||||
// const DESIGN = designText(ROOT); // the index's preamble, then every `## N.` block in § order
|
||||
//
|
||||
// docs/DESIGN.md is the index since 0.2.0: the current rules live in docs/design/*.md, the per-release revisions in
|
||||
// docs/history/*.md, and every `## N.` block (its heading, text and the `---` after it) sits in one of those files
|
||||
// verbatim. designText() puts the blocks back in section order (not file order — the tests slice it as `## n.` →
|
||||
// `## n+1.`), so from `## 0.` on it is the pre-split DESIGN.md byte for byte. A section found twice throws.
|
||||
|
||||
import { readFileSync, readdirSync, existsSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
|
||||
const HEAD_RE = /^## (\d+)\./;
|
||||
|
||||
/** The folders that hold the `## N.` blocks, after the index. */
|
||||
export const DESIGN_DIRS = ['docs/design', 'docs/history'];
|
||||
|
||||
/** Split a Markdown text at its `## N.` headings: { preamble, blocks: Map<N, text> } (each block ends before the next heading). */
|
||||
export function splitBlocks(text) {
|
||||
const lines = text.split('\n');
|
||||
const blocks = new Map();
|
||||
let cur = null;
|
||||
let buf = [];
|
||||
const preamble = [];
|
||||
const flush = () => {
|
||||
if (cur == null) preamble.push(...buf);
|
||||
else {
|
||||
if (blocks.has(cur)) throw new Error(`§${cur} appears twice`);
|
||||
blocks.set(cur, buf.join('\n'));
|
||||
}
|
||||
buf = [];
|
||||
};
|
||||
for (const line of lines) {
|
||||
const m = line.match(HEAD_RE);
|
||||
if (m) { flush(); cur = Number(m[1]); }
|
||||
buf.push(line);
|
||||
}
|
||||
flush();
|
||||
return { preamble: preamble.join('\n'), blocks };
|
||||
}
|
||||
|
||||
/** The design text in § order: the index's preamble, then every part file's blocks sorted by section number. */
|
||||
export function designText(root) {
|
||||
const index = readFileSync(join(root, 'docs/DESIGN.md'), 'utf8');
|
||||
const all = new Map();
|
||||
const { preamble, blocks: own } = splitBlocks(index);
|
||||
for (const [n, t] of own) all.set(n, t);
|
||||
for (const dir of DESIGN_DIRS) {
|
||||
if (!existsSync(join(root, dir))) continue;
|
||||
for (const f of readdirSync(join(root, dir)).filter((x) => x.endsWith('.md')).sort()) {
|
||||
for (const [n, t] of splitBlocks(readFileSync(join(root, dir, f), 'utf8')).blocks) {
|
||||
if (all.has(n)) throw new Error(`§${n} appears twice (${dir}/${f})`);
|
||||
all.set(n, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
return [preamble, ...[...all].sort((a, b) => a[0] - b[0]).map(([, t]) => t)].join('\n');
|
||||
}
|
||||
Reference in new issue
Block a user