@nielspeter/eess-md 0.1.2 → 0.3.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/conditions/resolve.d.ts +20 -1
- package/dist/conditions/resolve.d.ts.map +1 -1
- package/dist/conditions/resolve.js +63 -2
- package/dist/conditions/resolve.js.map +1 -1
- package/dist/rules/ledger.d.ts +38 -0
- package/dist/rules/ledger.d.ts.map +1 -1
- package/dist/rules/ledger.js +151 -32
- package/dist/rules/ledger.js.map +1 -1
- package/package.json +2 -2
|
@@ -25,12 +25,31 @@ export interface LinkResolveOptions {
|
|
|
25
25
|
* resolution is still tried first, so plain repo-absolute links keep working.
|
|
26
26
|
*/
|
|
27
27
|
readonly rootDir?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Resolve a link naming a real directory (`./fixed/` or `./fixed`, with or
|
|
30
|
+
* without the trailing slash — both forms occur in this repo's own corpus)
|
|
31
|
+
* even when it has no index file. Correct for a repo-hosted corpus (GitHub,
|
|
32
|
+
* GitLab render a directory link as its listing); wrong for a static-site
|
|
33
|
+
* corpus where a bare directory is not itself a page — there, reach for
|
|
34
|
+
* {@link tryIndex} instead. Off by default: this widens what "resolves"
|
|
35
|
+
* means, and a link resolving that shouldn't is a false green, not a
|
|
36
|
+
* convenience. Default `false`.
|
|
37
|
+
*
|
|
38
|
+
* A link naming a real directory always wins over an unrelated typo — if
|
|
39
|
+
* `./foo` was meant as a deleted `foo.md` but a directory `foo/` happens to
|
|
40
|
+
* exist at that path, it resolves as the directory. Not a new failure mode:
|
|
41
|
+
* GitHub renders that link as the directory listing too, so this only
|
|
42
|
+
* closes the gap between the gate and what the link actually does when
|
|
43
|
+
* followed, it doesn't introduce a new way to be surprised by it.
|
|
44
|
+
*/
|
|
45
|
+
readonly resolveDirectories?: boolean;
|
|
28
46
|
}
|
|
29
47
|
/**
|
|
30
48
|
* Condition: every (internal) link resolves to a file in the corpus's repo tree.
|
|
31
49
|
* Closes over the `Corpus` for the file index. External links and pure anchors
|
|
32
50
|
* are skipped. `options` adds extensionless-link resolution (`tryExtensions`,
|
|
33
|
-
* `tryIndex`) for static-site corpora
|
|
51
|
+
* `tryIndex`) for static-site corpora, and directory resolution
|
|
52
|
+
* (`resolveDirectories`) for repo-hosted ones.
|
|
34
53
|
*/
|
|
35
54
|
export declare function linkResolves(corpus: Corpus, options?: LinkResolveOptions): Condition<MdLink>;
|
|
36
55
|
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/conditions/resolve.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAW,MAAM,kBAAkB,CAAA;AAC1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAG/C;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1C;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/conditions/resolve.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAW,MAAM,kBAAkB,CAAA;AAC1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAG/C;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1C;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAA;CACtC;AA8DD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,SAAS,CAAC,MAAM,CAAC,CAyEhG"}
|
|
@@ -32,11 +32,38 @@ function candidates(target, options) {
|
|
|
32
32
|
}
|
|
33
33
|
return out;
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Every known directory reachable from `fileIndex`'s files, derived from it
|
|
37
|
+
* rather than new I/O: each indexed file's ancestors are known directories.
|
|
38
|
+
* `fileIndex` itself spans the whole physical repo walk from `cwd`, not just
|
|
39
|
+
* the corpus's configured `roots` (`roots` only filters which files become
|
|
40
|
+
* *documents* — see `corpus()`), so a directory link can resolve against
|
|
41
|
+
* something outside any configured root. Built only when `resolveDirectories`
|
|
42
|
+
* is on — the cost of a directory-shaped link resolving is opt-in, so is the
|
|
43
|
+
* cost of computing it.
|
|
44
|
+
*
|
|
45
|
+
* The repo root itself (`.`) is deliberately excluded — `[root](/)` still
|
|
46
|
+
* won't resolve even with the option on. Nobody links "the whole repo," and
|
|
47
|
+
* `resolveTargets` never had a resolvable shape for it before this option
|
|
48
|
+
* existed either.
|
|
49
|
+
*/
|
|
50
|
+
function directoryIndex(corpus) {
|
|
51
|
+
const dirs = new Set();
|
|
52
|
+
for (const rel of corpus.fileIndex) {
|
|
53
|
+
let dir = posix.dirname(rel);
|
|
54
|
+
while (dir !== '.' && dir !== '/' && !dirs.has(dir)) {
|
|
55
|
+
dirs.add(dir);
|
|
56
|
+
dir = posix.dirname(dir);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return dirs;
|
|
60
|
+
}
|
|
35
61
|
/**
|
|
36
62
|
* Condition: every (internal) link resolves to a file in the corpus's repo tree.
|
|
37
63
|
* Closes over the `Corpus` for the file index. External links and pure anchors
|
|
38
64
|
* are skipped. `options` adds extensionless-link resolution (`tryExtensions`,
|
|
39
|
-
* `tryIndex`) for static-site corpora
|
|
65
|
+
* `tryIndex`) for static-site corpora, and directory resolution
|
|
66
|
+
* (`resolveDirectories`) for repo-hosted ones.
|
|
40
67
|
*/
|
|
41
68
|
export function linkResolves(corpus, options = {}) {
|
|
42
69
|
// Basename → repo files, for finding a uniquely-moved target of a broken link.
|
|
@@ -49,6 +76,33 @@ export function linkResolves(corpus, options = {}) {
|
|
|
49
76
|
else
|
|
50
77
|
byBasename.set(base, [rel]);
|
|
51
78
|
}
|
|
79
|
+
const dirIndex = options.resolveDirectories === true ? directoryIndex(corpus) : undefined;
|
|
80
|
+
// Bug 0137: a link that names a real directory and one that names nothing
|
|
81
|
+
// at all both reported the identical "does not resolve" message — no hint
|
|
82
|
+
// that `resolveDirectories` exists, or that this specific target would
|
|
83
|
+
// resolve with it on. Built lazily (at most once, memoized) rather than
|
|
84
|
+
// unconditionally alongside `dirIndex`, so the happy path (no violations)
|
|
85
|
+
// never pays for it, and only when `resolveDirectories` is already off —
|
|
86
|
+
// when it's on, a real directory already resolved above and can't reach
|
|
87
|
+
// this branch at all.
|
|
88
|
+
//
|
|
89
|
+
// A site-absolute link with `rootDir` set yields two candidates
|
|
90
|
+
// (repo-root, then content-root — see `resolveTargets`), and either can
|
|
91
|
+
// independently be a real directory. Reporting whichever comes first
|
|
92
|
+
// unlabelled can name the *wrong* one: a repo-root directory that happens
|
|
93
|
+
// to share a name with the intended content-root page sends the author to
|
|
94
|
+
// toggle `resolveDirectories`, which would resolve the unrelated
|
|
95
|
+
// repo-root directory, not fix their actual (still-missing) page. Labelled
|
|
96
|
+
// only when there are two candidates to disambiguate between — the common,
|
|
97
|
+
// single-target case (no `rootDir`) is unaffected.
|
|
98
|
+
let diagnosticDirIndex;
|
|
99
|
+
const directoryHint = (target, label) => {
|
|
100
|
+
diagnosticDirIndex ??= directoryIndex(corpus);
|
|
101
|
+
const bare = target.replace(/\/+$/, '');
|
|
102
|
+
return diagnosticDirIndex.has(bare)
|
|
103
|
+
? ` — "${bare}"${label} is a real directory; this check runs with resolveDirectories off`
|
|
104
|
+
: '';
|
|
105
|
+
};
|
|
52
106
|
return {
|
|
53
107
|
description: 'resolve to an existing file',
|
|
54
108
|
evaluate: (links, ctx) => links.flatMap((link) => {
|
|
@@ -59,12 +113,19 @@ export function linkResolves(corpus, options = {}) {
|
|
|
59
113
|
return [];
|
|
60
114
|
if (targets.some((t) => candidates(t, options).some((c) => corpus.fileIndex.has(c))))
|
|
61
115
|
return [];
|
|
116
|
+
if (dirIndex !== undefined && targets.some((t) => dirIndex.has(t.replace(/\/+$/, ''))))
|
|
117
|
+
return [];
|
|
118
|
+
const hint = options.resolveDirectories === true
|
|
119
|
+
? ''
|
|
120
|
+
: (targets
|
|
121
|
+
.map((t, i) => directoryHint(t, targets.length > 1 ? (i === 0 ? ' (repo-root)' : ' (content-root)') : ''))
|
|
122
|
+
.find((h) => h) ?? '');
|
|
62
123
|
return [
|
|
63
124
|
mdViolation({
|
|
64
125
|
element: `${link.doc.relPath} → ${link.url}`,
|
|
65
126
|
file: link.doc.file,
|
|
66
127
|
line: link.line,
|
|
67
|
-
message: `broken link: "${link.url}" does not resolve to a file in the repo`,
|
|
128
|
+
message: `broken link: "${link.url}" does not resolve to a file in the repo${hint}`,
|
|
68
129
|
sourceText: link.doc.text,
|
|
69
130
|
fix: movedLinkFix(link, byBasename),
|
|
70
131
|
context: ctx,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/conditions/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAA;AAIjC,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/conditions/resolve.ts"],"names":[],"mappings":"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"}
|
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;AAgPD;;;;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,59 @@ 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
|
+
* An empty `states` must never match — a lane with no known/terminal
|
|
33
|
+
* vocabulary (`terminalStates: []`, a legitimate config: bug 0121's
|
|
34
|
+
* `proposals` lane, where nothing is ledger-closed by design) is a real,
|
|
35
|
+
* supported input, not a caller error. Naively joining zero alternatives
|
|
36
|
+
* makes the capture group `()`, a zero-width match that fires at almost any
|
|
37
|
+
* position — `findState` would then read every `State:`-shaped line as
|
|
38
|
+
* "readable, value ''" instead of falling through to the `UNREADABLE_RE`
|
|
39
|
+
* fallback, silently miscounting `withReadableState`/`unreadableState` and
|
|
40
|
+
* (for `isDoneItem`, which calls this with `terminalStates` directly) relying
|
|
41
|
+
* on `[].includes('')` being `false` by accident rather than by design.
|
|
42
|
+
*/
|
|
43
|
+
function stateMatcher(states) {
|
|
44
|
+
if (states.length === 0)
|
|
45
|
+
return /(?!)/; // never matches: forces the UNREADABLE_RE fallback
|
|
46
|
+
const alts = [...states]
|
|
47
|
+
.sort((a, b) => b.length - a.length)
|
|
48
|
+
.map((s) => escapeRe(s).replace(/['’]/g, "['’]"))
|
|
49
|
+
.join('|');
|
|
50
|
+
return new RegExp(`${LABEL}${WRAP}(${alts})(?![\\w'’-])`, 'i');
|
|
51
|
+
}
|
|
52
|
+
// Fallback: the line IS a state declaration, but its value is not in the
|
|
53
|
+
// vocabulary. Used only to name the offending value in the message — so it
|
|
54
|
+
// captures up to the house `—` separator rather than one whitespace-delimited
|
|
55
|
+
// token, or a multi-word state would be reported by its first word alone.
|
|
56
|
+
const UNREADABLE_RE = new RegExp(`${LABEL}(\\S[^—–]*?)\\s*(?:[—–].*)?$`, 'i');
|
|
57
|
+
const ELIDE = 32;
|
|
10
58
|
// Any one of these on a box's line marks it *disposed* (not silent). Tokens are
|
|
11
59
|
// the canonical hyphenated enum, word-bounded — so prose like "…the connection
|
|
12
60
|
// dropped in prod" does not falsely exempt a silent box. `deferred` must name a
|
|
@@ -21,13 +69,45 @@ const FENCE_RE = /(```|~~~)[\s\S]*?\1/g;
|
|
|
21
69
|
function stripFencedCode(s) {
|
|
22
70
|
return s.replace(FENCE_RE, (m) => '\n'.repeat((m.match(/\n/g) ?? []).length));
|
|
23
71
|
}
|
|
24
|
-
|
|
25
|
-
|
|
72
|
+
/**
|
|
73
|
+
* The `State:` token in the header region, with its line — one scan, shared by
|
|
74
|
+
* the done-item test and the placement check so the two cannot disagree about
|
|
75
|
+
* what a document says it is.
|
|
76
|
+
*/
|
|
77
|
+
function findState(text, vocabulary) {
|
|
78
|
+
const known = stateMatcher(vocabulary);
|
|
79
|
+
const canonical = (m) => vocabulary.find((s) => s.toLowerCase().replace(/’/g, "'") === m.toLowerCase().replace(/’/g, "'")) ?? m;
|
|
80
|
+
const lines = stripFencedCode(text).split('\n');
|
|
81
|
+
// The preamble **and the first section**. Stopping at the first `##` — as this
|
|
82
|
+
// did — meant the check never ran on a real document in the corpus it was
|
|
83
|
+
// written for: the house template is `# Title` / `## Status` / `- **State:** X`,
|
|
84
|
+
// so every single `State:` line sat one heading past where it looked, and the
|
|
85
|
+
// whole placement half reported green having examined nothing (bug 0119).
|
|
86
|
+
let seenHeading = 0;
|
|
87
|
+
for (let i = 0; i < lines.length; i++) {
|
|
88
|
+
if (/^##\s/.test(lines[i] ?? '')) {
|
|
89
|
+
seenHeading += 1;
|
|
90
|
+
if (seenHeading > 1)
|
|
91
|
+
break;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const line = lines[i] ?? '';
|
|
95
|
+
const hit = known.exec(line);
|
|
96
|
+
if (hit?.[1] !== undefined)
|
|
97
|
+
return { state: canonical(hit[1]), raw: hit[1], line: i + 1 };
|
|
98
|
+
const unreadable = UNREADABLE_RE.exec(line);
|
|
99
|
+
if (unreadable?.[1] !== undefined) {
|
|
100
|
+
const raw = unreadable[1];
|
|
101
|
+
return { raw: raw.length > ELIDE ? `${raw.slice(0, ELIDE)}…` : raw, line: i + 1 };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
26
105
|
}
|
|
27
|
-
function isDoneItem(doc, doneFolders) {
|
|
106
|
+
function isDoneItem(doc, doneFolders, terminalStates) {
|
|
28
107
|
if (doneFolders.some((seg) => `/${doc.relPath}`.includes(seg)))
|
|
29
108
|
return true;
|
|
30
|
-
|
|
109
|
+
const found = findState(doc.text, terminalStates);
|
|
110
|
+
return found?.state !== undefined && terminalStates.includes(found.state);
|
|
31
111
|
}
|
|
32
112
|
const v = (rule, doc, line, message, because) => ({
|
|
33
113
|
rule,
|
|
@@ -37,29 +117,28 @@ const v = (rule, doc, line, message, because) => ({
|
|
|
37
117
|
message,
|
|
38
118
|
because,
|
|
39
119
|
});
|
|
40
|
-
/**
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
120
|
+
/**
|
|
121
|
+
* What the header's `State:` line establishes — an unreadable token first, then
|
|
122
|
+
* state↔folder coherence. The order matters: a token the vocabulary does not
|
|
123
|
+
* contain cannot be classified as terminal or not, so reporting it is the only
|
|
124
|
+
* honest answer. Returning `null` there is what made this check silently
|
|
125
|
+
* self-disabling (bug 0118).
|
|
126
|
+
*/
|
|
127
|
+
function headerStateViolation(doc, inDoneFolder, closeInPlace, states, terminalStates) {
|
|
128
|
+
const known = [...new Set([...states, ...terminalStates])];
|
|
129
|
+
const found = findState(doc.text, known);
|
|
130
|
+
if (!found)
|
|
131
|
+
return null; // no State line at all → this document is not an item
|
|
132
|
+
if (found.state === undefined) {
|
|
133
|
+
return v('ledger/unknown-state', doc, found.line, `State: ${found.raw} is not a state this corpus declares — expected one of ${known.join(', ')}.` +
|
|
134
|
+
` 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
135
|
}
|
|
55
|
-
|
|
56
|
-
return null; // no neutral State token → nothing to check
|
|
57
|
-
const terminal = TERMINAL_STATES.has(state);
|
|
136
|
+
const terminal = terminalStates.includes(found.state);
|
|
58
137
|
if (inDoneFolder && !terminal) {
|
|
59
|
-
return v('ledger/state-folder-mismatch', doc,
|
|
138
|
+
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
139
|
}
|
|
61
140
|
if (!inDoneFolder && terminal && !closeInPlace) {
|
|
62
|
-
return v('ledger/state-folder-mismatch', doc,
|
|
141
|
+
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
142
|
}
|
|
64
143
|
return null;
|
|
65
144
|
}
|
|
@@ -102,18 +181,58 @@ export function honestyAtClose(corpus, options = {}) {
|
|
|
102
181
|
const doneFolders = options.doneFolders ?? DEFAULT_DONE_FOLDERS;
|
|
103
182
|
const boardFiles = new Set(options.boardFiles ?? DEFAULT_BOARD_FILES);
|
|
104
183
|
const closeInPlace = options.closeInPlace ?? false;
|
|
184
|
+
const states = options.states ?? DEFAULT_STATES;
|
|
185
|
+
const terminalStates = options.terminalStates ?? DEFAULT_TERMINAL_STATES;
|
|
105
186
|
const violations = [];
|
|
106
187
|
for (const doc of corpus.documents()) {
|
|
107
188
|
const base = doc.relPath.split('/').pop() ?? doc.relPath;
|
|
108
189
|
if (boardFiles.has(base))
|
|
109
190
|
continue;
|
|
110
191
|
const inDoneFolder = doneFolders.some((seg) => `/${doc.relPath}`.includes(seg));
|
|
111
|
-
const
|
|
112
|
-
if (
|
|
113
|
-
violations.push(
|
|
114
|
-
if (isDoneItem(doc, doneFolders))
|
|
192
|
+
const header = headerStateViolation(doc, inDoneFolder, closeInPlace, states, terminalStates);
|
|
193
|
+
if (header)
|
|
194
|
+
violations.push(header);
|
|
195
|
+
if (isDoneItem(doc, doneFolders, terminalStates))
|
|
115
196
|
violations.push(...ledgerViolations(doc));
|
|
116
197
|
}
|
|
117
198
|
return finishPreset(violations, options);
|
|
118
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* The denominator, computed by the preset itself.
|
|
202
|
+
*
|
|
203
|
+
* `withReadableState` is the number nobody could see when bug 0119 happened: the
|
|
204
|
+
* placement check had never examined a document, and every summary line in the
|
|
205
|
+
* repo reported a healthy done-count derived purely from folder membership. A
|
|
206
|
+
* caller that prints this cannot be blind and green at the same time — if the
|
|
207
|
+
* region assumption drifts from the corpus again, this drops and says so.
|
|
208
|
+
*
|
|
209
|
+
* Callers must not re-derive it. `check-ledger.mjs` did, with a copy of the very
|
|
210
|
+
* expression 0119 removed, and its copy disagreed with the preset on 56 of 56
|
|
211
|
+
* records while heading a section captioned "so a green is provably non-vacuous".
|
|
212
|
+
*/
|
|
213
|
+
export function ledgerStats(corpus, options = {}) {
|
|
214
|
+
const doneFolders = options.doneFolders ?? DEFAULT_DONE_FOLDERS;
|
|
215
|
+
const boardFiles = new Set(options.boardFiles ?? DEFAULT_BOARD_FILES);
|
|
216
|
+
const states = options.states ?? DEFAULT_STATES;
|
|
217
|
+
const terminalStates = options.terminalStates ?? DEFAULT_TERMINAL_STATES;
|
|
218
|
+
const known = [...new Set([...states, ...terminalStates])];
|
|
219
|
+
let scanned = 0;
|
|
220
|
+
let withReadableState = 0;
|
|
221
|
+
let unreadableState = 0;
|
|
222
|
+
let doneItems = 0;
|
|
223
|
+
for (const doc of corpus.documents()) {
|
|
224
|
+
const base = doc.relPath.split('/').pop() ?? doc.relPath;
|
|
225
|
+
if (boardFiles.has(base))
|
|
226
|
+
continue;
|
|
227
|
+
scanned += 1;
|
|
228
|
+
const found = findState(doc.text, known);
|
|
229
|
+
if (found?.state !== undefined)
|
|
230
|
+
withReadableState += 1;
|
|
231
|
+
else if (found !== null)
|
|
232
|
+
unreadableState += 1;
|
|
233
|
+
if (isDoneItem(doc, doneFolders, terminalStates))
|
|
234
|
+
doneItems += 1;
|
|
235
|
+
}
|
|
236
|
+
return { scanned, withReadableState, unreadableState, doneItems };
|
|
237
|
+
}
|
|
119
238
|
//# 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.3.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",
|