@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.
Files changed (138) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +16 -0
  3. package/README.md +411 -7
  4. package/dist/bin.d.ts +20 -0
  5. package/dist/bin.d.ts.map +1 -0
  6. package/dist/bin.js +26 -0
  7. package/dist/bin.js.map +1 -0
  8. package/dist/cli/corpus-loader.d.ts +198 -0
  9. package/dist/cli/corpus-loader.d.ts.map +1 -0
  10. package/dist/cli/corpus-loader.js +351 -0
  11. package/dist/cli/corpus-loader.js.map +1 -0
  12. package/dist/cli/corpus-statistics.d.ts +113 -0
  13. package/dist/cli/corpus-statistics.d.ts.map +1 -0
  14. package/dist/cli/corpus-statistics.js +119 -0
  15. package/dist/cli/corpus-statistics.js.map +1 -0
  16. package/dist/cli/diagnostic-reporter.d.ts +103 -0
  17. package/dist/cli/diagnostic-reporter.d.ts.map +1 -0
  18. package/dist/cli/diagnostic-reporter.js +254 -0
  19. package/dist/cli/diagnostic-reporter.js.map +1 -0
  20. package/dist/cli/project-ignore.d.ts +113 -0
  21. package/dist/cli/project-ignore.d.ts.map +1 -0
  22. package/dist/cli/project-ignore.js +199 -0
  23. package/dist/cli/project-ignore.js.map +1 -0
  24. package/dist/cli/safe-text.d.ts +25 -0
  25. package/dist/cli/safe-text.d.ts.map +1 -0
  26. package/dist/cli/safe-text.js +34 -0
  27. package/dist/cli/safe-text.js.map +1 -0
  28. package/dist/cli/supervisor.d.ts +108 -0
  29. package/dist/cli/supervisor.d.ts.map +1 -0
  30. package/dist/cli/supervisor.js +139 -0
  31. package/dist/cli/supervisor.js.map +1 -0
  32. package/dist/cli.d.ts +247 -0
  33. package/dist/cli.d.ts.map +1 -0
  34. package/dist/cli.js +591 -0
  35. package/dist/cli.js.map +1 -0
  36. package/dist/corpus-validator.d.ts +183 -0
  37. package/dist/corpus-validator.d.ts.map +1 -0
  38. package/dist/corpus-validator.js +479 -0
  39. package/dist/corpus-validator.js.map +1 -0
  40. package/dist/document-identity-rule.d.ts +198 -0
  41. package/dist/document-identity-rule.d.ts.map +1 -0
  42. package/dist/document-identity-rule.js +244 -0
  43. package/dist/document-identity-rule.js.map +1 -0
  44. package/dist/ecr.d.ts +103 -0
  45. package/dist/ecr.d.ts.map +1 -0
  46. package/dist/ecr.js +216 -0
  47. package/dist/ecr.js.map +1 -0
  48. package/dist/glob-pattern.d.ts +94 -0
  49. package/dist/glob-pattern.d.ts.map +1 -0
  50. package/dist/glob-pattern.js +188 -0
  51. package/dist/glob-pattern.js.map +1 -0
  52. package/dist/heading-source-form.d.ts +77 -0
  53. package/dist/heading-source-form.d.ts.map +1 -0
  54. package/dist/heading-source-form.js +129 -0
  55. package/dist/heading-source-form.js.map +1 -0
  56. package/dist/identifier-grammar.d.ts +212 -0
  57. package/dist/identifier-grammar.d.ts.map +1 -0
  58. package/dist/identifier-grammar.js +273 -0
  59. package/dist/identifier-grammar.js.map +1 -0
  60. package/dist/index.d.ts +19 -0
  61. package/dist/index.d.ts.map +1 -0
  62. package/dist/index.js +11 -0
  63. package/dist/index.js.map +1 -0
  64. package/dist/inline-reference-rule.d.ts +557 -0
  65. package/dist/inline-reference-rule.d.ts.map +1 -0
  66. package/dist/inline-reference-rule.js +802 -0
  67. package/dist/inline-reference-rule.js.map +1 -0
  68. package/dist/meta-documents.d.ts +91 -0
  69. package/dist/meta-documents.d.ts.map +1 -0
  70. package/dist/meta-documents.js +133 -0
  71. package/dist/meta-documents.js.map +1 -0
  72. package/dist/per-document-visitor.d.ts +510 -0
  73. package/dist/per-document-visitor.d.ts.map +1 -0
  74. package/dist/per-document-visitor.js +1032 -0
  75. package/dist/per-document-visitor.js.map +1 -0
  76. package/dist/references-section-rule.d.ts +482 -0
  77. package/dist/references-section-rule.d.ts.map +1 -0
  78. package/dist/references-section-rule.js +777 -0
  79. package/dist/references-section-rule.js.map +1 -0
  80. package/dist/section-hierarchy-rule.d.ts +299 -0
  81. package/dist/section-hierarchy-rule.d.ts.map +1 -0
  82. package/dist/section-hierarchy-rule.js +482 -0
  83. package/dist/section-hierarchy-rule.js.map +1 -0
  84. package/dist/source-alignment.d.ts +41 -0
  85. package/dist/source-alignment.d.ts.map +1 -0
  86. package/dist/source-alignment.js +166 -0
  87. package/dist/source-alignment.js.map +1 -0
  88. package/dist/source-lines.d.ts +69 -0
  89. package/dist/source-lines.d.ts.map +1 -0
  90. package/dist/source-lines.js +104 -0
  91. package/dist/source-lines.js.map +1 -0
  92. package/dist/spec-version.d.ts +19 -0
  93. package/dist/spec-version.d.ts.map +1 -0
  94. package/dist/spec-version.js +19 -0
  95. package/dist/spec-version.js.map +1 -0
  96. package/dist/types.d.ts +219 -0
  97. package/dist/types.d.ts.map +1 -0
  98. package/dist/types.js +11 -0
  99. package/dist/types.js.map +1 -0
  100. package/examples/docs/0. Orientation/0.0 - System Overview.md +34 -0
  101. package/examples/docs/0. Orientation/0.0.1 - Glossary.md +21 -0
  102. package/examples/docs/0. Orientation/0.0.2 - Quality Gates.md +22 -0
  103. package/examples/docs/3. Ingestion/3.1 - Ingestion - Validation Rules.md +33 -0
  104. package/examples/docs/4. Payments/4.10 - Settlement.md +22 -0
  105. package/examples/docs/4. Payments/4.2 - Payment Processing Contract.md +33 -0
  106. package/examples/docs/8. Orchestration/8.1 - Workflow Orchestration Contract.md +38 -0
  107. package/examples/docs/8. Orchestration/8.1.3 - Retry Policy.md +17 -0
  108. package/examples/docs/8. Orchestration/8.10 - Dead Letter Queue.md +20 -0
  109. package/examples/docs/README.md +7 -0
  110. package/package.json +65 -7
  111. package/protocol/navigation-protocol.md +223 -0
  112. package/spec/v2/1 - ECR - Structural Specification.md +1467 -0
  113. package/spec/v2/2 - ECR - User Guide.md +845 -0
  114. package/spec/v2/3 - Design Rationale - The Section Separator.md +243 -0
  115. package/src/bin.ts +30 -0
  116. package/src/cli/corpus-loader.ts +482 -0
  117. package/src/cli/corpus-statistics.ts +196 -0
  118. package/src/cli/diagnostic-reporter.ts +344 -0
  119. package/src/cli/project-ignore.ts +238 -0
  120. package/src/cli/safe-text.ts +39 -0
  121. package/src/cli/supervisor.ts +204 -0
  122. package/src/cli.ts +836 -0
  123. package/src/corpus-validator.ts +642 -0
  124. package/src/document-identity-rule.ts +422 -0
  125. package/src/ecr.ts +298 -0
  126. package/src/glob-pattern.ts +242 -0
  127. package/src/heading-source-form.ts +173 -0
  128. package/src/identifier-grammar.ts +380 -0
  129. package/src/index.ts +78 -0
  130. package/src/inline-reference-rule.ts +1235 -0
  131. package/src/meta-documents.ts +159 -0
  132. package/src/per-document-visitor.ts +1528 -0
  133. package/src/references-section-rule.ts +1182 -0
  134. package/src/section-hierarchy-rule.ts +705 -0
  135. package/src/source-alignment.ts +209 -0
  136. package/src/source-lines.ts +123 -0
  137. package/src/spec-version.ts +19 -0
  138. package/src/types.ts +267 -0
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Heading Source Form
3
+ *
4
+ * Checks that a heading carrying a DocID or SectionID is written in the one
5
+ * source form the published recipes can find (1#9.11 rule 1): an ATX heading
6
+ * whose line begins with its `#` characters, then exactly one space, then the
7
+ * identifier in literal characters.
8
+ *
9
+ * The Markdown parser accepts far more than that. A setext heading, an
10
+ * indented one, one inside a blockquote, one with a tab or two spaces after
11
+ * the hashes, and one whose identifier is emphasised, escaped or written as a
12
+ * character reference all parse to the same identifier -- and none of them is
13
+ * found by `^# 8\.1[^0-9.#]` or `^#+ 8\.1#3([^0-9]|$)`. So the check reads the
14
+ * heading's own source line and asks the question the recipe asks.
15
+ *
16
+ * It also asks whether that line is a line at all to a search engine. Two
17
+ * things can hide a correctly written heading from `^`: a lone carriage
18
+ * return before it, which Markdown treats as a line ending and the engines do
19
+ * not, and a byte-order mark before the first line, which ripgrep skips and
20
+ * GNU grep does not.
21
+ *
22
+ * Shared by ECR101 (the H1) and ECR102 (every deeper heading).
23
+ */
24
+ import { SourceLines } from './source-lines.js';
25
+ /** The `data.cause` of a heading whose source form no recipe can find. */
26
+ export const HEADING_SOURCE_FORM_CAUSE = 'heading-source-form';
27
+ /** The UTF-8 byte-order mark, as it appears at the start of decoded text. */
28
+ const BYTE_ORDER_MARK = '';
29
+ /**
30
+ * What may follow a DocID on its heading line, per the document recipe
31
+ * `^# 8\.1[^0-9.#]`: anything but a digit, `.` or `#`, so that `8.1` is not
32
+ * found as the start of `8.10`, `8.1.3` or `8.1#3`.
33
+ */
34
+ const AFTER_DOC_ID = /^[^0-9.#]/;
35
+ /**
36
+ * What may follow a SectionID on its heading line, per the section recipe
37
+ * `^#+ 8\.1#3([^0-9]|$)`: anything but a digit, or the end of the line.
38
+ */
39
+ const AFTER_SECTION_ID = /^(?:[^0-9]|$)/;
40
+ /**
41
+ * Tells whether headings are written where the recipes look for them.
42
+ */
43
+ export class HeadingSourceForm {
44
+ /** The document's source, by line; absent when none was supplied. */
45
+ lines;
46
+ /**
47
+ * @param sourceText - The document's raw Markdown. When absent, as in unit
48
+ * tests that supply only parsed heading text, there is
49
+ * no source to consult and every heading passes.
50
+ */
51
+ constructor(sourceText) {
52
+ this.lines = sourceText === undefined ? undefined : new SourceLines(sourceText);
53
+ }
54
+ /**
55
+ * Finds what, if anything, stops the recipe for a heading from finding it.
56
+ *
57
+ * @param range - The heading node's range
58
+ * @param depth - The heading's depth, 1 for the H1
59
+ * @param identifier - The DocID or SectionID parsed from the heading
60
+ * @returns The obstruction, or `undefined` when the recipe would find it
61
+ */
62
+ findObstruction(range, depth, identifier) {
63
+ if (this.lines === undefined || range === undefined) {
64
+ return undefined;
65
+ }
66
+ const lineNumber = range.start.line;
67
+ const line = this.lines.readLine(lineNumber) ?? '';
68
+ // A mark before the first line is reported only when it is what stands
69
+ // in the way: after it, the line must be a correct heading. A mark
70
+ // followed by a newline obstructs nothing, since the H1 then starts a
71
+ // later line, which both engines find.
72
+ if (lineNumber === 0 && line.startsWith(BYTE_ORDER_MARK)) {
73
+ return HeadingSourceForm.tellLineMatches(line.slice(1), depth, identifier)
74
+ ? 'byte-order-mark'
75
+ : 'form';
76
+ }
77
+ if (!HeadingSourceForm.tellLineMatches(line, depth, identifier)) {
78
+ return 'form';
79
+ }
80
+ return this.lines.tellStartsSearchLine(lineNumber) ? undefined : 'lone-carriage-return';
81
+ }
82
+ /**
83
+ * Reports whether a line reads as the recipe for its heading expects.
84
+ *
85
+ * @param line - The heading's source line
86
+ * @param depth - The heading's depth
87
+ * @param identifier - The DocID or SectionID parsed from the heading
88
+ * @returns `true` when the line is `#… identifier` followed by an allowed character
89
+ */
90
+ static tellLineMatches(line, depth, identifier) {
91
+ const prefix = `${'#'.repeat(depth)} ${identifier}`;
92
+ if (!line.startsWith(prefix)) {
93
+ return false;
94
+ }
95
+ const rest = line.slice(prefix.length);
96
+ return depth === 1 ? AFTER_DOC_ID.test(rest) : AFTER_SECTION_ID.test(rest);
97
+ }
98
+ /**
99
+ * The explanation a diagnostic gives for an unnavigable heading.
100
+ *
101
+ * @param obstruction - What stops the recipe from finding it
102
+ * @param depth - The heading's depth
103
+ * @param identifier - The DocID or SectionID parsed from the heading
104
+ * @returns A message naming the obstruction and the fix
105
+ */
106
+ static explain(obstruction, depth, identifier) {
107
+ const hashes = '#'.repeat(depth);
108
+ const opening = `The heading for "${identifier}" is not in the source form the navigation ` +
109
+ `recipes search for, so no search finds it.`;
110
+ switch (obstruction) {
111
+ case 'lone-carriage-return':
112
+ return (`${opening} It follows a lone carriage return (CR) line ending, and search ` +
113
+ `tools start a new line only at a line feed, so to them it is the middle of ` +
114
+ `the line before. Save the file with LF or CRLF line endings.`);
115
+ case 'byte-order-mark':
116
+ // Not `opening`: ripgrep skips the mark and does find this heading.
117
+ return (`The heading for "${identifier}" is not discoverable by every published ` +
118
+ `recipe. The file begins with a UTF-8 byte-order mark, which sits before the ` +
119
+ `heading's # characters; ripgrep skips it, but GNU grep reads it as text there ` +
120
+ `and finds no heading. Save the file as UTF-8 without a byte-order mark.`);
121
+ default:
122
+ return (`${opening} Write it as an ATX heading at the start of its line -- ` +
123
+ `"${hashes} ${identifier} - ..." -- with one space after the # characters ` +
124
+ `and the identifier in literal characters, without formatting, escapes or ` +
125
+ `indentation.`);
126
+ }
127
+ }
128
+ }
129
+ //# sourceMappingURL=heading-source-form.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heading-source-form.js","sourceRoot":"","sources":["../src/heading-source-form.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,212 @@
1
+ /**
2
+ * DocID and SectionID Grammar Parsing & Validation
3
+ *
4
+ * Implements the identifier grammar defined in the ECR specification (1#9.2).
5
+ *
6
+ * Grammar:
7
+ * DocID ::= Digit+ ("." Digit+)*
8
+ * SectionPath ::= Digit+ ("." Digit+)*
9
+ * SectionID ::= DocID "#" SectionPath
10
+ *
11
+ * All operations are deterministic and side-effect-free.
12
+ */
13
+ import type { DocID, SectionID } from './types.js';
14
+ /**
15
+ * Represents the outcome of parsing a string as a DocID.
16
+ *
17
+ * When parsing succeeds, `valid` is `true` and `docId` holds the parsed value.
18
+ * When parsing fails, `valid` is `false`.
19
+ */
20
+ export type DocIdParseResult = {
21
+ readonly valid: true;
22
+ readonly docId: DocID;
23
+ } | {
24
+ readonly valid: false;
25
+ };
26
+ /**
27
+ * Represents the outcome of parsing a string as a SectionID.
28
+ *
29
+ * When parsing succeeds, `valid` is `true`, `sectionId` holds the parsed value,
30
+ * and `docId` holds the DocID prefix that the SectionID extends.
31
+ * When parsing fails, `valid` is `false`.
32
+ */
33
+ export type SectionIdParseResult = {
34
+ readonly valid: true;
35
+ readonly sectionId: SectionID;
36
+ readonly docId: DocID;
37
+ /** The section path following the `#` separator, e.g. `3.1` in `8.1#3.1`. */
38
+ readonly sectionPath: string;
39
+ } | {
40
+ readonly valid: false;
41
+ };
42
+ /**
43
+ * Represents the outcome of extracting a SectionID and title from a sub-heading.
44
+ *
45
+ * When extraction succeeds, `valid` is `true` and both `sectionId` and `title`
46
+ * are present. When it fails, `valid` is `false`.
47
+ */
48
+ export type SectionHeadingParseResult = {
49
+ readonly valid: true;
50
+ readonly sectionId: SectionID;
51
+ readonly title: string;
52
+ } | {
53
+ readonly valid: false;
54
+ };
55
+ /**
56
+ * Represents the outcome of extracting a DocID and title from an H1 heading string.
57
+ *
58
+ * When extraction succeeds, `valid` is `true` and both `docId` and `title` are
59
+ * present. When extraction fails, `valid` is `false`.
60
+ */
61
+ export type HeadingParseResult = {
62
+ readonly valid: true;
63
+ readonly docId: DocID;
64
+ readonly title: string;
65
+ } | {
66
+ readonly valid: false;
67
+ };
68
+ /**
69
+ * Represents the outcome of validating a heading separator.
70
+ *
71
+ * `valid` is `true` when the heading carries a recognisable separator: a
72
+ * hyphen-minus, en dash or em dash after the identifier. When none is found,
73
+ * `valid` is `false` and `detectedSeparator` holds the canonical separator
74
+ * for use in the diagnostic message.
75
+ */
76
+ export type SeparatorValidationResult = {
77
+ readonly valid: true;
78
+ } | {
79
+ readonly valid: false;
80
+ readonly detectedSeparator: string;
81
+ };
82
+ /**
83
+ * Provides parsing and validation for DocID and SectionID identifiers
84
+ * as defined in the ECR specification (1#9.2).
85
+ *
86
+ * Grammar:
87
+ * DocID ::= Digit+ ("." Digit+)*
88
+ * SectionPath ::= Digit+ ("." Digit+)*
89
+ * SectionID ::= DocID "#" SectionPath
90
+ *
91
+ * This class encapsulates all identifier-level grammar operations
92
+ * required by the ECR structural specification.
93
+ *
94
+ * @example
95
+ * ```ts
96
+ * const grammar = new IdentifierGrammar();
97
+ * const result = grammar.parseDocId('3.1');
98
+ * // { valid: true, docId: '3.1' }
99
+ * ```
100
+ */
101
+ export declare class IdentifierGrammar {
102
+ /**
103
+ * Parses a string and determines whether it conforms to the DocID grammar.
104
+ *
105
+ * A valid DocID consists of one or more numeric segments separated by dots,
106
+ * where each segment contains one or more digits.
107
+ *
108
+ * @param input - The string to parse
109
+ * @returns A parse result indicating validity and, on success, the parsed DocID
110
+ */
111
+ parseDocId(input: string): DocIdParseResult;
112
+ /**
113
+ * Parses a string and determines whether it conforms to the SectionID grammar.
114
+ *
115
+ * A SectionID is a DocID, the separator `#`, and a section path
116
+ * of one or more dot-separated numeric segments. The separator is mandatory:
117
+ * a dotted identifier with no `#` is a DocID, never a SectionID.
118
+ *
119
+ * @param input - The string to parse
120
+ * @returns A parse result indicating validity and, on success, the SectionID,
121
+ * the DocID it belongs to, and the section path within that document
122
+ */
123
+ parseSectionId(input: string): SectionIdParseResult;
124
+ /**
125
+ * Determines whether a SectionID belongs to a given DocID.
126
+ *
127
+ * This is an exact comparison of the SectionID's document
128
+ * part against the supplied DocID. No prefix matching is involved, so a
129
+ * SectionID of document `8.1.3` does not belong to document `8.1`, and a
130
+ * SectionID of `8.10` does not belong to `8.1`.
131
+ *
132
+ * @param sectionId - The SectionID to check
133
+ * @param docId - The DocID the SectionID should belong to
134
+ * @returns `true` if the SectionID names a section of that document
135
+ */
136
+ tellSectionIdExtendsDocId(sectionId: SectionID, docId: DocID): boolean;
137
+ /**
138
+ * Counts the number of numeric segments in an identifier string.
139
+ *
140
+ * Segments are the numeric components separated by `"."`.
141
+ * For example, `"3.1.2"` has three segments.
142
+ *
143
+ * @param identifier - A DocID or SectionID string
144
+ * @returns The number of numeric segments
145
+ */
146
+ showSegmentCount(identifier: string): number;
147
+ /**
148
+ * Counts the segments in a SectionID's section path.
149
+ *
150
+ * For `8.1#3.1` the section path is `3.1`, so the length is 2. The DocID's
151
+ * own depth does not contribute.
152
+ *
153
+ * @param sectionId - The SectionID to measure
154
+ * @returns The number of section-path segments, or 0 if the input is not a SectionID
155
+ */
156
+ showSectionPathLength(sectionId: SectionID): number;
157
+ /**
158
+ * Computes the section-path length required of a heading at a given depth.
159
+ *
160
+ * A heading at Markdown depth *d* carries exactly *d - 1*
161
+ * section-path segments, independent of how deep its document's DocID is.
162
+ * An H2 carries one segment, an H3 two, and so on.
163
+ *
164
+ * @param headingDepth - The Markdown heading depth (2 for H2, 3 for H3, etc.)
165
+ * @returns The required number of section-path segments
166
+ */
167
+ showExpectedSectionPathLength(headingDepth: number): number;
168
+ /**
169
+ * Extracts the DocID and title from an H1 heading string.
170
+ *
171
+ * The heading must match the pattern: DocID <dash> Title, where the dash
172
+ * is a hyphen-minus, en dash or em dash with any surrounding whitespace.
173
+ * The title must be non-empty after trimming leading and trailing
174
+ * whitespace.
175
+ *
176
+ * @param headingText - The plain text content of the H1 heading node
177
+ * @returns A parse result indicating validity and, on success, the extracted DocID and title
178
+ */
179
+ parseHeading(headingText: string): HeadingParseResult;
180
+ /**
181
+ * Extracts the SectionID and title from a sub-heading string.
182
+ *
183
+ * A sub-heading carries a SectionID, so it must contain the `#` separator.
184
+ * An H1 carries a DocID and is parsed by {@link IdentifierGrammar.parseHeading}
185
+ * instead.
186
+ *
187
+ * @param headingText - The plain text content of a heading node at depth \>= 2
188
+ * @returns A parse result indicating validity and, on success, the SectionID and title
189
+ */
190
+ parseSectionHeading(headingText: string): SectionHeadingParseResult;
191
+ /**
192
+ * Validates that a heading string carries a separator between its
193
+ * identifier and its title.
194
+ *
195
+ * Per the ECR specification (1#9.3, 1#9.4), the separator may be a
196
+ * hyphen-minus (U+002D), an en dash (U+2013) or an em dash (U+2014), with
197
+ * any surrounding whitespace. Only a heading with no separator at all is
198
+ * invalid.
199
+ *
200
+ * @param headingText - The plain text content of a heading node
201
+ * @returns A validation result indicating whether the separator is valid
202
+ */
203
+ validateSeparator(headingText: string): SeparatorValidationResult;
204
+ /**
205
+ * Tests whether a string matches the DocID grammar: `Digit+ ("." Digit+)*`.
206
+ *
207
+ * @param input - The string to test
208
+ * @returns `true` if the input matches the DocID grammar, `false` otherwise
209
+ */
210
+ private matchesDocIdGrammar;
211
+ }
212
+ //# sourceMappingURL=identifier-grammar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identifier-grammar.d.ts","sourceRoot":"","sources":["../src/identifier-grammar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAMnD;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAC/C;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;AAE9B;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IACE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,6EAA6E;IAC7E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B,GACD;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;AAE9B;;;;;GAKG;AACH,MAAM,MAAM,yBAAyB,GACjC;IAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/E;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;AAE9B;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACvE;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;AAE9B;;;;;;;GAOG;AACH,MAAM,MAAM,yBAAyB,GACjC;IAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GACxB;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,CAAC;AAkElE;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,iBAAiB;IAC5B;;;;;;;;OAQG;IACI,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB;IAUlD;;;;;;;;;;OAUG;IACI,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,oBAAoB;IAkB1D;;;;;;;;;;;OAWG;IACI,yBAAyB,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO;IAU7E;;;;;;;;OAQG;IACI,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IASnD;;;;;;;;OAQG;IACI,qBAAqB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM;IAU1D;;;;;;;;;OASG;IACI,6BAA6B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAIlE;;;;;;;;;;OAUG;IACI,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,kBAAkB;IAyB5D;;;;;;;;;OASG;IACI,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,yBAAyB;IAiB1E;;;;;;;;;;;OAWG;IACI,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,yBAAyB;IAYxE;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;CAG5B"}
@@ -0,0 +1,273 @@
1
+ /**
2
+ * DocID and SectionID Grammar Parsing & Validation
3
+ *
4
+ * Implements the identifier grammar defined in the ECR specification (1#9.2).
5
+ *
6
+ * Grammar:
7
+ * DocID ::= Digit+ ("." Digit+)*
8
+ * SectionPath ::= Digit+ ("." Digit+)*
9
+ * SectionID ::= DocID "#" SectionPath
10
+ *
11
+ * All operations are deterministic and side-effect-free.
12
+ */
13
+ // ---------------------------------------------------------------------------
14
+ // Internal constants
15
+ // ---------------------------------------------------------------------------
16
+ /**
17
+ * Regular expression matching the DocID grammar: one or more numeric segments
18
+ * separated by dots. Each segment is one or more digits.
19
+ *
20
+ * Anchored to match the entire string.
21
+ */
22
+ const DOC_ID_PATTERN = /^\d+(\.\d+)*$/;
23
+ /**
24
+ * Regular expression matching the SectionID grammar: a DocID, the
25
+ * separator `#`, and a section path of one or more dot-separated numeric
26
+ * segments.
27
+ *
28
+ * The separator is what makes an identifier unambiguous. Without it, `0.0.2.1`
29
+ * could denote section 1 of document `0.0.2` or section 2.1 of document `0.0`,
30
+ * and a corpus numbering its documents hierarchically will contain both.
31
+ *
32
+ * Group 1: the DocID. Group 2: the section path.
33
+ */
34
+ const SECTION_ID_PATTERN = /^(\d+(?:\.\d+)*)#(\d+(?:\.\d+)*)$/;
35
+ /**
36
+ * Canonical separator, used when a separator must be rendered in a message.
37
+ */
38
+ const HYPHEN_MINUS_SEPARATOR = ' - ';
39
+ /**
40
+ * Regular expression matching a heading of the form `DocID <dash> Title`.
41
+ *
42
+ * The separator may be a hyphen-minus (U+002D), an en dash (U+2013) or an
43
+ * em dash (U+2014), with any amount of surrounding whitespace including none.
44
+ *
45
+ * Real-world corpora mix all three interchangeably, often within one document,
46
+ * and the separator carries no structural meaning: identity is carried entirely
47
+ * by the numeric identifier. Rejecting a dash variant would fail documents that
48
+ * are perfectly navigable, so all three are accepted.
49
+ *
50
+ * Group 1: the candidate DocID. Group 2: the title.
51
+ */
52
+ const HEADING_PATTERN = /^(\d+(?:\.\d+)*)\s*[-–—]\s*(.+)$/;
53
+ /**
54
+ * Detects whether a heading carries any recognised separator, irrespective of
55
+ * which dash variant is used.
56
+ */
57
+ const ANY_SEPARATOR_PATTERN = /\d\s*[-–—]\s*\S/;
58
+ /**
59
+ * Regular expression matching a sub-heading of the form `SectionID <dash> Title`.
60
+ *
61
+ * Group 1: the SectionID. Group 2: the title.
62
+ */
63
+ const SECTION_HEADING_PATTERN = /^(\d+(?:\.\d+)*#\d+(?:\.\d+)*)\s*[-\u2013\u2014]\s*(.+)$/;
64
+ // ---------------------------------------------------------------------------
65
+ // Identifier grammar parser
66
+ // ---------------------------------------------------------------------------
67
+ /**
68
+ * Provides parsing and validation for DocID and SectionID identifiers
69
+ * as defined in the ECR specification (1#9.2).
70
+ *
71
+ * Grammar:
72
+ * DocID ::= Digit+ ("." Digit+)*
73
+ * SectionPath ::= Digit+ ("." Digit+)*
74
+ * SectionID ::= DocID "#" SectionPath
75
+ *
76
+ * This class encapsulates all identifier-level grammar operations
77
+ * required by the ECR structural specification.
78
+ *
79
+ * @example
80
+ * ```ts
81
+ * const grammar = new IdentifierGrammar();
82
+ * const result = grammar.parseDocId('3.1');
83
+ * // { valid: true, docId: '3.1' }
84
+ * ```
85
+ */
86
+ export class IdentifierGrammar {
87
+ /**
88
+ * Parses a string and determines whether it conforms to the DocID grammar.
89
+ *
90
+ * A valid DocID consists of one or more numeric segments separated by dots,
91
+ * where each segment contains one or more digits.
92
+ *
93
+ * @param input - The string to parse
94
+ * @returns A parse result indicating validity and, on success, the parsed DocID
95
+ */
96
+ parseDocId(input) {
97
+ const isValid = this.matchesDocIdGrammar(input);
98
+ if (isValid) {
99
+ return { valid: true, docId: input };
100
+ }
101
+ return { valid: false };
102
+ }
103
+ /**
104
+ * Parses a string and determines whether it conforms to the SectionID grammar.
105
+ *
106
+ * A SectionID is a DocID, the separator `#`, and a section path
107
+ * of one or more dot-separated numeric segments. The separator is mandatory:
108
+ * a dotted identifier with no `#` is a DocID, never a SectionID.
109
+ *
110
+ * @param input - The string to parse
111
+ * @returns A parse result indicating validity and, on success, the SectionID,
112
+ * the DocID it belongs to, and the section path within that document
113
+ */
114
+ parseSectionId(input) {
115
+ const match = SECTION_ID_PATTERN.exec(input);
116
+ if (match === null) {
117
+ return { valid: false };
118
+ }
119
+ const docIdValue = match[1] ?? '';
120
+ const sectionPathValue = match[2] ?? '';
121
+ return {
122
+ valid: true,
123
+ sectionId: input,
124
+ docId: docIdValue,
125
+ sectionPath: sectionPathValue,
126
+ };
127
+ }
128
+ /**
129
+ * Determines whether a SectionID belongs to a given DocID.
130
+ *
131
+ * This is an exact comparison of the SectionID's document
132
+ * part against the supplied DocID. No prefix matching is involved, so a
133
+ * SectionID of document `8.1.3` does not belong to document `8.1`, and a
134
+ * SectionID of `8.10` does not belong to `8.1`.
135
+ *
136
+ * @param sectionId - The SectionID to check
137
+ * @param docId - The DocID the SectionID should belong to
138
+ * @returns `true` if the SectionID names a section of that document
139
+ */
140
+ tellSectionIdExtendsDocId(sectionId, docId) {
141
+ const parseResult = this.parseSectionId(sectionId);
142
+ if (!parseResult.valid) {
143
+ return false;
144
+ }
145
+ return parseResult.docId === docId;
146
+ }
147
+ /**
148
+ * Counts the number of numeric segments in an identifier string.
149
+ *
150
+ * Segments are the numeric components separated by `"."`.
151
+ * For example, `"3.1.2"` has three segments.
152
+ *
153
+ * @param identifier - A DocID or SectionID string
154
+ * @returns The number of numeric segments
155
+ */
156
+ showSegmentCount(identifier) {
157
+ if (identifier === '') {
158
+ return 0;
159
+ }
160
+ const segments = identifier.split('.');
161
+ return segments.length;
162
+ }
163
+ /**
164
+ * Counts the segments in a SectionID's section path.
165
+ *
166
+ * For `8.1#3.1` the section path is `3.1`, so the length is 2. The DocID's
167
+ * own depth does not contribute.
168
+ *
169
+ * @param sectionId - The SectionID to measure
170
+ * @returns The number of section-path segments, or 0 if the input is not a SectionID
171
+ */
172
+ showSectionPathLength(sectionId) {
173
+ const parseResult = this.parseSectionId(sectionId);
174
+ if (!parseResult.valid) {
175
+ return 0;
176
+ }
177
+ return this.showSegmentCount(parseResult.sectionPath);
178
+ }
179
+ /**
180
+ * Computes the section-path length required of a heading at a given depth.
181
+ *
182
+ * A heading at Markdown depth *d* carries exactly *d - 1*
183
+ * section-path segments, independent of how deep its document's DocID is.
184
+ * An H2 carries one segment, an H3 two, and so on.
185
+ *
186
+ * @param headingDepth - The Markdown heading depth (2 for H2, 3 for H3, etc.)
187
+ * @returns The required number of section-path segments
188
+ */
189
+ showExpectedSectionPathLength(headingDepth) {
190
+ return headingDepth - 1;
191
+ }
192
+ /**
193
+ * Extracts the DocID and title from an H1 heading string.
194
+ *
195
+ * The heading must match the pattern: DocID <dash> Title, where the dash
196
+ * is a hyphen-minus, en dash or em dash with any surrounding whitespace.
197
+ * The title must be non-empty after trimming leading and trailing
198
+ * whitespace.
199
+ *
200
+ * @param headingText - The plain text content of the H1 heading node
201
+ * @returns A parse result indicating validity and, on success, the extracted DocID and title
202
+ */
203
+ parseHeading(headingText) {
204
+ const match = HEADING_PATTERN.exec(headingText.trim());
205
+ if (match === null) {
206
+ return { valid: false };
207
+ }
208
+ const candidateDocId = match[1] ?? '';
209
+ const title = match[2] ?? '';
210
+ const docIdResult = this.parseDocId(candidateDocId);
211
+ if (!docIdResult.valid) {
212
+ return { valid: false };
213
+ }
214
+ const trimmedTitle = title.trim();
215
+ if (trimmedTitle.length === 0) {
216
+ return { valid: false };
217
+ }
218
+ return { valid: true, docId: docIdResult.docId, title };
219
+ }
220
+ /**
221
+ * Extracts the SectionID and title from a sub-heading string.
222
+ *
223
+ * A sub-heading carries a SectionID, so it must contain the `#` separator.
224
+ * An H1 carries a DocID and is parsed by {@link IdentifierGrammar.parseHeading}
225
+ * instead.
226
+ *
227
+ * @param headingText - The plain text content of a heading node at depth \>= 2
228
+ * @returns A parse result indicating validity and, on success, the SectionID and title
229
+ */
230
+ parseSectionHeading(headingText) {
231
+ const match = SECTION_HEADING_PATTERN.exec(headingText.trim());
232
+ if (match === null) {
233
+ return { valid: false };
234
+ }
235
+ const sectionId = match[1] ?? '';
236
+ const title = match[2] ?? '';
237
+ if (title.trim().length === 0) {
238
+ return { valid: false };
239
+ }
240
+ return { valid: true, sectionId, title };
241
+ }
242
+ /**
243
+ * Validates that a heading string carries a separator between its
244
+ * identifier and its title.
245
+ *
246
+ * Per the ECR specification (1#9.3, 1#9.4), the separator may be a
247
+ * hyphen-minus (U+002D), an en dash (U+2013) or an em dash (U+2014), with
248
+ * any surrounding whitespace. Only a heading with no separator at all is
249
+ * invalid.
250
+ *
251
+ * @param headingText - The plain text content of a heading node
252
+ * @returns A validation result indicating whether the separator is valid
253
+ */
254
+ validateSeparator(headingText) {
255
+ if (ANY_SEPARATOR_PATTERN.test(headingText)) {
256
+ return { valid: true };
257
+ }
258
+ return { valid: false, detectedSeparator: HYPHEN_MINUS_SEPARATOR };
259
+ }
260
+ // -------------------------------------------------------------------------
261
+ // Private helpers
262
+ // -------------------------------------------------------------------------
263
+ /**
264
+ * Tests whether a string matches the DocID grammar: `Digit+ ("." Digit+)*`.
265
+ *
266
+ * @param input - The string to test
267
+ * @returns `true` if the input matches the DocID grammar, `false` otherwise
268
+ */
269
+ matchesDocIdGrammar(input) {
270
+ return DOC_ID_PATTERN.test(input);
271
+ }
272
+ }
273
+ //# sourceMappingURL=identifier-grammar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identifier-grammar.js","sourceRoot":"","sources":["../src/identifier-grammar.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export type { DocID, SectionID, DiagnosticSeverity, Position, PositionRange, Diagnostic, ReferenceDirection, InlineReferenceKind, SectionNode, ReferenceEdge, InlineReferenceEdge, ExtractedDocument, LintInput, LintResult, CorpusDocumentEntry, CorpusIndex, CorpusResult, } from "./types.js";
2
+ export { IdentifierGrammar } from "./identifier-grammar.js";
3
+ export type { DocIdParseResult, SectionIdParseResult, HeadingParseResult, SectionHeadingParseResult, SeparatorValidationResult, } from "./identifier-grammar.js";
4
+ export { DocumentIdentityRule, DOCUMENT_IDENTITY_RULE_ID } from "./document-identity-rule.js";
5
+ export type { HeadingNodeData, DocumentIdentity, DocumentIdentityRuleResult, DocumentIdentityRuleOptions, } from "./document-identity-rule.js";
6
+ export { SectionHierarchyRule, SECTION_HIERARCHY_RULE_ID } from "./section-hierarchy-rule.js";
7
+ export type { SectionHierarchyRuleOptions, SectionHierarchyRuleResult, } from "./section-hierarchy-rule.js";
8
+ export { ReferencesSectionRule, REFERENCES_SECTION_RULE_ID } from "./references-section-rule.js";
9
+ export type { ListItemNodeData, ListItemSegment, ParsedReferenceEntry, ReferencesSectionRuleResult, ReferencesSectionRuleOptions, } from "./references-section-rule.js";
10
+ export { InlineReferenceRule, INLINE_REFERENCE_RULE_ID } from "./inline-reference-rule.js";
11
+ export type { TextNodeData, InlineSegment, InlineSegmentKind, DetectedInlineReference, InlineReferenceRuleResult, InlineReferenceRuleOptions, } from "./inline-reference-rule.js";
12
+ export { PerDocumentVisitor, UNPARSABLE_DOCUMENT_RULE_ID, UNPARSABLE_DOCUMENT_CAUSE, } from "./per-document-visitor.js";
13
+ export type { PerDocumentVisitorOptions, } from "./per-document-visitor.js";
14
+ export { CorpusValidator } from "./corpus-validator.js";
15
+ export { Ecr } from "./ecr.js";
16
+ export type { CorpusDocumentInput } from "./ecr.js";
17
+ export { MetaDocumentFilter, DEFAULT_META_DOCUMENT_NAMES } from "./meta-documents.js";
18
+ export { ECR_SPEC_VERSION } from "./spec-version.js";
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,KAAK,EACL,SAAS,EACT,kBAAkB,EAClB,QAAQ,EACR,aAAa,EACb,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,WAAW,EACX,aAAa,EACb,mBAAmB,EACnB,iBAAiB,EACjB,SAAS,EACT,UAAU,EACV,mBAAmB,EACnB,WAAW,EACX,YAAY,GACb,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,YAAY,EACV,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAC9F,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAC9F,YAAY,EACV,2BAA2B,EAC3B,0BAA0B,GAC3B,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AACjG,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,2BAA2B,EAC3B,4BAA4B,GAC7B,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAC3F,YAAY,EACV,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,uBAAuB,EACvB,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,kBAAkB,EAClB,2BAA2B,EAC3B,yBAAyB,GAC1B,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,yBAAyB,GAC1B,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,YAAY,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAEpD,OAAO,EAAE,kBAAkB,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AACtF,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ export { IdentifierGrammar } from "./identifier-grammar.js";
2
+ export { DocumentIdentityRule, DOCUMENT_IDENTITY_RULE_ID } from "./document-identity-rule.js";
3
+ export { SectionHierarchyRule, SECTION_HIERARCHY_RULE_ID } from "./section-hierarchy-rule.js";
4
+ export { ReferencesSectionRule, REFERENCES_SECTION_RULE_ID } from "./references-section-rule.js";
5
+ export { InlineReferenceRule, INLINE_REFERENCE_RULE_ID } from "./inline-reference-rule.js";
6
+ export { PerDocumentVisitor, UNPARSABLE_DOCUMENT_RULE_ID, UNPARSABLE_DOCUMENT_CAUSE, } from "./per-document-visitor.js";
7
+ export { CorpusValidator } from "./corpus-validator.js";
8
+ export { Ecr } from "./ecr.js";
9
+ export { MetaDocumentFilter, DEFAULT_META_DOCUMENT_NAMES } from "./meta-documents.js";
10
+ export { ECR_SPEC_VERSION } from "./spec-version.js";
11
+ //# sourceMappingURL=index.js.map