@nielspeter/eess-md 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/rules/ledger.d.ts +38 -0
- package/dist/rules/ledger.d.ts.map +1 -1
- package/dist/rules/ledger.js +138 -32
- package/dist/rules/ledger.js.map +1 -1
- package/package.json +2 -2
package/dist/rules/ledger.d.ts
CHANGED
|
@@ -34,6 +34,19 @@ export interface HonestyAtCloseOptions extends PresetReportOptions {
|
|
|
34
34
|
* check is disabled. Default `false`.
|
|
35
35
|
*/
|
|
36
36
|
readonly closeInPlace?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* The full `State:` vocabulary this corpus uses. A token outside it is
|
|
39
|
+
* **reported** (`ledger/unknown-state`), not ignored. Default: the plan lane's
|
|
40
|
+
* enum. A bug-shaped lane passes its own, e.g.
|
|
41
|
+
* `['Draft', 'Ready', 'Fixed', 'Rejected', 'Parked']`.
|
|
42
|
+
*/
|
|
43
|
+
readonly states?: readonly string[];
|
|
44
|
+
/**
|
|
45
|
+
* Which of {@link states} mean *closed*. Default `['Done', "Won't-do"]`; a
|
|
46
|
+
* bug lane passes `['Fixed', 'Rejected']`. Members are treated as known states
|
|
47
|
+
* whether or not they also appear in {@link states}.
|
|
48
|
+
*/
|
|
49
|
+
readonly terminalStates?: readonly string[];
|
|
37
50
|
}
|
|
38
51
|
/**
|
|
39
52
|
* Run the honesty-at-close gate over a corpus. Throws `ArchRuleError` on any
|
|
@@ -41,4 +54,29 @@ export interface HonestyAtCloseOptions extends PresetReportOptions {
|
|
|
41
54
|
* done-items (the inverse of the frozen-folder exemption).
|
|
42
55
|
*/
|
|
43
56
|
export declare function honestyAtClose(corpus: Corpus, options?: HonestyAtCloseOptions): ArchViolation[];
|
|
57
|
+
/** What a {@link honestyAtClose} run actually examined. */
|
|
58
|
+
export interface LedgerStats {
|
|
59
|
+
/** Documents considered (board files excluded). */
|
|
60
|
+
readonly scanned: number;
|
|
61
|
+
/** …of which carry a `State:` line the declared vocabulary can read. */
|
|
62
|
+
readonly withReadableState: number;
|
|
63
|
+
/** …of which carry a `State:` line whose value is not in the vocabulary. */
|
|
64
|
+
readonly unreadableState: number;
|
|
65
|
+
/** …of which are *done* — by folder or by terminal state — and so ledger-checked. */
|
|
66
|
+
readonly doneItems: number;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The denominator, computed by the preset itself.
|
|
70
|
+
*
|
|
71
|
+
* `withReadableState` is the number nobody could see when bug 0119 happened: the
|
|
72
|
+
* placement check had never examined a document, and every summary line in the
|
|
73
|
+
* repo reported a healthy done-count derived purely from folder membership. A
|
|
74
|
+
* caller that prints this cannot be blind and green at the same time — if the
|
|
75
|
+
* region assumption drifts from the corpus again, this drops and says so.
|
|
76
|
+
*
|
|
77
|
+
* Callers must not re-derive it. `check-ledger.mjs` did, with a copy of the very
|
|
78
|
+
* expression 0119 removed, and its copy disagreed with the preset on 56 of 56
|
|
79
|
+
* records while heading a section captioned "so a green is provably non-vacuous".
|
|
80
|
+
*/
|
|
81
|
+
export declare function ledgerStats(corpus: Corpus, options?: HonestyAtCloseOptions): LedgerStats;
|
|
44
82
|
//# sourceMappingURL=ledger.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../src/rules/ledger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAE1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAG1D;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,qBAAsB,SAAQ,mBAAmB;IAChE;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACxC,sEAAsE;IACtE,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACvC;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../src/rules/ledger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAE1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAG1D;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,qBAAsB,SAAQ,mBAAmB;IAChE;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACxC,sEAAsE;IACtE,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACvC;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAA;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC5C;AAoOD;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,qBAA0B,GAClC,aAAa,EAAE,CAoBjB;AAED,2DAA2D;AAC3D,MAAM,WAAW,WAAW;IAC1B,mDAAmD;IACnD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,wEAAwE;IACxE,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;IAClC,4EAA4E;IAC5E,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,qFAAqF;IACrF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,GAAG,WAAW,CAqB5F"}
|
package/dist/rules/ledger.js
CHANGED
|
@@ -2,11 +2,46 @@ import { finishPreset } from '@nielspeter/eess';
|
|
|
2
2
|
import { collectTaskItems } from '../model/task-items.js';
|
|
3
3
|
const DEFAULT_DONE_FOLDERS = ['/completed/', '/fixed/', '/wont-do/', '/delivered/', '/archived/'];
|
|
4
4
|
const DEFAULT_BOARD_FILES = ['ROADMAP.md', 'BUGS.md', 'REFINEMENT.md', 'SUPPORT.md', 'README.md'];
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
// The
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
const DEFAULT_STATES = ['Draft', 'Ready', 'Open', 'Done', "Won't-do"];
|
|
6
|
+
const DEFAULT_TERMINAL_STATES = ['Done', "Won't-do"];
|
|
7
|
+
// The `State:` label. A colon is **required** in every form: making it optional
|
|
8
|
+
// turned any line beginning with the word "State" into a state declaration, so
|
|
9
|
+
// `Stateless rendering is the default` reported its state as `less` and
|
|
10
|
+
// `State machine transitions are documented` reported `machine`. Both were
|
|
11
|
+
// silent before and would have been build failures.
|
|
12
|
+
const LABEL = String.raw `^\s*(?:[-*+]\s+)?(?:\*\*State:\*\*|\*\*State\*\*\s*:|__State__\s*:|State\s*:)\s*`;
|
|
13
|
+
// An emphasis wrapper or a leading symbol on the value — `**Done**`, `` `Done` ``,
|
|
14
|
+
// `✅ Done`. Markdown, not vocabulary.
|
|
15
|
+
const WRAP = String.raw `(?:\*\*|__|\x60|_)?(?:[^\w\s'’-]+\s*)?`;
|
|
16
|
+
const escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
17
|
+
/**
|
|
18
|
+
* A matcher built **from the declared vocabulary**, not a blind token grab.
|
|
19
|
+
*
|
|
20
|
+
* Capturing `(\S+)` and comparing it to the enum looked equivalent and was not:
|
|
21
|
+
* it regressed shapes the old enum regex read correctly — `**State: Done**`
|
|
22
|
+
* captured `Done**`, `- **State:** Done.` captured `Done.` — and told the author
|
|
23
|
+
* their corpus does not declare a state it plainly declares. It also made a
|
|
24
|
+
* multi-word state (`In progress`) unrepresentable, so `states` could not
|
|
25
|
+
* express the vocabularies it exists to express.
|
|
26
|
+
*
|
|
27
|
+
* Alternatives are sorted longest-first so `In progress` wins over `In`, the
|
|
28
|
+
* apostrophe accepts either glyph (an editor smart-quoting `Won't-do` should not
|
|
29
|
+
* break a build over two near-identical characters), and matching is
|
|
30
|
+
* case-insensitive with the declared spelling returned as canonical.
|
|
31
|
+
*/
|
|
32
|
+
function stateMatcher(states) {
|
|
33
|
+
const alts = [...states]
|
|
34
|
+
.sort((a, b) => b.length - a.length)
|
|
35
|
+
.map((s) => escapeRe(s).replace(/['’]/g, "['’]"))
|
|
36
|
+
.join('|');
|
|
37
|
+
return new RegExp(`${LABEL}${WRAP}(${alts})(?![\\w'’-])`, 'i');
|
|
38
|
+
}
|
|
39
|
+
// Fallback: the line IS a state declaration, but its value is not in the
|
|
40
|
+
// vocabulary. Used only to name the offending value in the message — so it
|
|
41
|
+
// captures up to the house `—` separator rather than one whitespace-delimited
|
|
42
|
+
// token, or a multi-word state would be reported by its first word alone.
|
|
43
|
+
const UNREADABLE_RE = new RegExp(`${LABEL}(\\S[^—–]*?)\\s*(?:[—–].*)?$`, 'i');
|
|
44
|
+
const ELIDE = 32;
|
|
10
45
|
// Any one of these on a box's line marks it *disposed* (not silent). Tokens are
|
|
11
46
|
// the canonical hyphenated enum, word-bounded — so prose like "…the connection
|
|
12
47
|
// dropped in prod" does not falsely exempt a silent box. `deferred` must name a
|
|
@@ -21,13 +56,45 @@ const FENCE_RE = /(```|~~~)[\s\S]*?\1/g;
|
|
|
21
56
|
function stripFencedCode(s) {
|
|
22
57
|
return s.replace(FENCE_RE, (m) => '\n'.repeat((m.match(/\n/g) ?? []).length));
|
|
23
58
|
}
|
|
24
|
-
|
|
25
|
-
|
|
59
|
+
/**
|
|
60
|
+
* The `State:` token in the header region, with its line — one scan, shared by
|
|
61
|
+
* the done-item test and the placement check so the two cannot disagree about
|
|
62
|
+
* what a document says it is.
|
|
63
|
+
*/
|
|
64
|
+
function findState(text, vocabulary) {
|
|
65
|
+
const known = stateMatcher(vocabulary);
|
|
66
|
+
const canonical = (m) => vocabulary.find((s) => s.toLowerCase().replace(/’/g, "'") === m.toLowerCase().replace(/’/g, "'")) ?? m;
|
|
67
|
+
const lines = stripFencedCode(text).split('\n');
|
|
68
|
+
// The preamble **and the first section**. Stopping at the first `##` — as this
|
|
69
|
+
// did — meant the check never ran on a real document in the corpus it was
|
|
70
|
+
// written for: the house template is `# Title` / `## Status` / `- **State:** X`,
|
|
71
|
+
// so every single `State:` line sat one heading past where it looked, and the
|
|
72
|
+
// whole placement half reported green having examined nothing (bug 0119).
|
|
73
|
+
let seenHeading = 0;
|
|
74
|
+
for (let i = 0; i < lines.length; i++) {
|
|
75
|
+
if (/^##\s/.test(lines[i] ?? '')) {
|
|
76
|
+
seenHeading += 1;
|
|
77
|
+
if (seenHeading > 1)
|
|
78
|
+
break;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const line = lines[i] ?? '';
|
|
82
|
+
const hit = known.exec(line);
|
|
83
|
+
if (hit?.[1] !== undefined)
|
|
84
|
+
return { state: canonical(hit[1]), raw: hit[1], line: i + 1 };
|
|
85
|
+
const unreadable = UNREADABLE_RE.exec(line);
|
|
86
|
+
if (unreadable?.[1] !== undefined) {
|
|
87
|
+
const raw = unreadable[1];
|
|
88
|
+
return { raw: raw.length > ELIDE ? `${raw.slice(0, ELIDE)}…` : raw, line: i + 1 };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
26
92
|
}
|
|
27
|
-
function isDoneItem(doc, doneFolders) {
|
|
93
|
+
function isDoneItem(doc, doneFolders, terminalStates) {
|
|
28
94
|
if (doneFolders.some((seg) => `/${doc.relPath}`.includes(seg)))
|
|
29
95
|
return true;
|
|
30
|
-
|
|
96
|
+
const found = findState(doc.text, terminalStates);
|
|
97
|
+
return found?.state !== undefined && terminalStates.includes(found.state);
|
|
31
98
|
}
|
|
32
99
|
const v = (rule, doc, line, message, because) => ({
|
|
33
100
|
rule,
|
|
@@ -37,29 +104,28 @@ const v = (rule, doc, line, message, because) => ({
|
|
|
37
104
|
message,
|
|
38
105
|
because,
|
|
39
106
|
});
|
|
40
|
-
/**
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
107
|
+
/**
|
|
108
|
+
* What the header's `State:` line establishes — an unreadable token first, then
|
|
109
|
+
* state↔folder coherence. The order matters: a token the vocabulary does not
|
|
110
|
+
* contain cannot be classified as terminal or not, so reporting it is the only
|
|
111
|
+
* honest answer. Returning `null` there is what made this check silently
|
|
112
|
+
* self-disabling (bug 0118).
|
|
113
|
+
*/
|
|
114
|
+
function headerStateViolation(doc, inDoneFolder, closeInPlace, states, terminalStates) {
|
|
115
|
+
const known = [...new Set([...states, ...terminalStates])];
|
|
116
|
+
const found = findState(doc.text, known);
|
|
117
|
+
if (!found)
|
|
118
|
+
return null; // no State line at all → this document is not an item
|
|
119
|
+
if (found.state === undefined) {
|
|
120
|
+
return v('ledger/unknown-state', doc, found.line, `State: ${found.raw} is not a state this corpus declares — expected one of ${known.join(', ')}.` +
|
|
121
|
+
` An unreadable state cannot be checked against its folder, so it is reported rather than skipped.`, 'a state nobody can read is a check that silently stops running');
|
|
54
122
|
}
|
|
55
|
-
|
|
56
|
-
return null; // no neutral State token → nothing to check
|
|
57
|
-
const terminal = TERMINAL_STATES.has(state);
|
|
123
|
+
const terminal = terminalStates.includes(found.state);
|
|
58
124
|
if (inDoneFolder && !terminal) {
|
|
59
|
-
return v('ledger/state-folder-mismatch', doc,
|
|
125
|
+
return v('ledger/state-folder-mismatch', doc, found.line, `State: ${found.state} but filed in a done-folder — move it back to the active lane or close it out.`, 'a done-folder item marked as not-done is a silent placement corruption');
|
|
60
126
|
}
|
|
61
127
|
if (!inDoneFolder && terminal && !closeInPlace) {
|
|
62
|
-
return v('ledger/state-folder-mismatch', doc,
|
|
128
|
+
return v('ledger/state-folder-mismatch', doc, found.line, `State: ${found.state} but not in a done-folder — the move-to-done was never made (orphaned close).`, 'a done item left in an active lane is an orphaned post-merge move');
|
|
63
129
|
}
|
|
64
130
|
return null;
|
|
65
131
|
}
|
|
@@ -102,18 +168,58 @@ export function honestyAtClose(corpus, options = {}) {
|
|
|
102
168
|
const doneFolders = options.doneFolders ?? DEFAULT_DONE_FOLDERS;
|
|
103
169
|
const boardFiles = new Set(options.boardFiles ?? DEFAULT_BOARD_FILES);
|
|
104
170
|
const closeInPlace = options.closeInPlace ?? false;
|
|
171
|
+
const states = options.states ?? DEFAULT_STATES;
|
|
172
|
+
const terminalStates = options.terminalStates ?? DEFAULT_TERMINAL_STATES;
|
|
105
173
|
const violations = [];
|
|
106
174
|
for (const doc of corpus.documents()) {
|
|
107
175
|
const base = doc.relPath.split('/').pop() ?? doc.relPath;
|
|
108
176
|
if (boardFiles.has(base))
|
|
109
177
|
continue;
|
|
110
178
|
const inDoneFolder = doneFolders.some((seg) => `/${doc.relPath}`.includes(seg));
|
|
111
|
-
const
|
|
112
|
-
if (
|
|
113
|
-
violations.push(
|
|
114
|
-
if (isDoneItem(doc, doneFolders))
|
|
179
|
+
const header = headerStateViolation(doc, inDoneFolder, closeInPlace, states, terminalStates);
|
|
180
|
+
if (header)
|
|
181
|
+
violations.push(header);
|
|
182
|
+
if (isDoneItem(doc, doneFolders, terminalStates))
|
|
115
183
|
violations.push(...ledgerViolations(doc));
|
|
116
184
|
}
|
|
117
185
|
return finishPreset(violations, options);
|
|
118
186
|
}
|
|
187
|
+
/**
|
|
188
|
+
* The denominator, computed by the preset itself.
|
|
189
|
+
*
|
|
190
|
+
* `withReadableState` is the number nobody could see when bug 0119 happened: the
|
|
191
|
+
* placement check had never examined a document, and every summary line in the
|
|
192
|
+
* repo reported a healthy done-count derived purely from folder membership. A
|
|
193
|
+
* caller that prints this cannot be blind and green at the same time — if the
|
|
194
|
+
* region assumption drifts from the corpus again, this drops and says so.
|
|
195
|
+
*
|
|
196
|
+
* Callers must not re-derive it. `check-ledger.mjs` did, with a copy of the very
|
|
197
|
+
* expression 0119 removed, and its copy disagreed with the preset on 56 of 56
|
|
198
|
+
* records while heading a section captioned "so a green is provably non-vacuous".
|
|
199
|
+
*/
|
|
200
|
+
export function ledgerStats(corpus, options = {}) {
|
|
201
|
+
const doneFolders = options.doneFolders ?? DEFAULT_DONE_FOLDERS;
|
|
202
|
+
const boardFiles = new Set(options.boardFiles ?? DEFAULT_BOARD_FILES);
|
|
203
|
+
const states = options.states ?? DEFAULT_STATES;
|
|
204
|
+
const terminalStates = options.terminalStates ?? DEFAULT_TERMINAL_STATES;
|
|
205
|
+
const known = [...new Set([...states, ...terminalStates])];
|
|
206
|
+
let scanned = 0;
|
|
207
|
+
let withReadableState = 0;
|
|
208
|
+
let unreadableState = 0;
|
|
209
|
+
let doneItems = 0;
|
|
210
|
+
for (const doc of corpus.documents()) {
|
|
211
|
+
const base = doc.relPath.split('/').pop() ?? doc.relPath;
|
|
212
|
+
if (boardFiles.has(base))
|
|
213
|
+
continue;
|
|
214
|
+
scanned += 1;
|
|
215
|
+
const found = findState(doc.text, known);
|
|
216
|
+
if (found?.state !== undefined)
|
|
217
|
+
withReadableState += 1;
|
|
218
|
+
else if (found !== null)
|
|
219
|
+
unreadableState += 1;
|
|
220
|
+
if (isDoneItem(doc, doneFolders, terminalStates))
|
|
221
|
+
doneItems += 1;
|
|
222
|
+
}
|
|
223
|
+
return { scanned, withReadableState, unreadableState, doneItems };
|
|
224
|
+
}
|
|
119
225
|
//# sourceMappingURL=ledger.js.map
|
package/dist/rules/ledger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ledger.js","sourceRoot":"","sources":["../../src/rules/ledger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA4B,MAAM,kBAAkB,CAAA;AAIzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"ledger.js","sourceRoot":"","sources":["../../src/rules/ledger.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nielspeter/eess-md",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Architecture testing for a Markdown corpus — the Markdown dialect of the eess family. Links resolve, code pointers ground, ADRs declare enforcement.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"eess"
|
|
49
49
|
],
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@nielspeter/eess": "^0.2.
|
|
51
|
+
"@nielspeter/eess": "^0.2.2",
|
|
52
52
|
"mdast-util-from-markdown": "^2.0.3",
|
|
53
53
|
"mdast-util-gfm": "^3.1.0",
|
|
54
54
|
"micromark-extension-gfm": "^3.0.0",
|