@nielspeter/eess-md 0.8.0 → 0.9.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.
Files changed (66) hide show
  1. package/README.md +3 -1
  2. package/dist/builders/declaration-findings.d.ts +37 -0
  3. package/dist/builders/declaration-findings.d.ts.map +1 -0
  4. package/dist/builders/declaration-findings.js +128 -0
  5. package/dist/builders/declaration-findings.js.map +1 -0
  6. package/dist/builders/links.d.ts +60 -1
  7. package/dist/builders/links.d.ts.map +1 -1
  8. package/dist/builders/links.js +92 -1
  9. package/dist/builders/links.js.map +1 -1
  10. package/dist/conditions/linked-back.d.ts +17 -0
  11. package/dist/conditions/linked-back.d.ts.map +1 -0
  12. package/dist/conditions/linked-back.js +122 -0
  13. package/dist/conditions/linked-back.js.map +1 -0
  14. package/dist/conditions/resolve.d.ts +8 -40
  15. package/dist/conditions/resolve.d.ts.map +1 -1
  16. package/dist/conditions/resolve.js +26 -138
  17. package/dist/conditions/resolve.js.map +1 -1
  18. package/dist/corpus.d.ts +3 -0
  19. package/dist/corpus.d.ts.map +1 -1
  20. package/dist/corpus.js +7 -10
  21. package/dist/corpus.js.map +1 -1
  22. package/dist/index.d.ts +4 -1
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +4 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/model/document.d.ts +8 -1
  27. package/dist/model/document.d.ts.map +1 -1
  28. package/dist/model/document.js +14 -3
  29. package/dist/model/document.js.map +1 -1
  30. package/dist/model/label.d.ts +35 -0
  31. package/dist/model/label.d.ts.map +1 -0
  32. package/dist/model/label.js +68 -0
  33. package/dist/model/label.js.map +1 -0
  34. package/dist/model/links.d.ts +43 -0
  35. package/dist/model/links.d.ts.map +1 -1
  36. package/dist/model/links.js +112 -11
  37. package/dist/model/links.js.map +1 -1
  38. package/dist/model/prose.d.ts +11 -0
  39. package/dist/model/prose.d.ts.map +1 -1
  40. package/dist/model/prose.js +50 -5
  41. package/dist/model/prose.js.map +1 -1
  42. package/dist/model/query.d.ts +7 -0
  43. package/dist/model/query.d.ts.map +1 -1
  44. package/dist/model/query.js +10 -3
  45. package/dist/model/query.js.map +1 -1
  46. package/dist/model/resolve-link.d.ts +142 -0
  47. package/dist/model/resolve-link.d.ts.map +1 -0
  48. package/dist/model/resolve-link.js +194 -0
  49. package/dist/model/resolve-link.js.map +1 -0
  50. package/dist/predicates/declared-block.d.ts +29 -0
  51. package/dist/predicates/declared-block.d.ts.map +1 -0
  52. package/dist/predicates/declared-block.js +47 -0
  53. package/dist/predicates/declared-block.js.map +1 -0
  54. package/dist/predicates/live-target.d.ts +12 -0
  55. package/dist/predicates/live-target.d.ts.map +1 -0
  56. package/dist/predicates/live-target.js +17 -0
  57. package/dist/predicates/live-target.js.map +1 -0
  58. package/dist/rules/adr.d.ts +14 -5
  59. package/dist/rules/adr.d.ts.map +1 -1
  60. package/dist/rules/adr.js +5 -27
  61. package/dist/rules/adr.js.map +1 -1
  62. package/dist/rules/ledger.d.ts +10 -6
  63. package/dist/rules/ledger.d.ts.map +1 -1
  64. package/dist/rules/ledger.js +80 -24
  65. package/dist/rules/ledger.js.map +1 -1
  66. package/package.json +6 -3
