@timiagama/ecr 0.0.1 → 0.1.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/LICENSE +202 -0
- package/NOTICE +16 -0
- package/README.md +411 -7
- package/dist/bin.d.ts +20 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +26 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli/corpus-loader.d.ts +198 -0
- package/dist/cli/corpus-loader.d.ts.map +1 -0
- package/dist/cli/corpus-loader.js +351 -0
- package/dist/cli/corpus-loader.js.map +1 -0
- package/dist/cli/corpus-statistics.d.ts +113 -0
- package/dist/cli/corpus-statistics.d.ts.map +1 -0
- package/dist/cli/corpus-statistics.js +119 -0
- package/dist/cli/corpus-statistics.js.map +1 -0
- package/dist/cli/diagnostic-reporter.d.ts +103 -0
- package/dist/cli/diagnostic-reporter.d.ts.map +1 -0
- package/dist/cli/diagnostic-reporter.js +254 -0
- package/dist/cli/diagnostic-reporter.js.map +1 -0
- package/dist/cli/project-ignore.d.ts +113 -0
- package/dist/cli/project-ignore.d.ts.map +1 -0
- package/dist/cli/project-ignore.js +199 -0
- package/dist/cli/project-ignore.js.map +1 -0
- package/dist/cli/safe-text.d.ts +25 -0
- package/dist/cli/safe-text.d.ts.map +1 -0
- package/dist/cli/safe-text.js +34 -0
- package/dist/cli/safe-text.js.map +1 -0
- package/dist/cli/supervisor.d.ts +108 -0
- package/dist/cli/supervisor.d.ts.map +1 -0
- package/dist/cli/supervisor.js +139 -0
- package/dist/cli/supervisor.js.map +1 -0
- package/dist/cli.d.ts +247 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +591 -0
- package/dist/cli.js.map +1 -0
- package/dist/corpus-validator.d.ts +183 -0
- package/dist/corpus-validator.d.ts.map +1 -0
- package/dist/corpus-validator.js +479 -0
- package/dist/corpus-validator.js.map +1 -0
- package/dist/document-identity-rule.d.ts +198 -0
- package/dist/document-identity-rule.d.ts.map +1 -0
- package/dist/document-identity-rule.js +244 -0
- package/dist/document-identity-rule.js.map +1 -0
- package/dist/ecr.d.ts +103 -0
- package/dist/ecr.d.ts.map +1 -0
- package/dist/ecr.js +216 -0
- package/dist/ecr.js.map +1 -0
- package/dist/glob-pattern.d.ts +94 -0
- package/dist/glob-pattern.d.ts.map +1 -0
- package/dist/glob-pattern.js +188 -0
- package/dist/glob-pattern.js.map +1 -0
- package/dist/heading-source-form.d.ts +77 -0
- package/dist/heading-source-form.d.ts.map +1 -0
- package/dist/heading-source-form.js +129 -0
- package/dist/heading-source-form.js.map +1 -0
- package/dist/identifier-grammar.d.ts +212 -0
- package/dist/identifier-grammar.d.ts.map +1 -0
- package/dist/identifier-grammar.js +273 -0
- package/dist/identifier-grammar.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/inline-reference-rule.d.ts +557 -0
- package/dist/inline-reference-rule.d.ts.map +1 -0
- package/dist/inline-reference-rule.js +802 -0
- package/dist/inline-reference-rule.js.map +1 -0
- package/dist/meta-documents.d.ts +91 -0
- package/dist/meta-documents.d.ts.map +1 -0
- package/dist/meta-documents.js +133 -0
- package/dist/meta-documents.js.map +1 -0
- package/dist/per-document-visitor.d.ts +510 -0
- package/dist/per-document-visitor.d.ts.map +1 -0
- package/dist/per-document-visitor.js +1032 -0
- package/dist/per-document-visitor.js.map +1 -0
- package/dist/references-section-rule.d.ts +482 -0
- package/dist/references-section-rule.d.ts.map +1 -0
- package/dist/references-section-rule.js +777 -0
- package/dist/references-section-rule.js.map +1 -0
- package/dist/section-hierarchy-rule.d.ts +299 -0
- package/dist/section-hierarchy-rule.d.ts.map +1 -0
- package/dist/section-hierarchy-rule.js +482 -0
- package/dist/section-hierarchy-rule.js.map +1 -0
- package/dist/source-alignment.d.ts +41 -0
- package/dist/source-alignment.d.ts.map +1 -0
- package/dist/source-alignment.js +166 -0
- package/dist/source-alignment.js.map +1 -0
- package/dist/source-lines.d.ts +69 -0
- package/dist/source-lines.d.ts.map +1 -0
- package/dist/source-lines.js +104 -0
- package/dist/source-lines.js.map +1 -0
- package/dist/spec-version.d.ts +19 -0
- package/dist/spec-version.d.ts.map +1 -0
- package/dist/spec-version.js +19 -0
- package/dist/spec-version.js.map +1 -0
- package/dist/types.d.ts +219 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -0
- package/examples/docs/0. Orientation/0.0 - System Overview.md +34 -0
- package/examples/docs/0. Orientation/0.0.1 - Glossary.md +21 -0
- package/examples/docs/0. Orientation/0.0.2 - Quality Gates.md +22 -0
- package/examples/docs/3. Ingestion/3.1 - Ingestion - Validation Rules.md +33 -0
- package/examples/docs/4. Payments/4.10 - Settlement.md +22 -0
- package/examples/docs/4. Payments/4.2 - Payment Processing Contract.md +33 -0
- package/examples/docs/8. Orchestration/8.1 - Workflow Orchestration Contract.md +38 -0
- package/examples/docs/8. Orchestration/8.1.3 - Retry Policy.md +17 -0
- package/examples/docs/8. Orchestration/8.10 - Dead Letter Queue.md +20 -0
- package/examples/docs/README.md +7 -0
- package/package.json +65 -7
- package/protocol/navigation-protocol.md +223 -0
- package/spec/v2/1 - ECR - Structural Specification.md +1467 -0
- package/spec/v2/2 - ECR - User Guide.md +845 -0
- package/spec/v2/3 - Design Rationale - The Section Separator.md +243 -0
- package/src/bin.ts +30 -0
- package/src/cli/corpus-loader.ts +482 -0
- package/src/cli/corpus-statistics.ts +196 -0
- package/src/cli/diagnostic-reporter.ts +344 -0
- package/src/cli/project-ignore.ts +238 -0
- package/src/cli/safe-text.ts +39 -0
- package/src/cli/supervisor.ts +204 -0
- package/src/cli.ts +836 -0
- package/src/corpus-validator.ts +642 -0
- package/src/document-identity-rule.ts +422 -0
- package/src/ecr.ts +298 -0
- package/src/glob-pattern.ts +242 -0
- package/src/heading-source-form.ts +173 -0
- package/src/identifier-grammar.ts +380 -0
- package/src/index.ts +78 -0
- package/src/inline-reference-rule.ts +1235 -0
- package/src/meta-documents.ts +159 -0
- package/src/per-document-visitor.ts +1528 -0
- package/src/references-section-rule.ts +1182 -0
- package/src/section-hierarchy-rule.ts +705 -0
- package/src/source-alignment.ts +209 -0
- package/src/source-lines.ts +123 -0
- package/src/spec-version.ts +19 -0
- package/src/types.ts +267 -0
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-Document Visitor
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates all four ECR rules (ECR101--ECR104) over a single Markdown
|
|
5
|
+
* document, producing a composite {@link LintResult}.
|
|
6
|
+
*
|
|
7
|
+
* This is the integration layer that:
|
|
8
|
+
* 1. Parses Markdown text into an AST using `unified` + `remark-parse`
|
|
9
|
+
* 2. Walks the AST and dispatches nodes to the appropriate rules
|
|
10
|
+
* 3. Manages the rule initialisation dependency chain:
|
|
11
|
+
* - ECR101 must complete before ECR102/ECR103 can start
|
|
12
|
+
* - ECR103 must complete before ECR104 can start (to provide declared DocIDs)
|
|
13
|
+
* - If ECR101 fails, downstream rules are skipped entirely
|
|
14
|
+
* 4. Filters text nodes: excludes those inside `code`, `inlineCode`, `html`,
|
|
15
|
+
* or link URL contexts before feeding to ECR104
|
|
16
|
+
* 5. Tracks the current section context (heading identifier) for ECR104
|
|
17
|
+
* 6. Feeds list items within the References section to ECR103
|
|
18
|
+
* 7. Finalises all rules and assembles the composite {@link LintResult}
|
|
19
|
+
*
|
|
20
|
+
* Spec references:
|
|
21
|
+
* - 1#8 -- Visitor and State Model
|
|
22
|
+
* - 1#11.1 -- Pass 1: Per-Document Parse, Validate, Extract
|
|
23
|
+
* - 1#9.3 -- Document Identity Rule [ECR101]
|
|
24
|
+
* - 1#9.4 -- Section Structure Rules [ECR102]
|
|
25
|
+
* - 1#9.5 -- Inline Reference Rules [ECR104]
|
|
26
|
+
* - 1#9.6 -- References Section Rules [ECR103]
|
|
27
|
+
* - 1#10.2 -- LintResult
|
|
28
|
+
* - 1#10.4 -- ExtractedDocument
|
|
29
|
+
*/
|
|
30
|
+
import type { LintResult } from './types.js';
|
|
31
|
+
/**
|
|
32
|
+
* Configuration options for constructing a {@link PerDocumentVisitor} instance.
|
|
33
|
+
*/
|
|
34
|
+
export interface PerDocumentVisitorOptions {
|
|
35
|
+
/**
|
|
36
|
+
* The opaque, host-provided URI identifying the document being validated.
|
|
37
|
+
*
|
|
38
|
+
* Passed through to all rules and echoed in the {@link LintResult.input} field.
|
|
39
|
+
*/
|
|
40
|
+
readonly uri: string;
|
|
41
|
+
/**
|
|
42
|
+
* Optional version tag for the document instance.
|
|
43
|
+
*
|
|
44
|
+
* Passed through to the {@link LintResult.input} field. When omitted, the
|
|
45
|
+
* resulting {@link LintInput.version} will be `undefined`.
|
|
46
|
+
*/
|
|
47
|
+
readonly version?: number;
|
|
48
|
+
}
|
|
49
|
+
/** Rule identifier reported when a document cannot be parsed at all. */
|
|
50
|
+
export declare const UNPARSABLE_DOCUMENT_RULE_ID: string;
|
|
51
|
+
/** The `data.cause` of that diagnostic. */
|
|
52
|
+
export declare const UNPARSABLE_DOCUMENT_CAUSE: string;
|
|
53
|
+
/**
|
|
54
|
+
* MDAST node types whose descendant text nodes must be excluded from
|
|
55
|
+
* ECR104 inline reference detection.
|
|
56
|
+
*
|
|
57
|
+
* Per 1#9.5, text nodes inside code blocks, inline code, and HTML
|
|
58
|
+
* elements are not valid candidates for inline reference detection.
|
|
59
|
+
*/
|
|
60
|
+
export declare const EXCLUDED_ANCESTOR_NODE_TYPES: ReadonlySet<string>;
|
|
61
|
+
/**
|
|
62
|
+
* Orchestrates all four ECR rules (ECR101--ECR104) over a single Markdown
|
|
63
|
+
* document and produces a composite {@link LintResult}.
|
|
64
|
+
*
|
|
65
|
+
* The visitor is stateless between calls to {@link lint}. Each invocation
|
|
66
|
+
* produces a fresh result with no side effects on the visitor instance.
|
|
67
|
+
*
|
|
68
|
+
* The visitor creates its own {@link IdentifierGrammar} instance internally
|
|
69
|
+
* and manages the rule initialisation dependency chain:
|
|
70
|
+
* - ECR101 (Document Identity) runs first on all headings
|
|
71
|
+
* - If ECR101 produces a valid DocID, ECR102 (Section Hierarchy) and
|
|
72
|
+
* ECR103 (References Section) are initialised and fed their respective nodes
|
|
73
|
+
* - After ECR103 finalises, the set of declared DocIDs is extracted and
|
|
74
|
+
* used to initialise ECR104 (Inline Reference)
|
|
75
|
+
* - If ECR101 fails (no valid DocID), the result is returned early with
|
|
76
|
+
* `ok=false` and no `extracted` field
|
|
77
|
+
*
|
|
78
|
+
* Usage:
|
|
79
|
+
* ```ts
|
|
80
|
+
* const visitor = new PerDocumentVisitor({
|
|
81
|
+
* uri: 'file:///docs/3.1.md',
|
|
82
|
+
* version: 1,
|
|
83
|
+
* });
|
|
84
|
+
*
|
|
85
|
+
* const result: LintResult = visitor.lint('# 3.1 - My Document\n\n## References\n- 8.1 - ...');
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* const visitor = new PerDocumentVisitor({ uri: 'file:///docs/5.1.md' });
|
|
91
|
+
* const result: LintResult = visitor.lint(markdownText);
|
|
92
|
+
*
|
|
93
|
+
* if (result.ok) {
|
|
94
|
+
* console.log('Document is valid:', result.extracted?.docId);
|
|
95
|
+
* } else {
|
|
96
|
+
* console.log('Diagnostics:', result.diagnostics);
|
|
97
|
+
* }
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
export declare class PerDocumentVisitor {
|
|
101
|
+
/**
|
|
102
|
+
* The opaque, host-provided URI identifying the document being validated.
|
|
103
|
+
*/
|
|
104
|
+
private readonly uri;
|
|
105
|
+
/**
|
|
106
|
+
* Optional version tag for the document instance.
|
|
107
|
+
*/
|
|
108
|
+
private readonly version;
|
|
109
|
+
/**
|
|
110
|
+
* The {@link IdentifierGrammar} instance shared across all rules
|
|
111
|
+
* within a single visitor. Created once during construction.
|
|
112
|
+
*/
|
|
113
|
+
private readonly grammar;
|
|
114
|
+
/**
|
|
115
|
+
* Constructs a new Per-Document Visitor.
|
|
116
|
+
*
|
|
117
|
+
* Creates an internal {@link IdentifierGrammar} instance for use
|
|
118
|
+
* across all rule evaluations performed by this visitor.
|
|
119
|
+
*
|
|
120
|
+
* @param options - Configuration including the document URI and optional version
|
|
121
|
+
*/
|
|
122
|
+
constructor(options: PerDocumentVisitorOptions);
|
|
123
|
+
/**
|
|
124
|
+
* Lints a single Markdown document and produces a composite {@link LintResult}.
|
|
125
|
+
*
|
|
126
|
+
* Each call is stateless: the visitor creates fresh rule instances,
|
|
127
|
+
* parses the Markdown text into an AST, walks the AST to feed nodes
|
|
128
|
+
* to the appropriate rules, finalises all rules, and assembles the result.
|
|
129
|
+
*
|
|
130
|
+
* The orchestration proceeds in phases:
|
|
131
|
+
* 1. Parse the Markdown text into an MDAST {@link MdastRoot} node
|
|
132
|
+
* 2. First pass: walk headings and list items for ECR101, ECR102, ECR103
|
|
133
|
+
* 3. If ECR101 fails (no valid DocID), return early with `ok=false`
|
|
134
|
+
* 4. Second pass: walk text nodes for ECR104 (with ancestor filtering
|
|
135
|
+
* and section context tracking)
|
|
136
|
+
* 5. Assemble the composite {@link LintResult} from all rule results
|
|
137
|
+
*
|
|
138
|
+
* @param markdownText - The raw Markdown text of the document to lint
|
|
139
|
+
* @returns The composite lint result including diagnostics and, when a valid
|
|
140
|
+
* DocID is recovered, extracted structural artefacts
|
|
141
|
+
*/
|
|
142
|
+
lint(markdownText: string): LintResult;
|
|
143
|
+
/**
|
|
144
|
+
* Parses raw Markdown text into an MDAST {@link MdastRoot} node.
|
|
145
|
+
*
|
|
146
|
+
* Uses `unified` with `remark-parse` to produce a standards-compliant
|
|
147
|
+
* MDAST tree with positional metadata attached to all nodes.
|
|
148
|
+
*
|
|
149
|
+
* The `unified().use(remarkParse).parse()` call returns a type that
|
|
150
|
+
* cannot be directly assigned to our local {@link MdastRoot} interface
|
|
151
|
+
* because `mdast` types are not importable as a module specifier in this
|
|
152
|
+
* project. The cast via `unknown` is safe because `remark-parse` always
|
|
153
|
+
* produces an MDAST Root node at runtime.
|
|
154
|
+
*
|
|
155
|
+
* @param markdownText - The raw Markdown text to parse
|
|
156
|
+
* @returns The parsed MDAST root node
|
|
157
|
+
*/
|
|
158
|
+
private parseMarkdown;
|
|
159
|
+
/**
|
|
160
|
+
* Reports a document the parser could not read.
|
|
161
|
+
*
|
|
162
|
+
* The parser walks a document's structure by recursion, inside a package
|
|
163
|
+
* this project does not control, so a deeply nested link label or image
|
|
164
|
+
* description can end the parse with a stack overflow. That must be one
|
|
165
|
+
* document's error, reported like any other, and never a crash that stops
|
|
166
|
+
* a corpus part way and leaves the rest unvalidated.
|
|
167
|
+
*
|
|
168
|
+
* @param error - What the parser threw
|
|
169
|
+
* @returns A failing result carrying one error diagnostic
|
|
170
|
+
*/
|
|
171
|
+
private reportUnparsable;
|
|
172
|
+
/**
|
|
173
|
+
* Executes the first AST traversal pass: headings, sections, and references.
|
|
174
|
+
*
|
|
175
|
+
* This pass walks the AST in document order and:
|
|
176
|
+
* - Feeds every heading node to ECR101 (`DocumentIdentityRule.evaluateHeading`)
|
|
177
|
+
* - Finalises ECR101 to determine whether a valid DocID was recovered
|
|
178
|
+
* - If a valid DocID is recovered:
|
|
179
|
+
* - Registers the root H1 heading with ECR102
|
|
180
|
+
* (`SectionHierarchyRule.registerRootHeading`)
|
|
181
|
+
* - Feeds headings with depth \>= 2 to ECR102
|
|
182
|
+
* (`SectionHierarchyRule.evaluateHeading`)
|
|
183
|
+
* - Feeds all headings to ECR103
|
|
184
|
+
* (`ReferencesSectionRule.evaluateHeading`)
|
|
185
|
+
* - Feeds list items within the References section to ECR103
|
|
186
|
+
* (`ReferencesSectionRule.evaluateListItem`)
|
|
187
|
+
* - Finalises ECR102 and ECR103
|
|
188
|
+
* - If no valid DocID is recovered, ECR102 and ECR103 are skipped
|
|
189
|
+
*
|
|
190
|
+
* The pass is structured so that all heading nodes are collected first
|
|
191
|
+
* for ECR101, then the collected headings are replayed for ECR102 and ECR103.
|
|
192
|
+
*
|
|
193
|
+
* @param root - The parsed MDAST root node
|
|
194
|
+
* @param sourceText - The document's raw Markdown, for the heading source-form check of 1#9.11
|
|
195
|
+
* @returns The intermediate result from the headings and references pass
|
|
196
|
+
*/
|
|
197
|
+
private executeHeadingsAndReferencesPass;
|
|
198
|
+
/**
|
|
199
|
+
* Collects all heading nodes from the AST into the provided array.
|
|
200
|
+
*
|
|
201
|
+
* Walks the AST depth-first in document order, extracting
|
|
202
|
+
* {@link HeadingNodeData} from every node with `type === 'heading'`.
|
|
203
|
+
*
|
|
204
|
+
* @param node - The root of the walk
|
|
205
|
+
* @param headings - The accumulator array for collected heading data
|
|
206
|
+
*/
|
|
207
|
+
private collectHeadings;
|
|
208
|
+
/**
|
|
209
|
+
* Reads a node's plain text: what a reader sees, with the formatting gone.
|
|
210
|
+
*
|
|
211
|
+
* @param node - The node to read
|
|
212
|
+
* @returns Its text, and its descendants' text, in order
|
|
213
|
+
*/
|
|
214
|
+
private static showNodeText;
|
|
215
|
+
/**
|
|
216
|
+
* Puts a node's children on a walk's stack so that they come off it in
|
|
217
|
+
* document order.
|
|
218
|
+
*
|
|
219
|
+
* Every walk over a document's nodes keeps its own stack rather than
|
|
220
|
+
* calling itself, because nesting in Markdown costs the author almost
|
|
221
|
+
* nothing: a few thousand nested blockquotes, or nested bold spans, fit in
|
|
222
|
+
* a few kilobytes, and recursion over them exhausts the call stack and
|
|
223
|
+
* takes the process with it. A stack on the heap has no such limit.
|
|
224
|
+
*
|
|
225
|
+
* @param node - The node whose children are to be walked
|
|
226
|
+
* @param pending - The stack to push onto, from which nodes are taken with `pop`
|
|
227
|
+
*/
|
|
228
|
+
private static pushChildren;
|
|
229
|
+
/**
|
|
230
|
+
* Finds the References section and feeds its placement and entries to ECR103.
|
|
231
|
+
*
|
|
232
|
+
* The `## References` heading is looked for anywhere in the tree, not only
|
|
233
|
+
* among the root's children. A section nested in a blockquote or a list
|
|
234
|
+
* item used to be passed over, so its entries were silently discarded and
|
|
235
|
+
* the document reported as having an empty References section. It is now
|
|
236
|
+
* found, reported as misplaced (1#9.11 rule 3), and its entries still read.
|
|
237
|
+
*
|
|
238
|
+
* The entries are the items of the list that immediately follows the
|
|
239
|
+
* heading, or of a list that opens the container immediately following it
|
|
240
|
+
* -- which is also a placement violation.
|
|
241
|
+
*
|
|
242
|
+
* @param root - The parsed MDAST root node
|
|
243
|
+
* @param referencesSectionRule - The ECR103 rule instance to feed
|
|
244
|
+
*/
|
|
245
|
+
private feedListItemsToReferencesRule;
|
|
246
|
+
/**
|
|
247
|
+
* Finds the list holding the References entries, given the node after the
|
|
248
|
+
* heading: that node itself, or a list opening the container it is, at any
|
|
249
|
+
* depth of nesting.
|
|
250
|
+
*
|
|
251
|
+
* Looking one container deep lost `> > - 8.1 - …`: the list was never
|
|
252
|
+
* found, so its entries were discarded and the section reported as empty.
|
|
253
|
+
*
|
|
254
|
+
* @param next - The node immediately following the `## References` heading
|
|
255
|
+
* @returns The entries' list, or `undefined` when there is none
|
|
256
|
+
*/
|
|
257
|
+
private findReferencesList;
|
|
258
|
+
/**
|
|
259
|
+
* Finds the first `## References` heading in document order, at any depth.
|
|
260
|
+
*
|
|
261
|
+
* @param node - The node to search from
|
|
262
|
+
* @returns The heading and its position among its siblings, or `undefined`
|
|
263
|
+
*/
|
|
264
|
+
private findReferencesSection;
|
|
265
|
+
/**
|
|
266
|
+
* Executes the second AST traversal pass: inline reference detection.
|
|
267
|
+
*
|
|
268
|
+
* This pass walks the AST in document order using a custom recursive
|
|
269
|
+
* traversal that tracks ancestor node types and:
|
|
270
|
+
* - Tracks the current section context (the most recently encountered
|
|
271
|
+
* heading identifier), starting with the DocID before any H2 heading
|
|
272
|
+
* - For each text node encountered, checks whether the node's ancestor
|
|
273
|
+
* chain includes any excluded node types (`code`, `inlineCode`, `html`)
|
|
274
|
+
* - Text nodes whose ancestors include excluded types are skipped
|
|
275
|
+
* - Valid text nodes are fed to ECR104
|
|
276
|
+
* (`InlineReferenceRule.evaluateTextNode`) with the current
|
|
277
|
+
* section context
|
|
278
|
+
* - After traversal, ECR104 is finalised
|
|
279
|
+
*
|
|
280
|
+
* @param root - The parsed MDAST root node
|
|
281
|
+
* @param docId - The document's established DocID
|
|
282
|
+
* @param declaredDocIds - The set of DocIDs declared in the References section
|
|
283
|
+
* @param sourceText - The document's raw Markdown, for the source-form checks of 1#9.11
|
|
284
|
+
* @returns The intermediate result from the inline references pass
|
|
285
|
+
*/
|
|
286
|
+
private executeInlineReferencesPass;
|
|
287
|
+
/**
|
|
288
|
+
* Walks the AST to find inline runs for ECR104, tracking whether an
|
|
289
|
+
* excluded ancestor encloses the node and updating section context when
|
|
290
|
+
* headings are encountered.
|
|
291
|
+
*
|
|
292
|
+
* A paragraph is handed to ECR104 whole, as one inline run, because a
|
|
293
|
+
* citation is recognised in the text a reader sees and not one parsed text
|
|
294
|
+
* node at a time (1#9.5 rule 1). Its children are not walked separately.
|
|
295
|
+
*
|
|
296
|
+
* A hand-written depth-first, pre-order walk over an explicit stack: document
|
|
297
|
+
* order decides which section each run belongs to, and see
|
|
298
|
+
* {@link PerDocumentVisitor.pushChildren} for why the stack is not the call
|
|
299
|
+
* stack. Exclusion is carried down as one flag, because a node is excluded
|
|
300
|
+
* exactly when some ancestor's type is, so nothing is gained by keeping the
|
|
301
|
+
* ancestors themselves.
|
|
302
|
+
*
|
|
303
|
+
* @param root - The root of the walk
|
|
304
|
+
* @param sectionContext - Mutable wrapper holding the current section context
|
|
305
|
+
* @param inlineReferenceRule - The ECR104 rule instance to feed runs to
|
|
306
|
+
*/
|
|
307
|
+
private walkNodesForInlineReferences;
|
|
308
|
+
/**
|
|
309
|
+
* Puts a node's children on the inline walk's stack, in document order,
|
|
310
|
+
* noting whether an excluded ancestor now encloses them.
|
|
311
|
+
*
|
|
312
|
+
* @param node - The node whose children are to be walked
|
|
313
|
+
* @param excluded - Whether an excluded ancestor already encloses the node
|
|
314
|
+
* @param pending - The stack to push onto
|
|
315
|
+
*/
|
|
316
|
+
private static pushInlineWalkChildren;
|
|
317
|
+
/**
|
|
318
|
+
* Flattens one inline node into the segments a reader sees, in order.
|
|
319
|
+
*
|
|
320
|
+
* Text becomes a `text` segment carrying its position, and inline code a
|
|
321
|
+
* `code` segment. Formatting contributes its contents, each segment noting
|
|
322
|
+
* the spans around it. A hard break, an image, and a `<br>` tag become a
|
|
323
|
+
* `break` of one space, because a reader sees the words either side of them
|
|
324
|
+
* as separate. Any other inline HTML -- a comment, or a tag such as
|
|
325
|
+
* `<span>` -- contributes nothing, because it separates nothing:
|
|
326
|
+
* `60<span>s</span>` reads as `60s`.
|
|
327
|
+
*
|
|
328
|
+
* @param node - An inline node
|
|
329
|
+
* @param wrappers - Types of the formatting spans enclosing it, outermost first
|
|
330
|
+
* @param segments - Accumulator the segments are appended to
|
|
331
|
+
*/
|
|
332
|
+
private collectInlineSegments;
|
|
333
|
+
/**
|
|
334
|
+
* Turns one inline node into segments, or puts its children on the stack
|
|
335
|
+
* to be turned into segments in their turn.
|
|
336
|
+
*
|
|
337
|
+
* @param entry - The node and the formatting spans enclosing it
|
|
338
|
+
* @param segments - Accumulator the segments are appended to
|
|
339
|
+
* @param pending - The walk's stack, which children are pushed onto in document order
|
|
340
|
+
*/
|
|
341
|
+
private collectInlineSegment;
|
|
342
|
+
/**
|
|
343
|
+
* Determines the current section context identifier for a given heading.
|
|
344
|
+
*
|
|
345
|
+
* The section context is the identifier (DocID or SectionID) of the most
|
|
346
|
+
* recently encountered numbered heading. Before any H2 heading, the context
|
|
347
|
+
* is the DocID. After an H2 or deeper heading, the context is the
|
|
348
|
+
* SectionID of that heading.
|
|
349
|
+
*
|
|
350
|
+
* This method extracts the identifier from the heading text using the
|
|
351
|
+
* grammar's separator convention. If the heading text does not contain
|
|
352
|
+
* a valid identifier, the previous context is retained.
|
|
353
|
+
*
|
|
354
|
+
* @param headingText - The plain text content of the heading node
|
|
355
|
+
* @param headingDepth - The Markdown heading depth (1--6)
|
|
356
|
+
* @param currentContext - The current section context before this heading
|
|
357
|
+
* @returns The updated section context identifier
|
|
358
|
+
*/
|
|
359
|
+
private determineSectionContext;
|
|
360
|
+
/**
|
|
361
|
+
* Determines whether a heading is the `## References` structural heading.
|
|
362
|
+
*
|
|
363
|
+
* The `## References` heading is owned by ECR103 and should not be
|
|
364
|
+
* evaluated by ECR102 (Section Hierarchy), because it is not a numbered
|
|
365
|
+
* section heading and would fail SectionID parsing.
|
|
366
|
+
*
|
|
367
|
+
* Per 1#9.6, the References heading is identified by depth === 2
|
|
368
|
+
* and text content exactly equal to `"References"`.
|
|
369
|
+
*
|
|
370
|
+
* @param headingData - The heading node data to check
|
|
371
|
+
* @returns `true` if the heading is the `## References` heading, `false` otherwise
|
|
372
|
+
*/
|
|
373
|
+
private tellReferencesHeading;
|
|
374
|
+
/**
|
|
375
|
+
* Extracts the plain text content from a list item AST node.
|
|
376
|
+
*
|
|
377
|
+
* Gathers the text of the list item's child nodes into a single plain text
|
|
378
|
+
* string suitable for feeding to ECR103.
|
|
379
|
+
*
|
|
380
|
+
* @param listItemNode - The MDAST list item node to extract text from
|
|
381
|
+
* @returns The extracted {@link ListItemNodeData} with text and optional range
|
|
382
|
+
*/
|
|
383
|
+
private extractListItemNodeData;
|
|
384
|
+
/**
|
|
385
|
+
* Classifies a literal node for tracing its text back to the source.
|
|
386
|
+
*
|
|
387
|
+
* @param type - The node's MDAST type
|
|
388
|
+
* @returns `text` for a text node, `code` for inline code, `other` otherwise
|
|
389
|
+
*/
|
|
390
|
+
private static showSegmentKind;
|
|
391
|
+
/**
|
|
392
|
+
* Splits a list item's text into the parsed nodes it comes from.
|
|
393
|
+
*
|
|
394
|
+
* Follows `mdast-util-to-string` exactly -- a node's `value`, else an
|
|
395
|
+
* image's `alt`, else its children in order -- so that joining the
|
|
396
|
+
* segments reproduces the entry text the rule parses, and an offset in that
|
|
397
|
+
* text identifies the node, and so the source, it came from.
|
|
398
|
+
*
|
|
399
|
+
* @param node - A node within the list item
|
|
400
|
+
* @param segments - Accumulator the segments are appended to
|
|
401
|
+
*/
|
|
402
|
+
private collectListItemSegments;
|
|
403
|
+
/**
|
|
404
|
+
* Extracts heading node data from an MDAST heading node.
|
|
405
|
+
*
|
|
406
|
+
* Reads the plain text content with {@link PerDocumentVisitor.showNodeText}
|
|
407
|
+
* and maps the MDAST position to a {@link HeadingNodeData} structure
|
|
408
|
+
* suitable for consumption by ECR101, ECR102, and ECR103.
|
|
409
|
+
*
|
|
410
|
+
* @param headingNode - The MDAST heading node to extract data from
|
|
411
|
+
* @returns The extracted {@link HeadingNodeData} with depth, text, and optional range
|
|
412
|
+
*/
|
|
413
|
+
private extractHeadingNodeData;
|
|
414
|
+
/**
|
|
415
|
+
* Extracts text node data from an MDAST text node.
|
|
416
|
+
*
|
|
417
|
+
* Maps the MDAST text node's value and position to a {@link TextNodeData}
|
|
418
|
+
* structure suitable for consumption by ECR104.
|
|
419
|
+
*
|
|
420
|
+
* @param textNode - The MDAST text node to extract data from
|
|
421
|
+
* @returns The extracted {@link TextNodeData} with text and optional range
|
|
422
|
+
*/
|
|
423
|
+
private extractTextNodeData;
|
|
424
|
+
/**
|
|
425
|
+
* Extracts the set of declared DocIDs from a completed ECR103 result.
|
|
426
|
+
*
|
|
427
|
+
* Iterates over the extracted {@link ReferenceEdge} artefacts and
|
|
428
|
+
* collects the `toDocId` field from each edge into a `ReadonlySet<DocID>`.
|
|
429
|
+
* This set is used to initialise ECR104 for undeclared reference detection.
|
|
430
|
+
*
|
|
431
|
+
* @param references - The extracted reference edges from ECR103
|
|
432
|
+
* @returns The set of declared DocIDs
|
|
433
|
+
*/
|
|
434
|
+
private extractDeclaredDocIds;
|
|
435
|
+
/**
|
|
436
|
+
* Maps an MDAST position to a {@link PositionRange}, if available.
|
|
437
|
+
*
|
|
438
|
+
* MDAST positions use 1-based lines and 1-based columns, while
|
|
439
|
+
* {@link PositionRange} uses 0-based lines and 0-based characters.
|
|
440
|
+
* This method performs the conversion.
|
|
441
|
+
*
|
|
442
|
+
* @param mdastPosition - The MDAST position object, or `undefined` if
|
|
443
|
+
* positional metadata is not available
|
|
444
|
+
* @returns The mapped position range, or `undefined` if no position is available
|
|
445
|
+
*/
|
|
446
|
+
private mapPosition;
|
|
447
|
+
/**
|
|
448
|
+
* Assembles the composite {@link LintResult} from individual rule results.
|
|
449
|
+
*
|
|
450
|
+
* Aggregates diagnostics from all rules, determines the `ok` status
|
|
451
|
+
* (true when no error-severity diagnostics are present), and constructs
|
|
452
|
+
* the {@link ExtractedDocument} when a valid DocID was recovered.
|
|
453
|
+
*
|
|
454
|
+
* @param identityResult - The result from ECR101
|
|
455
|
+
* @param sectionsResult - The result from ECR102 (undefined if ECR101 failed)
|
|
456
|
+
* @param referencesResult - The result from ECR103 (undefined if ECR101 failed)
|
|
457
|
+
* @param inlineResult - The result from ECR104 (undefined if ECR101 failed)
|
|
458
|
+
* @returns The composite lint result
|
|
459
|
+
*/
|
|
460
|
+
private assembleLintResult;
|
|
461
|
+
/**
|
|
462
|
+
* Aggregates diagnostics from all rule results into a single array.
|
|
463
|
+
*
|
|
464
|
+
* Collects diagnostics from ECR101, ECR102, ECR103, and ECR104 in that
|
|
465
|
+
* order. Rules that did not run (undefined results) contribute no
|
|
466
|
+
* diagnostics.
|
|
467
|
+
*
|
|
468
|
+
* @param identityResult - The result from ECR101
|
|
469
|
+
* @param sectionsResult - The result from ECR102 (undefined if ECR101 failed)
|
|
470
|
+
* @param referencesResult - The result from ECR103 (undefined if ECR101 failed)
|
|
471
|
+
* @param inlineResult - The result from ECR104 (undefined if ECR101 failed)
|
|
472
|
+
* @returns The aggregated array of all diagnostics
|
|
473
|
+
*/
|
|
474
|
+
private aggregateDiagnostics;
|
|
475
|
+
/**
|
|
476
|
+
* Constructs the {@link LintInput} descriptor for the result.
|
|
477
|
+
*
|
|
478
|
+
* Echoes the visitor's URI and optional version into the standard
|
|
479
|
+
* input descriptor shape.
|
|
480
|
+
*
|
|
481
|
+
* @returns The lint input descriptor
|
|
482
|
+
*/
|
|
483
|
+
private buildLintInput;
|
|
484
|
+
/**
|
|
485
|
+
* Determines the composite `ok` status from an aggregated diagnostics array.
|
|
486
|
+
*
|
|
487
|
+
* The result is `ok` (true) when no diagnostics have severity `"error"`.
|
|
488
|
+
* Any error-severity diagnostic causes the result to be not-ok (false).
|
|
489
|
+
*
|
|
490
|
+
* @param diagnostics - The full array of aggregated diagnostics from all rules
|
|
491
|
+
* @returns `true` if no error diagnostics are present, `false` otherwise
|
|
492
|
+
*/
|
|
493
|
+
private tellAllDiagnosticsPassable;
|
|
494
|
+
/**
|
|
495
|
+
* Constructs the {@link ExtractedDocument} from individual rule extraction
|
|
496
|
+
* results.
|
|
497
|
+
*
|
|
498
|
+
* Assembles the document identity (DocID and title), section nodes,
|
|
499
|
+
* reference edges, and inline reference edges into the canonical
|
|
500
|
+
* extracted document shape.
|
|
501
|
+
*
|
|
502
|
+
* @param identity - The document identity from ECR101
|
|
503
|
+
* @param sections - The section nodes from ECR102
|
|
504
|
+
* @param references - The reference edges from ECR103
|
|
505
|
+
* @param inlineReferences - The inline reference edges from ECR104
|
|
506
|
+
* @returns The assembled extracted document
|
|
507
|
+
*/
|
|
508
|
+
private buildExtractedDocument;
|
|
509
|
+
}
|
|
510
|
+
//# sourceMappingURL=per-document-visitor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"per-document-visitor.d.ts","sourceRoot":"","sources":["../src/per-document-visitor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAaH,OAAO,KAAK,EAMV,UAAU,EAKX,MAAM,YAAY,CAAC;AA6EpB;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAErB;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AA6CD,wEAAwE;AACxE,eAAO,MAAM,2BAA2B,EAAE,MAA8B,CAAC;AAEzE,2CAA2C;AAC3C,eAAO,MAAM,yBAAyB,EAAE,MAA8B,CAAC;AASvE;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,EAAE,WAAW,CAAC,MAAM,CAI3D,CAAC;AAiGH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,qBAAa,kBAAkB;IAC7B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAE7B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAE7C;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAE5C;;;;;;;OAOG;gBACgB,OAAO,EAAE,yBAAyB;IAMrD;;;;;;;;;;;;;;;;;;OAkBG;IACI,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,UAAU;IAqD7C;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,aAAa;IAOrB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,gBAAgB;IA0BxB;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,OAAO,CAAC,gCAAgC;IA4ExC;;;;;;;;OAQG;IACH,OAAO,CAAC,eAAe;IAqBvB;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,YAAY;IAgC3B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,MAAM,CAAC,YAAY;IAgB3B;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,6BAA6B;IA8BrC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,kBAAkB;IAc1B;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;IAsC7B;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,OAAO,CAAC,2BAA2B;IAkCnC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,OAAO,CAAC,4BAA4B;IAyDpC;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAsBrC;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,qBAAqB;IAkB7B;;;;;;;OAOG;IACH,OAAO,CAAC,oBAAoB;IAiD5B;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,uBAAuB;IA6B/B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,qBAAqB;IAQ7B;;;;;;;;OAQG;IACH,OAAO,CAAC,uBAAuB;IAoB/B;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,eAAe;IAQ9B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,uBAAuB;IAmC/B;;;;;;;;;OASG;IACH,OAAO,CAAC,sBAAsB;IAoB9B;;;;;;;;OAQG;IACH,OAAO,CAAC,mBAAmB;IAkB3B;;;;;;;;;OASG;IACH,OAAO,CAAC,qBAAqB;IAgB7B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,WAAW;IAyBnB;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,kBAAkB;IAiD1B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,oBAAoB;IAiC5B;;;;;;;OAOG;IACH,OAAO,CAAC,cAAc;IAStB;;;;;;;;OAQG;IACH,OAAO,CAAC,0BAA0B;IAQlC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,sBAAsB;CAgB/B"}
|