@nielspeter/eess-md 0.8.0 → 0.10.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/README.md +13 -1
- package/dist/builders/code-blocks.d.ts +37 -0
- package/dist/builders/code-blocks.d.ts.map +1 -0
- package/dist/builders/code-blocks.js +143 -0
- package/dist/builders/code-blocks.js.map +1 -0
- package/dist/builders/declaration-findings.d.ts +37 -0
- package/dist/builders/declaration-findings.d.ts.map +1 -0
- package/dist/builders/declaration-findings.js +128 -0
- package/dist/builders/declaration-findings.js.map +1 -0
- package/dist/builders/links.d.ts +60 -1
- package/dist/builders/links.d.ts.map +1 -1
- package/dist/builders/links.js +92 -1
- package/dist/builders/links.js.map +1 -1
- package/dist/conditions/linked-back.d.ts +17 -0
- package/dist/conditions/linked-back.d.ts.map +1 -0
- package/dist/conditions/linked-back.js +122 -0
- package/dist/conditions/linked-back.js.map +1 -0
- package/dist/conditions/resolve.d.ts +8 -40
- package/dist/conditions/resolve.d.ts.map +1 -1
- package/dist/conditions/resolve.js +26 -138
- package/dist/conditions/resolve.js.map +1 -1
- package/dist/corpus.d.ts +3 -0
- package/dist/corpus.d.ts.map +1 -1
- package/dist/corpus.js +7 -10
- package/dist/corpus.js.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/model/code-block-parse.d.ts +118 -0
- package/dist/model/code-block-parse.d.ts.map +1 -0
- package/dist/model/code-block-parse.js +368 -0
- package/dist/model/code-block-parse.js.map +1 -0
- package/dist/model/document.d.ts +14 -3
- package/dist/model/document.d.ts.map +1 -1
- package/dist/model/document.js +30 -7
- package/dist/model/document.js.map +1 -1
- package/dist/model/label.d.ts +35 -0
- package/dist/model/label.d.ts.map +1 -0
- package/dist/model/label.js +68 -0
- package/dist/model/label.js.map +1 -0
- package/dist/model/links.d.ts +43 -0
- package/dist/model/links.d.ts.map +1 -1
- package/dist/model/links.js +112 -11
- package/dist/model/links.js.map +1 -1
- package/dist/model/prose.d.ts +11 -0
- package/dist/model/prose.d.ts.map +1 -1
- package/dist/model/prose.js +50 -5
- package/dist/model/prose.js.map +1 -1
- package/dist/model/query.d.ts +7 -0
- package/dist/model/query.d.ts.map +1 -1
- package/dist/model/query.js +10 -3
- package/dist/model/query.js.map +1 -1
- package/dist/model/resolve-link.d.ts +142 -0
- package/dist/model/resolve-link.d.ts.map +1 -0
- package/dist/model/resolve-link.js +194 -0
- package/dist/model/resolve-link.js.map +1 -0
- package/dist/predicates/declared-block.d.ts +29 -0
- package/dist/predicates/declared-block.d.ts.map +1 -0
- package/dist/predicates/declared-block.js +47 -0
- package/dist/predicates/declared-block.js.map +1 -0
- package/dist/predicates/live-target.d.ts +12 -0
- package/dist/predicates/live-target.d.ts.map +1 -0
- package/dist/predicates/live-target.js +17 -0
- package/dist/predicates/live-target.js.map +1 -0
- package/dist/rules/adr.d.ts +14 -5
- package/dist/rules/adr.d.ts.map +1 -1
- package/dist/rules/adr.js +5 -27
- package/dist/rules/adr.js.map +1 -1
- package/dist/rules/ledger.d.ts +10 -6
- package/dist/rules/ledger.d.ts.map +1 -1
- package/dist/rules/ledger.js +80 -24
- package/dist/rules/ledger.js.map +1 -1
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -144,7 +144,9 @@ a `correspondence()` against the set you hold, both directions. The docs page's
|
|
|
144
144
|
```typescript
|
|
145
145
|
import { adrEnforcement } from '@nielspeter/eess-md/rules/adr'
|
|
146
146
|
|
|
147
|
-
|
|
147
|
+
// section+table present, valid tiers, cited paths exist. A cited it('…') title is not
|
|
148
|
+
// checked here — run eess-crossvalidate's adrCitationsResolve for that.
|
|
149
|
+
adrEnforcement(c, { dir: 'docs/adr/**' })
|
|
148
150
|
```
|
|
149
151
|
|
|
150
152
|
An index/schema doc in the ADR directory (`README.md` or `index.md`) is exempt —
|
|
@@ -168,6 +170,16 @@ adrEnforcement(c, {
|
|
|
168
170
|
})
|
|
169
171
|
```
|
|
170
172
|
|
|
173
|
+
## Code blocks that parse: `parseCodeBlocks()` + `codeBlocks()`
|
|
174
|
+
|
|
175
|
+
Check every fenced block of one language with a parser you name. eess-md owns the loop and the
|
|
176
|
+
evidence, and never loads a parser itself. `parseCodeBlocks(corpus, { language, parser })` is the
|
|
177
|
+
one async call; `codeBlocks(parsed).should().parse().check()` is an ordinary synchronous rule over
|
|
178
|
+
what it parsed. A parser names itself and declares canaries it must reject, and every way it can
|
|
179
|
+
fail (a throw, a hang past its budget, a malformed or missing verdict, a canary it accepts) is one
|
|
180
|
+
unsuppressable finding, never a pass. The port and the failure table are in
|
|
181
|
+
[the Markdown dialect's docs](../../docs/markdown.md#code-blocks-that-parse).
|
|
182
|
+
|
|
171
183
|
## `@nielspeter/eess-md/internal` is not API
|
|
172
184
|
|
|
173
185
|
| Specifier | What it is |
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { RuleBuilder, type CollectResult } from '@nielspeter/eess';
|
|
2
|
+
import { type ParsedCodeBlock, type ParsedCodeBlocks } from '../model/code-block-parse.js';
|
|
3
|
+
/** The instrument's identity: one constant, so several rules over one failed parse dedupe to one. */
|
|
4
|
+
export declare const CODE_BLOCK_PARSER_INSTRUMENT = "eess-md: code-block parser";
|
|
5
|
+
/**
|
|
6
|
+
* Rule builder over the blocks `parseCodeBlocks` parsed. Its elements are the parsed set, so a
|
|
7
|
+
* predicate can only narrow what a parser saw, never select a block no parser saw.
|
|
8
|
+
*
|
|
9
|
+
* No rule surface here is async: the parse happens once in `parseCodeBlocks`, and this builder reads
|
|
10
|
+
* its facts synchronously (plan 0412; an async `check()` would need an ADR).
|
|
11
|
+
*/
|
|
12
|
+
export declare class CodeBlockRuleBuilder extends RuleBuilder<ParsedCodeBlock, ParsedCodeBlocks> {
|
|
13
|
+
constructor(parsed: ParsedCodeBlocks);
|
|
14
|
+
protected getElements(): ParsedCodeBlock[];
|
|
15
|
+
/** No Markdown file loaded at all outranks everything, `.expectEmpty()` included (ADR-010). */
|
|
16
|
+
protected sourceEmpty(): boolean;
|
|
17
|
+
/** When near-miss tags are why nothing was examined, send the author to the spelling. */
|
|
18
|
+
protected deadGlobDiagnosis(): string | undefined;
|
|
19
|
+
/** The kernel's verdict, plus the instrument finding once per rule when the parser failed. */
|
|
20
|
+
protected collectViolations(): CollectResult;
|
|
21
|
+
/** Filter to blocks in documents whose repo-relative path matches the file glob. */
|
|
22
|
+
resideInFile(glob: string): this;
|
|
23
|
+
/** Filter to blocks in documents whose repo-relative path matches the folder glob. */
|
|
24
|
+
resideInFolder(glob: string): this;
|
|
25
|
+
/** Assert every selected block parses: an `invalid` or `unrecognised` verdict is a finding. */
|
|
26
|
+
parse(): this;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Entry point: rules over the code blocks one `parseCodeBlocks` call parsed.
|
|
30
|
+
*
|
|
31
|
+
* ```ts
|
|
32
|
+
* const parsed = await parseCodeBlocks(corpus, { language: 'mermaid', parser })
|
|
33
|
+
* codeBlocks(parsed).should().parse().check()
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function codeBlocks(parsed: ParsedCodeBlocks): CodeBlockRuleBuilder;
|
|
37
|
+
//# sourceMappingURL=code-blocks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-blocks.d.ts","sourceRoot":"","sources":["../../src/builders/code-blocks.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,WAAW,EAGX,KAAK,aAAa,EAGnB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAA;AAIrC,qGAAqG;AACrG,eAAO,MAAM,4BAA4B,+BAA+B,CAAA;AAiExE;;;;;;GAMG;AACH,qBAAa,oBAAqB,SAAQ,WAAW,CAAC,eAAe,EAAE,gBAAgB,CAAC;gBAC1E,MAAM,EAAE,gBAAgB;IAYpC,SAAS,CAAC,WAAW,IAAI,eAAe,EAAE;IAI1C,+FAA+F;cAC5E,WAAW,IAAI,OAAO;IAIzC,yFAAyF;cACtE,iBAAiB,IAAI,MAAM,GAAG,SAAS;IAS1D,8FAA8F;cAC3E,iBAAiB,IAAI,aAAa;IAqBrD,oFAAoF;IACpF,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIhC,sFAAsF;IACtF,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIlC,+FAA+F;IAC/F,KAAK,IAAI,IAAI;CAGd;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,oBAAoB,CAEzE"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { ArchConfigError, RuleBuilder, collectResult, } from '@nielspeter/eess';
|
|
2
|
+
import { describeNearMisses, isParsedCodeBlocks, } from '../model/code-block-parse.js';
|
|
3
|
+
import { resideInFile, resideInFolder } from '../predicates/document.js';
|
|
4
|
+
import { mdViolation } from '../model/violation.js';
|
|
5
|
+
/** The instrument's identity: one constant, so several rules over one failed parse dedupe to one. */
|
|
6
|
+
export const CODE_BLOCK_PARSER_INSTRUMENT = 'eess-md: code-block parser';
|
|
7
|
+
const onDocument = (p) => ({
|
|
8
|
+
description: p.description,
|
|
9
|
+
test: (b) => p.test(b.doc),
|
|
10
|
+
});
|
|
11
|
+
function bodyLineCount(value) {
|
|
12
|
+
return value === '' ? 0 : value.split('\n').length;
|
|
13
|
+
}
|
|
14
|
+
/** Condition: every selected block's verdict is `valid`. */
|
|
15
|
+
function parse(parsed) {
|
|
16
|
+
const by = `${parsed.parser.name} ${parsed.parser.version}`;
|
|
17
|
+
return {
|
|
18
|
+
description: `parse with ${by}`,
|
|
19
|
+
evaluate: (elements, ctx) => elements.flatMap((e) => {
|
|
20
|
+
const v = e.verdict;
|
|
21
|
+
// No verdict is never a pass: it exists only beside a failure, which the builder reports.
|
|
22
|
+
// `parseCodeBlocks` guarantees that pairing by construction (every path yields one verdict
|
|
23
|
+
// per text or a failure), so no second check here: one that can never fire proves nothing.
|
|
24
|
+
if (v === null || v.outcome === 'valid')
|
|
25
|
+
return [];
|
|
26
|
+
const where = `${e.doc.relPath}:${String(e.block.line)}`;
|
|
27
|
+
if (v.outcome === 'unrecognised') {
|
|
28
|
+
return [
|
|
29
|
+
{
|
|
30
|
+
...mdViolation({
|
|
31
|
+
element: where,
|
|
32
|
+
file: e.doc.file,
|
|
33
|
+
line: e.block.line,
|
|
34
|
+
message: `${by} does not recognise this \`${parsed.language}\` block: ${v.message}`,
|
|
35
|
+
sourceText: e.doc.text,
|
|
36
|
+
context: ctx,
|
|
37
|
+
}),
|
|
38
|
+
suggestion: v.remedy,
|
|
39
|
+
},
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
const lines = bodyLineCount(e.block.value);
|
|
43
|
+
const inner = v.line;
|
|
44
|
+
const inside = inner !== null && inner >= 1 && inner <= lines;
|
|
45
|
+
const line = inside ? e.block.line + inner : e.block.line;
|
|
46
|
+
const note = inside
|
|
47
|
+
? ''
|
|
48
|
+
: inner === null
|
|
49
|
+
? ' (the line inside the block is unknown)'
|
|
50
|
+
: ` (the parser gave line ${String(inner)} for a ${String(lines)}-line block)`;
|
|
51
|
+
return [
|
|
52
|
+
{
|
|
53
|
+
...mdViolation({
|
|
54
|
+
element: where,
|
|
55
|
+
file: e.doc.file,
|
|
56
|
+
line,
|
|
57
|
+
message: `this \`${parsed.language}\` block does not parse with ${by}: ${v.message}${note}`,
|
|
58
|
+
sourceText: e.doc.text,
|
|
59
|
+
context: ctx,
|
|
60
|
+
}),
|
|
61
|
+
suggestion: v.remedy,
|
|
62
|
+
},
|
|
63
|
+
];
|
|
64
|
+
}),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Rule builder over the blocks `parseCodeBlocks` parsed. Its elements are the parsed set, so a
|
|
69
|
+
* predicate can only narrow what a parser saw, never select a block no parser saw.
|
|
70
|
+
*
|
|
71
|
+
* No rule surface here is async: the parse happens once in `parseCodeBlocks`, and this builder reads
|
|
72
|
+
* its facts synchronously (plan 0412; an async `check()` would need an ADR).
|
|
73
|
+
*/
|
|
74
|
+
export class CodeBlockRuleBuilder extends RuleBuilder {
|
|
75
|
+
constructor(parsed) {
|
|
76
|
+
super(parsed);
|
|
77
|
+
if (!isParsedCodeBlocks(parsed)) {
|
|
78
|
+
throw new ArchConfigError('codeBlocks', "codeBlocks() takes the object this copy of eess-md's parseCodeBlocks() returned. A " +
|
|
79
|
+
'hand-built object would let any verdict through unchecked. If you built it with ' +
|
|
80
|
+
'parseCodeBlocks, two copies of @nielspeter/eess-md are installed; dedupe them.');
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
getElements() {
|
|
84
|
+
return [...this.project.blocks];
|
|
85
|
+
}
|
|
86
|
+
/** No Markdown file loaded at all outranks everything, `.expectEmpty()` included (ADR-010). */
|
|
87
|
+
sourceEmpty() {
|
|
88
|
+
return this.project.documentsLoaded === 0;
|
|
89
|
+
}
|
|
90
|
+
/** When near-miss tags are why nothing was examined, send the author to the spelling. */
|
|
91
|
+
deadGlobDiagnosis() {
|
|
92
|
+
const { blocks, nearMisses, language } = this.project;
|
|
93
|
+
if (blocks.length > 0 || nearMisses.length === 0)
|
|
94
|
+
return undefined;
|
|
95
|
+
return (`no block is tagged \`${language}\`, and the tag is matched exactly. These are not read: ` +
|
|
96
|
+
`${describeNearMisses(nearMisses)}. Retag them \`${language}\`.`);
|
|
97
|
+
}
|
|
98
|
+
/** The kernel's verdict, plus the instrument finding once per rule when the parser failed. */
|
|
99
|
+
collectViolations() {
|
|
100
|
+
const base = super.collectViolations();
|
|
101
|
+
const failure = this.project.failure;
|
|
102
|
+
if (failure === null)
|
|
103
|
+
return base;
|
|
104
|
+
const { name, version } = this.project.parser;
|
|
105
|
+
const instrument = {
|
|
106
|
+
rule: CODE_BLOCK_PARSER_INSTRUMENT,
|
|
107
|
+
ruleId: CODE_BLOCK_PARSER_INSTRUMENT,
|
|
108
|
+
element: `${name}@${version}`,
|
|
109
|
+
file: '',
|
|
110
|
+
line: 0,
|
|
111
|
+
message: `the ${this.project.language} blocks were not checked: ${failure.cause.replace(/\.$/, '')}. No block of the ` +
|
|
112
|
+
`language has a verdict, so this rule cannot pass.`,
|
|
113
|
+
suggestion: failure.remedy,
|
|
114
|
+
bypassFilters: true,
|
|
115
|
+
};
|
|
116
|
+
// The kernel's evidence, passed through whole, so no field it adds later can be dropped here.
|
|
117
|
+
return collectResult([...base, instrument], base);
|
|
118
|
+
}
|
|
119
|
+
/** Filter to blocks in documents whose repo-relative path matches the file glob. */
|
|
120
|
+
resideInFile(glob) {
|
|
121
|
+
return this.addPredicate(onDocument(resideInFile(glob)));
|
|
122
|
+
}
|
|
123
|
+
/** Filter to blocks in documents whose repo-relative path matches the folder glob. */
|
|
124
|
+
resideInFolder(glob) {
|
|
125
|
+
return this.addPredicate(onDocument(resideInFolder(glob)));
|
|
126
|
+
}
|
|
127
|
+
/** Assert every selected block parses: an `invalid` or `unrecognised` verdict is a finding. */
|
|
128
|
+
parse() {
|
|
129
|
+
return this.addCondition(parse(this.project));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Entry point: rules over the code blocks one `parseCodeBlocks` call parsed.
|
|
134
|
+
*
|
|
135
|
+
* ```ts
|
|
136
|
+
* const parsed = await parseCodeBlocks(corpus, { language: 'mermaid', parser })
|
|
137
|
+
* codeBlocks(parsed).should().parse().check()
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
export function codeBlocks(parsed) {
|
|
141
|
+
return new CodeBlockRuleBuilder(parsed);
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=code-blocks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-blocks.js","sourceRoot":"","sources":["../../src/builders/code-blocks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ConditionContext } from '@nielspeter/eess';
|
|
2
|
+
import type { Corpus } from '../corpus.js';
|
|
3
|
+
import { type ArchViolation } from '../model/violation.js';
|
|
4
|
+
/** What an `areLabelled()`/`areInSection()` call declared, kept for the declaration scan. */
|
|
5
|
+
export type LinkDeclaration = {
|
|
6
|
+
readonly kind: 'label';
|
|
7
|
+
readonly label: string;
|
|
8
|
+
} | {
|
|
9
|
+
readonly kind: 'section';
|
|
10
|
+
readonly name: string | RegExp;
|
|
11
|
+
};
|
|
12
|
+
/** One key per distinct declaration, so a label declared twice is scanned once. */
|
|
13
|
+
export declare function declarationKey(d: LinkDeclaration): string;
|
|
14
|
+
/**
|
|
15
|
+
* Plan 0405 — findings about the declarations themselves, scanned over the whole
|
|
16
|
+
* corpus (not the rule's selection: a misspelt declaration is, by definition, not
|
|
17
|
+
* selected). Each names something the selector could not read (ADR-016 rule 7):
|
|
18
|
+
*
|
|
19
|
+
* - **a near-miss label:** a wrapped label (`**Label:**`, `**Label**:`,
|
|
20
|
+
* `__Label__:`) opening a block that matches the declared one except for case
|
|
21
|
+
* or inner spacing. The plain `Label:` form is never a near-miss: prose
|
|
22
|
+
* beginning "related to:" is common;
|
|
23
|
+
* - **a label inside the declaration:** a different wrapped label nested inside
|
|
24
|
+
* a declaration takes the links under it out of the declaration;
|
|
25
|
+
* - **a label where no block starts:** the label, exact or near, later in a
|
|
26
|
+
* paragraph, in a table cell or in a heading, where it declares nothing — or
|
|
27
|
+
* at a block's start in a form the grammar does not read (`**_Label:_**`, a
|
|
28
|
+
* whole line in bold);
|
|
29
|
+
* - **reference-style links:** a declaration holding `[text][ref]` links, which
|
|
30
|
+
* eess-md does not read;
|
|
31
|
+
* - **an empty declaration:** a wrapped label selecting no link — it names no
|
|
32
|
+
* record, or it stands alone with no list directly under it;
|
|
33
|
+
* - **a near-miss section:** a heading that misses a string declaration by case
|
|
34
|
+
* or spacing (a `RegExp` states its own tolerance).
|
|
35
|
+
*/
|
|
36
|
+
export declare function declarationFindings(corpus: Corpus, declarations: readonly LinkDeclaration[], context: ConditionContext): ArchViolation[];
|
|
37
|
+
//# sourceMappingURL=declaration-findings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"declaration-findings.d.ts","sourceRoot":"","sources":["../../src/builders/declaration-findings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAG1C,OAAO,EAAe,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAGvE,6FAA6F;AAC7F,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAA;AAEhE,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,CAGzD;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,SAAS,eAAe,EAAE,EACxC,OAAO,EAAE,gBAAgB,GACxB,aAAa,EAAE,CAyHjB"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { collectLinkBlocks } from '../model/links.js';
|
|
2
|
+
import { isLabelAlone, isNearMiss, labelPattern, wrappedLabelOf } from '../model/label.js';
|
|
3
|
+
import { mdViolation } from '../model/violation.js';
|
|
4
|
+
import { decidingBlock } from '../predicates/declared-block.js';
|
|
5
|
+
/** One key per distinct declaration, so a label declared twice is scanned once. */
|
|
6
|
+
export function declarationKey(d) {
|
|
7
|
+
if (d.kind === 'label')
|
|
8
|
+
return `label:${d.label}`;
|
|
9
|
+
return typeof d.name === 'string' ? `section:${d.name}` : `section-re:${String(d.name)}`;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Plan 0405 — findings about the declarations themselves, scanned over the whole
|
|
13
|
+
* corpus (not the rule's selection: a misspelt declaration is, by definition, not
|
|
14
|
+
* selected). Each names something the selector could not read (ADR-016 rule 7):
|
|
15
|
+
*
|
|
16
|
+
* - **a near-miss label:** a wrapped label (`**Label:**`, `**Label**:`,
|
|
17
|
+
* `__Label__:`) opening a block that matches the declared one except for case
|
|
18
|
+
* or inner spacing. The plain `Label:` form is never a near-miss: prose
|
|
19
|
+
* beginning "related to:" is common;
|
|
20
|
+
* - **a label inside the declaration:** a different wrapped label nested inside
|
|
21
|
+
* a declaration takes the links under it out of the declaration;
|
|
22
|
+
* - **a label where no block starts:** the label, exact or near, later in a
|
|
23
|
+
* paragraph, in a table cell or in a heading, where it declares nothing — or
|
|
24
|
+
* at a block's start in a form the grammar does not read (`**_Label:_**`, a
|
|
25
|
+
* whole line in bold);
|
|
26
|
+
* - **reference-style links:** a declaration holding `[text][ref]` links, which
|
|
27
|
+
* eess-md does not read;
|
|
28
|
+
* - **an empty declaration:** a wrapped label selecting no link — it names no
|
|
29
|
+
* record, or it stands alone with no list directly under it;
|
|
30
|
+
* - **a near-miss section:** a heading that misses a string declaration by case
|
|
31
|
+
* or spacing (a `RegExp` states its own tolerance).
|
|
32
|
+
*/
|
|
33
|
+
export function declarationFindings(corpus, declarations, context) {
|
|
34
|
+
const out = [];
|
|
35
|
+
for (const doc of corpus.documents()) {
|
|
36
|
+
const { links, references, blocks, unreadLabels } = collectLinkBlocks(doc.root, doc.text);
|
|
37
|
+
// Each finding names its kind in its element, so one `.excluding()` sanctions one kind
|
|
38
|
+
// (`→ label "Supersedes" (empty)`), and carries its own remedy as the suggestion.
|
|
39
|
+
const report = (line, element, message, suggestion) => {
|
|
40
|
+
out.push(mdViolation({
|
|
41
|
+
file: doc.file,
|
|
42
|
+
line,
|
|
43
|
+
sourceText: doc.text,
|
|
44
|
+
context: { ...context, suggestion },
|
|
45
|
+
element,
|
|
46
|
+
message,
|
|
47
|
+
}));
|
|
48
|
+
};
|
|
49
|
+
for (const d of declarations) {
|
|
50
|
+
if (d.kind === 'section') {
|
|
51
|
+
if (typeof d.name !== 'string')
|
|
52
|
+
continue;
|
|
53
|
+
const declared = d.name;
|
|
54
|
+
for (const section of doc.sections) {
|
|
55
|
+
if (!isNearMiss(section.name, declared))
|
|
56
|
+
continue;
|
|
57
|
+
report(section.line, `${doc.relPath} → section "${section.name}" (near miss)`, `the heading "${section.name}" is not the declared section "${declared}", so the links under it are not checked`, `write it "${declared}"`);
|
|
58
|
+
}
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const L = d.label;
|
|
62
|
+
const declared = new RegExp(labelPattern(L));
|
|
63
|
+
const element = (found, kind) => `${doc.relPath} → label "${found}" (${kind})`;
|
|
64
|
+
for (const block of blocks) {
|
|
65
|
+
const found = wrappedLabelOf(block.text);
|
|
66
|
+
if (found === undefined || !isNearMiss(found, L))
|
|
67
|
+
continue;
|
|
68
|
+
report(block.line, element(found, 'near miss'), `the label "${found}" is not the declared "${L}", so the links under it are not checked`, `write it "${L}"`);
|
|
69
|
+
}
|
|
70
|
+
// Which declaration blocks select a link, which hold a reference, which enclose anything.
|
|
71
|
+
const selects = new Set();
|
|
72
|
+
const holdsReference = new Set();
|
|
73
|
+
const encloses = new Set();
|
|
74
|
+
const taken = new Map();
|
|
75
|
+
const classify = (path, isReference) => {
|
|
76
|
+
for (const b of path)
|
|
77
|
+
encloses.add(b.line);
|
|
78
|
+
const decision = decidingBlock(path, declared);
|
|
79
|
+
if (decision === undefined)
|
|
80
|
+
return;
|
|
81
|
+
if (decision.matches) {
|
|
82
|
+
;
|
|
83
|
+
(isReference ? holdsReference : selects).add(decision.block.line);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const found = wrappedLabelOf(decision.block.text);
|
|
87
|
+
const outer = path.slice(0, decision.at).some((b) => declared.test(b.text));
|
|
88
|
+
if (found !== undefined && outer && !isNearMiss(found, L)) {
|
|
89
|
+
taken.set(decision.block.line, found);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
for (const l of links)
|
|
93
|
+
classify(l.blockPath ?? [], false);
|
|
94
|
+
for (const path of references)
|
|
95
|
+
classify(path, true);
|
|
96
|
+
for (const [line, found] of taken) {
|
|
97
|
+
report(line, element(found, `inside "${L}"`), `the label "${found}" sits inside the "${L}" declaration and takes the links under it out of it`, `drop the label, or move it out of the "${L}" list`);
|
|
98
|
+
}
|
|
99
|
+
for (const block of blocks) {
|
|
100
|
+
if (!declared.test(block.text))
|
|
101
|
+
continue;
|
|
102
|
+
if (holdsReference.has(block.line)) {
|
|
103
|
+
report(block.line, element(L, 'reference links'), `the "${L}" declaration holds reference-style links, which eess-md does not read`, 'write them as inline links ([text](path))');
|
|
104
|
+
}
|
|
105
|
+
else if (wrappedLabelOf(block.text) === L &&
|
|
106
|
+
!selects.has(block.line) &&
|
|
107
|
+
// A link under it that is not selected is already a finding of its own.
|
|
108
|
+
!encloses.has(block.line)) {
|
|
109
|
+
const alone = isLabelAlone(block.text);
|
|
110
|
+
report(block.line, element(L, 'empty'), alone
|
|
111
|
+
? `the "${L}" label stands alone with no list directly under it, so it declares nothing`
|
|
112
|
+
: `the "${L}" declaration names no record`, alone
|
|
113
|
+
? 'put its list right after it, or its links on its line'
|
|
114
|
+
: 'add the links it declares, or remove the label');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
for (const u of unreadLabels) {
|
|
118
|
+
if (u.label !== L && !isNearMiss(u.label, L))
|
|
119
|
+
continue;
|
|
120
|
+
report(u.line, element(u.label, u.reason === 'format' ? 'formatting' : 'not at a block start'), u.reason === 'format'
|
|
121
|
+
? `the label "${u.label}" is written with formatting eess-md does not read, so the links after it are not read as a declaration`
|
|
122
|
+
: `the label "${u.label}" is not at the start of a paragraph or list item, so the links after it are not read as a declaration`, u.reason === 'format' ? `write it **${L}:**` : 'start a paragraph or list item with it');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=declaration-findings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"declaration-findings.js","sourceRoot":"","sources":["../../src/builders/declaration-findings.ts"],"names":[],"mappings":"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"}
|
package/dist/builders/links.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RuleBuilder } from '@nielspeter/eess';
|
|
1
|
+
import { RuleBuilder, type CollectResult } from '@nielspeter/eess';
|
|
2
2
|
import type { Corpus } from '../corpus.js';
|
|
3
3
|
import { type MdLink } from '../model/links.js';
|
|
4
4
|
import { type LinkResolveOptions } from '../conditions/resolve.js';
|
|
@@ -9,17 +9,76 @@ export type { MdLink } from '../model/links.js';
|
|
|
9
9
|
* Rule builder over the corpus's markdown links.
|
|
10
10
|
*/
|
|
11
11
|
export declare class LinkRuleBuilder extends RuleBuilder<MdLink, Corpus> {
|
|
12
|
+
/** What `areLabelled()`/`areInSection()` declared, for the near-miss scan (plan 0405). */
|
|
13
|
+
private _declarations;
|
|
12
14
|
protected getElements(): MdLink[];
|
|
13
15
|
/** Filter to links that point within the repo (no scheme). */
|
|
14
16
|
areInternal(): this;
|
|
15
17
|
/** Filter to links with an external scheme (http, mailto, protocol-relative). */
|
|
16
18
|
areExternal(): this;
|
|
19
|
+
/**
|
|
20
|
+
* Filter to links declared under `label` (plan 0405), in any of the ledger's
|
|
21
|
+
* forms (`**Label:**`, `**Label**:`, `__Label__:`, `Label:`), matched exactly
|
|
22
|
+
* and case-sensitively. A link is under the label when it sits in the block the
|
|
23
|
+
* label opens, in that block's nested lists, or — for a label alone on its line
|
|
24
|
+
* — in the lists directly after it. The nearest label decides: walking out from
|
|
25
|
+
* the link, the first block that is the label, or opens with a wrapped label of
|
|
26
|
+
* its own, settles it; a plain line that is not the label settles nothing.
|
|
27
|
+
*
|
|
28
|
+
* The rule also reports, over the whole corpus, what it cannot read: a wrapped
|
|
29
|
+
* label that misses the declared one only by case or spacing, a different
|
|
30
|
+
* wrapped label inside the declaration, the label where no block starts, a
|
|
31
|
+
* declaration holding reference-style links, and a wrapped declaration with
|
|
32
|
+
* nothing under it. That check
|
|
33
|
+
* runs through this method only: a selection taken with `.select()` carries no
|
|
34
|
+
* findings, so it carries no such check either.
|
|
35
|
+
*/
|
|
36
|
+
areLabelled(label: string): this;
|
|
37
|
+
/**
|
|
38
|
+
* Filter to links under a heading matching `name` — a string exactly, or a
|
|
39
|
+
* `RegExp` — at any depth beneath it, matched the way `haveSection()` matches
|
|
40
|
+
* (plan 0405). A heading that misses a string `name` only by case or spacing
|
|
41
|
+
* is reported, as for `areLabelled()`.
|
|
42
|
+
*/
|
|
43
|
+
areInSection(name: string | RegExp): this;
|
|
44
|
+
/**
|
|
45
|
+
* Record a declaration once; declaring the same label twice scans it once.
|
|
46
|
+
* Called on the copy `addPredicate()` returns, and it replaces the array rather
|
|
47
|
+
* than pushing into it, so a fork never shares its parent's declarations — the
|
|
48
|
+
* kernel's shallow `copy()` is enough.
|
|
49
|
+
*/
|
|
50
|
+
private recordDeclaration;
|
|
17
51
|
/**
|
|
18
52
|
* Condition: internal links resolve to an existing repo file. Static-site
|
|
19
53
|
* corpora with extensionless links pass `tryExtensions`/`tryIndex`, e.g.
|
|
20
54
|
* `resolve({ tryExtensions: ['.md'], tryIndex: 'index.md' })`.
|
|
21
55
|
*/
|
|
22
56
|
resolve(options?: LinkResolveOptions): this;
|
|
57
|
+
/**
|
|
58
|
+
* Filter to links whose target is not a frozen document (plan 0406) — a frozen
|
|
59
|
+
* record is history and cannot be edited to answer. Pass the options you pass
|
|
60
|
+
* `beLinkedBack()`, so the two resolve a link the same way. Every other target
|
|
61
|
+
* is kept, and examined.
|
|
62
|
+
*/
|
|
63
|
+
haveLiveTargets(options?: LinkResolveOptions): this;
|
|
64
|
+
/**
|
|
65
|
+
* Condition: each link's target links back to the link's document (plan 0406).
|
|
66
|
+
* Any link back answers; several are one answer, and an incidental mention
|
|
67
|
+
* counts. A target that cannot answer — frozen, outside the corpus, missing, a
|
|
68
|
+
* directory, the record itself, an external URL — is one finding naming its
|
|
69
|
+
* cause, with its remedy as the suggestion. Takes the options `resolve()`
|
|
70
|
+
* takes, so a corpus with extensionless links resolves both ends the same way.
|
|
71
|
+
*/
|
|
72
|
+
beLinkedBack(options?: LinkResolveOptions): this;
|
|
73
|
+
/**
|
|
74
|
+
* The base result, plus findings about the declarations themselves (plan
|
|
75
|
+
* 0405). The base evidence passes through unchanged: the declarations' scan
|
|
76
|
+
* examines nothing the rule asserts over, so it must not raise `examined`
|
|
77
|
+
* (which would hide the zero-examined finding when every declaration is
|
|
78
|
+
* misspelt) and must not go through `mergeCollectResults`, whose dead-member
|
|
79
|
+
* rule would read an empty findings part as a dead rule on every clean run.
|
|
80
|
+
*/
|
|
81
|
+
protected collectViolations(): CollectResult;
|
|
23
82
|
}
|
|
24
83
|
/** Entry point: build rules over the corpus's markdown links. */
|
|
25
84
|
export declare function links(corpus: Corpus): LinkRuleBuilder;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../../src/builders/links.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAkB,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../../src/builders/links.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiB,KAAK,aAAa,EAAkB,MAAM,kBAAkB,CAAA;AACjG,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAgB,KAAK,MAAM,EAAkB,MAAM,mBAAmB,CAAA;AAE7E,OAAO,EAAgB,KAAK,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAUhF,YAAY,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAElE,sEAAsE;AACtE,YAAY,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAW/C;;GAEG;AACH,qBAAa,eAAgB,SAAQ,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC;IAC9D,0FAA0F;IAC1F,OAAO,CAAC,aAAa,CAAiC;IAEtD,SAAS,CAAC,WAAW,IAAI,MAAM,EAAE;IAIjC,8DAA8D;IAC9D,WAAW,IAAI,IAAI;IAInB,iFAAiF;IACjF,WAAW,IAAI,IAAI;IAInB;;;;;;;;;;;;;;;;OAgBG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAOhC;;;;;OAKG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAOzC;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAQzB;;;;OAIG;IACH,OAAO,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,IAAI;IAI3C;;;;;OAKG;IACH,eAAe,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,IAAI;IAInD;;;;;;;OAOG;IACH,YAAY,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,IAAI;IAIhD;;;;;;;OAOG;cACgB,iBAAiB,IAAI,aAAa;CAWtD;AAED,iEAAiE;AACjE,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,CAErD"}
|
package/dist/builders/links.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import { RuleBuilder } from '@nielspeter/eess';
|
|
1
|
+
import { RuleBuilder, collectResult } from '@nielspeter/eess';
|
|
2
2
|
import { collectLinks } from '../model/links.js';
|
|
3
3
|
import { stampedByDocument } from '../model/by-document.js';
|
|
4
4
|
import { linkResolves } from '../conditions/resolve.js';
|
|
5
|
+
import { linkedBack } from '../conditions/linked-back.js';
|
|
6
|
+
import { haveLiveTargetsPredicate } from '../predicates/live-target.js';
|
|
7
|
+
import { areInSectionPredicate, areLabelledPredicate } from '../predicates/declared-block.js';
|
|
8
|
+
import { declarationFindings, declarationKey, } from './declaration-findings.js';
|
|
5
9
|
const areInternal = () => ({
|
|
6
10
|
description: 'are internal',
|
|
7
11
|
test: (l) => !l.external,
|
|
@@ -14,6 +18,8 @@ const areExternal = () => ({
|
|
|
14
18
|
* Rule builder over the corpus's markdown links.
|
|
15
19
|
*/
|
|
16
20
|
export class LinkRuleBuilder extends RuleBuilder {
|
|
21
|
+
/** What `areLabelled()`/`areInSection()` declared, for the near-miss scan (plan 0405). */
|
|
22
|
+
_declarations = [];
|
|
17
23
|
getElements() {
|
|
18
24
|
return stampedByDocument(this.project, (doc) => collectLinks(doc.root, doc.text));
|
|
19
25
|
}
|
|
@@ -25,6 +31,54 @@ export class LinkRuleBuilder extends RuleBuilder {
|
|
|
25
31
|
areExternal() {
|
|
26
32
|
return this.addPredicate(areExternal());
|
|
27
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Filter to links declared under `label` (plan 0405), in any of the ledger's
|
|
36
|
+
* forms (`**Label:**`, `**Label**:`, `__Label__:`, `Label:`), matched exactly
|
|
37
|
+
* and case-sensitively. A link is under the label when it sits in the block the
|
|
38
|
+
* label opens, in that block's nested lists, or — for a label alone on its line
|
|
39
|
+
* — in the lists directly after it. The nearest label decides: walking out from
|
|
40
|
+
* the link, the first block that is the label, or opens with a wrapped label of
|
|
41
|
+
* its own, settles it; a plain line that is not the label settles nothing.
|
|
42
|
+
*
|
|
43
|
+
* The rule also reports, over the whole corpus, what it cannot read: a wrapped
|
|
44
|
+
* label that misses the declared one only by case or spacing, a different
|
|
45
|
+
* wrapped label inside the declaration, the label where no block starts, a
|
|
46
|
+
* declaration holding reference-style links, and a wrapped declaration with
|
|
47
|
+
* nothing under it. That check
|
|
48
|
+
* runs through this method only: a selection taken with `.select()` carries no
|
|
49
|
+
* findings, so it carries no such check either.
|
|
50
|
+
*/
|
|
51
|
+
areLabelled(label) {
|
|
52
|
+
return this.addPredicate(areLabelledPredicate(label)).recordDeclaration({
|
|
53
|
+
kind: 'label',
|
|
54
|
+
label,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Filter to links under a heading matching `name` — a string exactly, or a
|
|
59
|
+
* `RegExp` — at any depth beneath it, matched the way `haveSection()` matches
|
|
60
|
+
* (plan 0405). A heading that misses a string `name` only by case or spacing
|
|
61
|
+
* is reported, as for `areLabelled()`.
|
|
62
|
+
*/
|
|
63
|
+
areInSection(name) {
|
|
64
|
+
return this.addPredicate(areInSectionPredicate(name)).recordDeclaration({
|
|
65
|
+
kind: 'section',
|
|
66
|
+
name,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Record a declaration once; declaring the same label twice scans it once.
|
|
71
|
+
* Called on the copy `addPredicate()` returns, and it replaces the array rather
|
|
72
|
+
* than pushing into it, so a fork never shares its parent's declarations — the
|
|
73
|
+
* kernel's shallow `copy()` is enough.
|
|
74
|
+
*/
|
|
75
|
+
recordDeclaration(d) {
|
|
76
|
+
const key = declarationKey(d);
|
|
77
|
+
if (!this._declarations.some((x) => declarationKey(x) === key)) {
|
|
78
|
+
this._declarations = [...this._declarations, d];
|
|
79
|
+
}
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
28
82
|
/**
|
|
29
83
|
* Condition: internal links resolve to an existing repo file. Static-site
|
|
30
84
|
* corpora with extensionless links pass `tryExtensions`/`tryIndex`, e.g.
|
|
@@ -33,6 +87,43 @@ export class LinkRuleBuilder extends RuleBuilder {
|
|
|
33
87
|
resolve(options) {
|
|
34
88
|
return this.addCondition(linkResolves(this.project, options));
|
|
35
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Filter to links whose target is not a frozen document (plan 0406) — a frozen
|
|
92
|
+
* record is history and cannot be edited to answer. Pass the options you pass
|
|
93
|
+
* `beLinkedBack()`, so the two resolve a link the same way. Every other target
|
|
94
|
+
* is kept, and examined.
|
|
95
|
+
*/
|
|
96
|
+
haveLiveTargets(options) {
|
|
97
|
+
return this.addPredicate(haveLiveTargetsPredicate(this.project, options));
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Condition: each link's target links back to the link's document (plan 0406).
|
|
101
|
+
* Any link back answers; several are one answer, and an incidental mention
|
|
102
|
+
* counts. A target that cannot answer — frozen, outside the corpus, missing, a
|
|
103
|
+
* directory, the record itself, an external URL — is one finding naming its
|
|
104
|
+
* cause, with its remedy as the suggestion. Takes the options `resolve()`
|
|
105
|
+
* takes, so a corpus with extensionless links resolves both ends the same way.
|
|
106
|
+
*/
|
|
107
|
+
beLinkedBack(options) {
|
|
108
|
+
return this.addCondition(linkedBack(this.project, options));
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The base result, plus findings about the declarations themselves (plan
|
|
112
|
+
* 0405). The base evidence passes through unchanged: the declarations' scan
|
|
113
|
+
* examines nothing the rule asserts over, so it must not raise `examined`
|
|
114
|
+
* (which would hide the zero-examined finding when every declaration is
|
|
115
|
+
* misspelt) and must not go through `mergeCollectResults`, whose dead-member
|
|
116
|
+
* rule would read an empty findings part as a dead rule on every clean run.
|
|
117
|
+
*/
|
|
118
|
+
collectViolations() {
|
|
119
|
+
const base = super.collectViolations();
|
|
120
|
+
if (this._declarations.length === 0)
|
|
121
|
+
return base;
|
|
122
|
+
const findings = declarationFindings(this.project, this._declarations, this.buildConditionContext());
|
|
123
|
+
if (findings.length === 0)
|
|
124
|
+
return base;
|
|
125
|
+
return collectResult([...base, ...findings], base);
|
|
126
|
+
}
|
|
36
127
|
}
|
|
37
128
|
/** Entry point: build rules over the corpus's markdown links. */
|
|
38
129
|
export function links(corpus) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"links.js","sourceRoot":"","sources":["../../src/builders/links.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"links.js","sourceRoot":"","sources":["../../src/builders/links.ts"],"names":[],"mappings":"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"}
|