@@ -0,0 +1,194 @@
1
+ import { posix } from 'node:path';
2
+ const matchersOf = new WeakMap();
3
+ /**
4
+ * Record how `corpus()` filtered its files. Called by `corpus()` only; a
5
+ * `Corpus` built any other way has no matchers, and an unloaded `.md` file in
6
+ * it is reported as `outside-roots`.
7
+ */
8
+ export function registerCorpusMatchers(corpus, matchers) {
9
+ matchersOf.set(corpus, matchers);
10
+ }
11
+ const indexesOf = new WeakMap();
12
+ /**
13
+ * The two corpus-wide indexes resolution needs, built once per corpus. Before
14
+ * plan 0404 the directory index was rebuilt by every `resolve()` condition;
15
+ * called per link from a custom rule it would be rebuilt per link.
16
+ *
17
+ * The directory index is derived from `fileIndex` rather than new I/O: each
18
+ * indexed file's ancestors are known directories. `fileIndex` spans the whole
19
+ * physical repo walk from `cwd`, not just the configured `roots`, so a
20
+ * directory link can resolve against something outside any root. The repo
21
+ * root itself (`.`) is deliberately excluded — nobody links "the whole repo".
22
+ */
23
+ function indexes(corpus) {
24
+ const cached = indexesOf.get(corpus);
25
+ if (cached !== undefined)
26
+ return cached;
27
+ const directories = new Set();
28
+ for (const rel of corpus.fileIndex) {
29
+ let dir = posix.dirname(rel);
30
+ while (dir !== '.' && dir !== '/' && !directories.has(dir)) {
31
+ directories.add(dir);
32
+ dir = posix.dirname(dir);
33
+ }
34
+ }
35
+ const documents = new Map();
36
+ for (const doc of corpus.documents())
37
+ documents.set(doc.relPath, doc);
38
+ const built = { directories, documents };
39
+ indexesOf.set(corpus, built);
40
+ return built;
41
+ }
42
+ /**
43
+ * A link URL's base repo-relative target(s), or `[]` for a pure fragment.
44
+ * Site-absolute links (leading `/`) yield the repo-root target, then the
45
+ * content-root target when `rootDir` is set. Throws `URIError` on malformed
46
+ * percent-encoding; `resolveLink` turns that into `missing`.
47
+ *
48
+ * Exported for `linkResolves`, which labels the two site-absolute candidates
49
+ * in its directory hint (bug 0137); not part of the package's public API.
50
+ */
51
+ export function linkTargets(link, options) {
52
+ const withoutFragment = link.url.split('#')[0] ?? '';
53
+ if (withoutFragment === '')
54
+ return [];
55
+ const decoded = decodeURIComponent(withoutFragment);
56
+ if (decoded.startsWith('/')) {
57
+ const repoRooted = posix.normalize(decoded.replace(/^\/+/, ''));
58
+ return options.rootDir !== undefined
59
+ ? [repoRooted, posix.normalize(posix.join(options.rootDir, repoRooted))]
60
+ : [repoRooted];
61
+ }
62
+ const base = posix.dirname(link.doc.relPath);
63
+ return [posix.normalize(posix.join(base, decoded))];
64
+ }
65
+ /** Every repo-relative file candidate for one target, in the order they are tried. */
66
+ function candidates(target, options) {
67
+ const out = [target];
68
+ const bare = target.replace(/\/+$/, '');
69
+ for (const ext of options.tryExtensions ?? []) {
70
+ out.push(bare + ext);
71
+ }
72
+ if (options.tryIndex !== undefined) {
73
+ out.push(posix.join(bare, options.tryIndex));
74
+ }
75
+ return out;
76
+ }
77
+ function fileTarget(path, link, corpus) {
78
+ if (path === link.doc.relPath)
79
+ return { kind: 'self' };
80
+ const doc = indexes(corpus).documents.get(path);
81
+ if (doc !== undefined)
82
+ return { kind: 'document', path, doc };
83
+ const matchers = matchersOf.get(corpus);
84
+ const reasons = [];
85
+ if (!path.endsWith('.md'))
86
+ reasons.push('not-markdown');
87
+ if (matchers?.ignored(path) === true)
88
+ reasons.push('ignored');
89
+ if (matchers === undefined || !matchers.inRoots(path))
90
+ reasons.push('outside-roots');
91
+ // A loaded `corpus()` reads exactly the `.md` files in its roots that it does
92
+ // not ignore, so one of the three always applies. Should a hand-built
93
+ // `Corpus` disagree, `outside-roots` is the reason that names a remedy.
94
+ if (reasons.length === 0)
95
+ reasons.push('outside-roots');
96
+ return { kind: 'not-in-corpus', path, reasons };
97
+ }
98
+ /**
99
+ * Resolve a link to the one case it is (plan 0404). Total: it never throws.
100
+ *
101
+ * Candidates are tried in a fixed order — each target (repo-root, then
102
+ * content-root when `rootDir` is set), and within it the URL as written, then
103
+ * `tryExtensions`, then `tryIndex`. The first existing **file** wins. Only when
104
+ * no candidate is a file is a directory reported, the first target's first.
105
+ * When nothing exists, `missing.tried` is every candidate tried, in order.
106
+ *
107
+ * Links into the built-in ignores (`node_modules`, `.git`, `dist`, …) are
108
+ * `missing`: `corpus()` never walks those folders, so their files are not known.
109
+ *
110
+ * The directory and document indexes are built on a corpus's first resolution
111
+ * and cached. A `corpus()` result never changes, so that is exact; a hand-built
112
+ * `Corpus` whose `documents()` returns something different later is not re-read.
113
+ */
114
+ export function resolveLink(link, corpus, options = {}) {
115
+ if (link.external)
116
+ return { kind: 'external' };
117
+ let targets;
118
+ try {
119
+ targets = linkTargets(link, options);
120
+ }
121
+ catch (error) {
122
+ // Malformed percent-encoding (`%E0`): the URL names no file anyone can
123
+ // reach, which is exactly `missing`. Reported, never thrown, so one bad
124
+ // link cannot abort a whole run.
125
+ void error;
126
+ return { kind: 'missing', tried: [link.url] };
127
+ }
128
+ if (targets.length === 0)
129
+ return { kind: 'self' };
130
+ const tried = [];
131
+ for (const target of targets) {
132
+ for (const candidate of candidates(target, options)) {
133
+ tried.push(candidate);
134
+ if (corpus.fileIndex.has(candidate))
135
+ return fileTarget(candidate, link, corpus);
136
+ }
137
+ }
138
+ const { directories } = indexes(corpus);
139
+ for (const target of targets) {
140
+ const bare = target.replace(/\/+$/, '');
141
+ if (directories.has(bare))
142
+ return { kind: 'directory', path: bare };
143
+ }
144
+ return { kind: 'missing', tried };
145
+ }
146
+ /** Basename → every repo file with it, for {@link movedLinkFix}. Built once per caller. */
147
+ export function basenameIndex(corpus) {
148
+ const byBasename = new Map();
149
+ for (const rel of corpus.fileIndex) {
150
+ const base = rel.slice(rel.lastIndexOf('/') + 1);
151
+ const list = byBasename.get(base);
152
+ if (list)
153
+ list.push(rel);
154
+ else
155
+ byBasename.set(base, [rel]);
156
+ }
157
+ return byBasename;
158
+ }
159
+ /**
160
+ * If a broken link's basename uniquely names one file in the repo (the target
161
+ * moved, not renamed), a deterministic autofix rewriting the URL to a path
162
+ * relative to the linking document (plan 0066). Ambiguous basename, or a URL
163
+ * whose exact span isn't known, → no fix.
164
+ *
165
+ * Lives beside `resolveLink` so that path arithmetic stays in this one module
166
+ * (plan 0404's structural rule keeps `node:path` out of the conditions).
167
+ */
168
+ export function movedLinkFix(link, byBasename) {
169
+ if (link.urlStart === undefined || link.urlEnd === undefined)
170
+ return undefined;
171
+ const path = link.url.split('#')[0] ?? '';
172
+ const fragment = link.url.slice(path.length); // '' or '#anchor'
173
+ const base = path.slice(path.replace(/\/+$/, '').lastIndexOf('/') + 1);
174
+ const matches = byBasename.get(base) ?? [];
175
+ if (matches.length !== 1)
176
+ return undefined; // renamed (no match) or ambiguous → no fix
177
+ const target = matches[0];
178
+ if (target === undefined)
179
+ return undefined;
180
+ let rel = posix.relative(posix.dirname(link.doc.relPath), target);
181
+ if (!rel.startsWith('.'))
182
+ rel = './' + rel;
183
+ const replacement = rel + fragment;
184
+ if (replacement === link.url)
185
+ return undefined;
186
+ return {
187
+ file: link.doc.file,
188
+ start: link.urlStart,
189
+ end: link.urlEnd,
190
+ replacement,
191
+ describe: `rewrite link "${link.url}" → "${replacement}"`,
192
+ };
193
+ }
194
+ //# sourceMappingURL=resolve-link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-link.js","sourceRoot":"","sources":["../../src/model/resolve-link.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { Predicate } from '@nielspeter/eess';
2
+ import type { MdLink, MdLinkBlock } from '../model/links.js';
3
+ /**
4
+ * Plan 0405 — select the links a block declares.
5
+ *
6
+ * These factories are deliberately NOT exported from the package root, the same
7
+ * as `areInternal`/`areLive`: the declaration scan lives in `LinkRuleBuilder`,
8
+ * which records the declaration when `areLabelled()`/`areInSection()` is called.
9
+ * A raw predicate composed through `satisfy()`/`not()`/`or()` would select
10
+ * without recording anything, and so without the scan.
11
+ */
12
+ /**
13
+ * The block that decides whether a link with this `path` is declared under the
14
+ * label `declared` matches: walking from the innermost block outwards, the first
15
+ * that either matches it (any form, exact case) or opens with a wrapped label of
16
+ * its own. A plain line that is not the label — `bug 0402: [b](b.md)`,
17
+ * `Metadata:`, a URL — never decides, so it neither hides a declaration nor
18
+ * captures one.
19
+ */
20
+ export declare function decidingBlock(path: readonly MdLinkBlock[], declared: RegExp): {
21
+ readonly block: MdLinkBlock;
22
+ readonly at: number;
23
+ readonly matches: boolean;
24
+ } | undefined;
25
+ /** Links declared under `label` (case-sensitive), in any label form, at any depth below it. */
26
+ export declare function areLabelledPredicate(label: string): Predicate<MdLink>;
27
+ /** Links under a heading matching `name` (a string exactly, or a `RegExp`), at any depth beneath it. */
28
+ export declare function areInSectionPredicate(name: string | RegExp): Predicate<MdLink>;
29
+ //# sourceMappingURL=declared-block.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"declared-block.d.ts","sourceRoot":"","sources":["../../src/predicates/declared-block.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAI5D;;;;;;;;GAQG;AAEH;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,SAAS,WAAW,EAAE,EAC5B,QAAQ,EAAE,MAAM,GACf;IAAE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,CAQ7F;AAED,+FAA+F;AAC/F,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAMrE;AAED,wGAAwG;AACxG,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAK9E"}
@@ -0,0 +1,47 @@
1
+ import { labelPattern, wrappedLabelOf } from '../model/label.js';
2
+ import { inSection } from '../model/query.js';
3
+ /**
4
+ * Plan 0405 — select the links a block declares.
5
+ *
6
+ * These factories are deliberately NOT exported from the package root, the same
7
+ * as `areInternal`/`areLive`: the declaration scan lives in `LinkRuleBuilder`,
8
+ * which records the declaration when `areLabelled()`/`areInSection()` is called.
9
+ * A raw predicate composed through `satisfy()`/`not()`/`or()` would select
10
+ * without recording anything, and so without the scan.
11
+ */
12
+ /**
13
+ * The block that decides whether a link with this `path` is declared under the
14
+ * label `declared` matches: walking from the innermost block outwards, the first
15
+ * that either matches it (any form, exact case) or opens with a wrapped label of
16
+ * its own. A plain line that is not the label — `bug 0402: [b](b.md)`,
17
+ * `Metadata:`, a URL — never decides, so it neither hides a declaration nor
18
+ * captures one.
19
+ */
20
+ export function decidingBlock(path, declared) {
21
+ for (let at = path.length - 1; at >= 0; at--) {
22
+ const block = path[at];
23
+ if (block === undefined)
24
+ continue;
25
+ if (declared.test(block.text))
26
+ return { block, at, matches: true };
27
+ if (wrappedLabelOf(block.text) !== undefined)
28
+ return { block, at, matches: false };
29
+ }
30
+ return undefined;
31
+ }
32
+ /** Links declared under `label` (case-sensitive), in any label form, at any depth below it. */
33
+ export function areLabelledPredicate(label) {
34
+ const re = new RegExp(labelPattern(label));
35
+ return {
36
+ description: `are declared under the label "${label}"`,
37
+ test: (l) => decidingBlock(l.blockPath ?? [], re)?.matches === true,
38
+ };
39
+ }
40
+ /** Links under a heading matching `name` (a string exactly, or a `RegExp`), at any depth beneath it. */
41
+ export function areInSectionPredicate(name) {
42
+ return {
43
+ description: `are in section "${String(name)}"`,
44
+ test: (l) => inSection(l, name),
45
+ };
46
+ }
47
+ //# sourceMappingURL=declared-block.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"declared-block.js","sourceRoot":"","sources":["../../src/predicates/declared-block.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAE7C;;;;;;;;GAQG;AAEH;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAC3B,IAA4B,EAC5B,QAAgB;IAEhB,KAAK,IAAI,EAAE,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC;QAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,CAAA;QACtB,IAAI,KAAK,KAAK,SAAS;YAAE,SAAQ;QACjC,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;QAClE,IAAI,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,SAAS;YAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAA;IACpF,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,oBAAoB,CAAC,KAAa;IAChD,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAA;IAC1C,OAAO;QACL,WAAW,EAAE,iCAAiC,KAAK,GAAG;QACtD,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,OAAO,KAAK,IAAI;KACpE,CAAA;AACH,CAAC;AAED,wGAAwG;AACxG,MAAM,UAAU,qBAAqB,CAAC,IAAqB;IACzD,OAAO;QACL,WAAW,EAAE,mBAAmB,MAAM,CAAC,IAAI,CAAC,GAAG;QAC/C,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC;KAChC,CAAA;AACH,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { Predicate } from '@nielspeter/eess';
2
+ import type { Corpus } from '../corpus.js';
3
+ import type { MdLink } from '../model/links.js';
4
+ import { type LinkResolveOptions } from '../model/resolve-link.js';
5
+ /**
6
+ * Links whose target is not a frozen corpus document (plan 0406), resolved with
7
+ * `resolveLink` and `options` — pass `beLinkedBack()` the same options, so both
8
+ * resolve a link the same way. Every other case is kept: a missing or external
9
+ * target is still examined, and still reported.
10
+ */
11
+ export declare function haveLiveTargetsPredicate(corpus: Corpus, options?: LinkResolveOptions): Predicate<MdLink>;
12
+ //# sourceMappingURL=live-target.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-target.d.ts","sourceRoot":"","sources":["../../src/predicates/live-target.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAe,KAAK,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAE/E;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,kBAAuB,GAC/B,SAAS,CAAC,MAAM,CAAC,CAQnB"}
@@ -0,0 +1,17 @@
1
+ import { resolveLink } from '../model/resolve-link.js';
2
+ /**
3
+ * Links whose target is not a frozen corpus document (plan 0406), resolved with
4
+ * `resolveLink` and `options` — pass `beLinkedBack()` the same options, so both
5
+ * resolve a link the same way. Every other case is kept: a missing or external
6
+ * target is still examined, and still reported.
7
+ */
8
+ export function haveLiveTargetsPredicate(corpus, options = {}) {
9
+ return {
10
+ description: 'have live targets (not in a frozen folder)',
11
+ test: (link) => {
12
+ const target = resolveLink(link, corpus, options);
13
+ return !(target.kind === 'document' && target.doc.frozen);
14
+ },
15
+ };
16
+ }
17
+ //# sourceMappingURL=live-target.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live-target.js","sourceRoot":"","sources":["../../src/predicates/live-target.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAA2B,MAAM,0BAA0B,CAAA;AAE/E;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CACtC,MAAc,EACd,UAA8B,EAAE;IAEhC,OAAO;QACL,WAAW,EAAE,4CAA4C;QACzD,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE;YACb,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;YACjD,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,UAAU,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QAC3D,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -19,19 +19,28 @@ export interface AdrEnforcementOptions extends PresetBaseOptions {
19
19
  };
20
20
  /** Valid tier numbers. Default `[1,2,3,4,5]`. */
21
21
  readonly tiers?: readonly number[];
22
- /** Verify cited file paths exist and cited `it('…')` titles resolve. Default `true`. */
22
+ /**
23
+ * Verify that the file paths a Mechanism cell cites exist. Default `true`.
24
+ *
25
+ * A cited `it('…')` **title** is not resolved here. Whether it names a real test is
26
+ * `eess-crossvalidate`'s `adrCitationsResolve`, which reads the test AST: a markdown
27
+ * dialect reading test files as text matched `it('r')` against any test beginning with
28
+ * `r`, and could not tell a commented-out test from a live one (bug 0111). Run that
29
+ * check too if your ADRs cite test titles.
30
+ */
23
31
  readonly verifyCitations?: boolean;
24
32
  }
25
33
  /**
26
34
  * OPINIONATED preset: gate a repo's ADRs on the EESS enforcement-tier model.
27
35
  * Gates on *declaration* — an ADR fails for a missing `## Enforcement` table, a
28
- * clause with no valid tier, or (when `verifyCitations`) a citation that doesn't
29
- * resolve; a soft-tier clause declared as such passes.
36
+ * clause with no valid tier, or (when `verifyCitations`) a cited file path that
37
+ * doesn't exist; a soft-tier clause declared as such passes.
30
38
  *
31
39
  * Emits per-rule ids so `overrides` can downgrade/disable individual checks.
32
40
  *
33
- * The citation check resolves two forms — a backticked file path and an
34
- * `it('…')` title. A Mechanism cell that cites something else (a rule id in
41
+ * The citation check resolves one form, a backticked file path. A cited `it('…')`
42
+ * title is `eess-crossvalidate`'s `adrCitationsResolve` to resolve, against the
43
+ * test AST (bug 0111). A Mechanism cell that cites something else (a rule id in
35
44
  * your own architecture tool, a CI job) is not resolved here, and this preset
36
45
  * takes no plugin for it: what counts as a live id is your fact, not the
37
46
  * corpus's. Compose that check from `rows()` + `correspondence()` against the
@@ -1 +1 @@
1
- {"version":3,"file":"adr.d.ts","sourceRoot":"","sources":["../../src/rules/adr.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,aAAa,EAClB,KAAK,iBAAiB,EAEvB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAW1C;;;;;GAKG;AACH,MAAM,WAAW,qBAAsB,SAAQ,iBAAiB;IAC9D,uDAAuD;IACvD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,sEAAsE;IACtE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAClC,kEAAkE;IAClE,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACtE,iDAAiD;IACjD,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,wFAAwF;IACxF,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAA;CACnC;AAuDD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,qBAA0B,GAClC,aAAa,EAAE,CAgDjB"}
1
+ {"version":3,"file":"adr.d.ts","sourceRoot":"","sources":["../../src/rules/adr.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,aAAa,EAClB,KAAK,iBAAiB,EAEvB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAW1C;;;;;GAKG;AACH,MAAM,WAAW,qBAAsB,SAAQ,iBAAiB;IAC9D,uDAAuD;IACvD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,sEAAsE;IACtE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAClC,kEAAkE;IAClE,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACtE,iDAAiD;IACjD,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC;;;;;;;;OAQG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAA;CACnC;AA8BD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,qBAA0B,GAClC,aAAa,EAAE,CAgDjB"}
package/dist/rules/adr.js CHANGED
@@ -1,5 +1,3 @@
1
- import { existsSync, readFileSync } from 'node:fs';
2
- import { join } from 'node:path';
3
1
  import { dispatchRule, finishPreset, validateOverrides, not, mergeCollectResults, } from '@nielspeter/eess';
4
2
  import { docs } from '../builders/docs.js';
5
3
  import { haveNameMatching } from '../predicates/document.js';
@@ -11,15 +9,6 @@ import { haveTableRowsSatisfying } from '../conditions/table-rows.js';
11
9
  const notIndexDoc = not(haveNameMatching(/^(README|index)\.md$/i));
12
10
  const RULE_IDS = ['adr/enforcement-declared', 'adr/valid-tiers', 'adr/citations-resolve'];
13
11
  const PATH_RE = /`([A-Za-z0-9_./-]+\.[A-Za-z0-9]+)`/g;
14
- const IT_CITE_RE = /it(?:\.\w+)?\(\s*['"]([^'"]+)['"]/g;
15
- /** Does `testFile` define a test titled `title`? (Text-level; 0059 upgrades to AST.) */
16
- function testDefinesIt(testAbs, title) {
17
- if (!existsSync(testAbs))
18
- return false;
19
- const content = readFileSync(testAbs, 'utf8');
20
- const esc = title.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
21
- return new RegExp(`it(?:\\.\\w+)?\\(\\s*['"\`]${esc}`).test(content);
22
- }
23
12
  function validateTier(ctx, tiers) {
24
13
  const clause = ctx.cells[0] ?? '';
25
14
  const match = ctx.get('tier').match(/[1-5]/);
@@ -32,38 +21,27 @@ function validateCitations(ctx, corpus) {
32
21
  const clause = ctx.cells[0] ?? '';
33
22
  const mech = ctx.get('mechanism');
34
23
  const problems = [];
35
- const citedPaths = [];
36
24
  for (const m of mech.matchAll(PATH_RE)) {
37
25
  const p = m[1];
38
26
  if (p === undefined)
39
27
  continue;
40
- citedPaths.push(p);
41
28
  if (!corpus.fileIndex.has(p)) {
42
29
  problems.push(`clause "${clause}" cites missing file \`${p}\``);
43
30
  }
44
31
  }
45
- const testFiles = citedPaths.filter((p) => p.endsWith('.ts'));
46
- for (const m of mech.matchAll(IT_CITE_RE)) {
47
- const title = m[1];
48
- if (title === undefined)
49
- continue;
50
- const found = testFiles.some((p) => testDefinesIt(join(corpus.root, p), title));
51
- if (!found) {
52
- problems.push(`clause "${clause}" cites it('${title}') not found in ${testFiles.length ? testFiles.join(', ') : 'any cited test file'}`);
53
- }
54
- }
55
32
  return problems;
56
33
  }
57
34
  /**
58
35
  * OPINIONATED preset: gate a repo's ADRs on the EESS enforcement-tier model.
59
36
  * Gates on *declaration* — an ADR fails for a missing `## Enforcement` table, a
60
- * clause with no valid tier, or (when `verifyCitations`) a citation that doesn't
61
- * resolve; a soft-tier clause declared as such passes.
37
+ * clause with no valid tier, or (when `verifyCitations`) a cited file path that
38
+ * doesn't exist; a soft-tier clause declared as such passes.
62
39
  *
63
40
  * Emits per-rule ids so `overrides` can downgrade/disable individual checks.
64
41
  *
65
- * The citation check resolves two forms — a backticked file path and an
66
- * `it('…')` title. A Mechanism cell that cites something else (a rule id in
42
+ * The citation check resolves one form, a backticked file path. A cited `it('…')`
43
+ * title is `eess-crossvalidate`'s `adrCitationsResolve` to resolve, against the
44
+ * test AST (bug 0111). A Mechanism cell that cites something else (a rule id in
67
45
  * your own architecture tool, a CI job) is not resolved here, and this preset
68
46
  * takes no plugin for it: what counts as a live id is your fact, not the
69
47
  * corpus's. Compose that check from `rows()` + `correspondence()` against the
@@ -1 +1 @@
1
- {"version":3,"file":"adr.js","sourceRoot":"","sources":["../../src/rules/adr.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"adr.js","sourceRoot":"","sources":["../../src/rules/adr.ts"],"names":[],"mappings":"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"}
@@ -48,15 +48,19 @@ export interface HonestyAtCloseOptions extends PresetReportOptions {
48
48
  readonly closeInPlace?: boolean;
49
49
  /**
50
50
  * The full `State:` vocabulary this corpus uses. A token outside it is
51
- * **reported** (`ledger/unknown-state`), not ignored. Default: the plan lane's
52
- * enum. A bug-shaped lane passes its own, e.g.
53
- * `['Draft', 'Ready', 'Fixed', 'Rejected', 'Parked']`.
51
+ * **reported** (`ledger/unknown-state`), not ignored. A bug-shaped lane passes its own,
52
+ * e.g. `['Draft', 'Ready', 'Fixed', 'Rejected', 'Parked']`.
53
+ *
54
+ * **Declare it together with {@link terminalStates}, or omit both** for the plan lane's
55
+ * defaults. One alone throws an `ArchConfigError` (bug 0284).
54
56
  */
55
57
  readonly states?: readonly string[];
56
58
  /**
57
- * Which of {@link states} mean *closed*. Default `['Done', "Won't-do"]`; a
58
- * bug lane passes `['Fixed', 'Rejected']`. Members are treated as known states
59
- * whether or not they also appear in {@link states}.
59
+ * Which of {@link states} mean *closed*; a bug lane passes `['Fixed', 'Rejected']`.
60
+ * Members are treated as known states whether or not they also appear in {@link states}.
61
+ *
62
+ * **Declare it together with {@link states}, or omit both** for the defaults
63
+ * (`['Done', "Won't-do"]`). One alone throws an `ArchConfigError` (bug 0284).
60
64
  */
61
65
  readonly terminalStates?: readonly string[];
62
66
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../src/rules/ledger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,mBAAmB,EAAuB,MAAM,kBAAkB,CAAA;AAE9F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAE1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAC1D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAMjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;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;IAC3C;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAA;CACtC;AAwED;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,IAAI,CAAC,EAAE,IAAI,GACV;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAItD;AA6TD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsFG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,qBAA0B,GAClC,aAAa,EAAE,CA2EjB;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;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,GAAG,WAAW,CAqB5F"}
1
+ {"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../src/rules/ledger.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,mBAAmB,EAEzB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAE1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAC1D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAOjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;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;;;;;;;OAOG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC;;;;;;OAMG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC3C;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAA;CACtC;AAqHD;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,IAAI,CAAC,EAAE,IAAI,GACV;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAItD;AA2VD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsFG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,qBAA0B,GAClC,aAAa,EAAE,CA4EjB;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;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,GAAG,WAAW,CAoB5F"}