@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
package/dist/bin.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ECR Executable Entry Point
|
|
4
|
+
*
|
|
5
|
+
* This file runs the CLI unconditionally and does nothing else. It must not
|
|
6
|
+
* guard itself with a "was I invoked directly?" check that compares
|
|
7
|
+
* `process.argv[1]` with this module's path: package managers install the
|
|
8
|
+
* binary as a symlink (`node_modules/.bin/ecr`), Node resolves the module to
|
|
9
|
+
* its real path, and the two never match, so a guarded entry point silently
|
|
10
|
+
* exits 0 without running. Keeping the commands in `cli.ts` and the side
|
|
11
|
+
* effect here removes the need for any such check.
|
|
12
|
+
*
|
|
13
|
+
* It is also where supervision is asked for, because this file knows the one
|
|
14
|
+
* thing a supervised run needs: the script a child process would have to run,
|
|
15
|
+
* which is this file itself, at its real path rather than through whatever
|
|
16
|
+
* symlink invoked it. A host embedding the library instead of the command
|
|
17
|
+
* gets no supervision, and bounds its own work.
|
|
18
|
+
*/
|
|
19
|
+
import { fileURLToPath } from 'node:url';
|
|
20
|
+
import { EcrCommandLine } from './cli.js';
|
|
21
|
+
const result = new EcrCommandLine({
|
|
22
|
+
supervision: { entryPoint: fileURLToPath(import.meta.url) },
|
|
23
|
+
}).run(process.argv.slice(2));
|
|
24
|
+
process[result.stream].write(result.output);
|
|
25
|
+
process.exitCode = result.exitCode;
|
|
26
|
+
//# sourceMappingURL=bin.js.map
|
package/dist/bin.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG1C,MAAM,MAAM,GAAmB,IAAI,cAAc,CAAC;IAChD,WAAW,EAAE,EAAE,UAAU,EAAE,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;CAC5D,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9B,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC5C,OAAO,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Corpus Loading
|
|
3
|
+
*
|
|
4
|
+
* File discovery is the host's responsibility, not the linter's. This module
|
|
5
|
+
* is the CLI's implementation of that responsibility: it walks a directory,
|
|
6
|
+
* excludes meta-documents, and produces the inputs the linter consumes.
|
|
7
|
+
*/
|
|
8
|
+
import type { CorpusDocumentInput } from '../ecr.js';
|
|
9
|
+
/**
|
|
10
|
+
* A path the walk reached but could not read.
|
|
11
|
+
*/
|
|
12
|
+
export interface UnreadablePath {
|
|
13
|
+
/** Corpus-relative path, with forward slashes. */
|
|
14
|
+
readonly path: string;
|
|
15
|
+
/** Why it could not be read: the file system's error code, or its message. */
|
|
16
|
+
readonly reason: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The outcome of walking a corpus directory.
|
|
20
|
+
*/
|
|
21
|
+
export interface LoadedCorpus {
|
|
22
|
+
/** Documents to validate, in path order. */
|
|
23
|
+
readonly documents: readonly CorpusDocumentInput[];
|
|
24
|
+
/**
|
|
25
|
+
* Corpus-relative paths excluded as meta-documents or by ignore pattern. A
|
|
26
|
+
* directory excluded whole by a pattern is listed once, with a trailing
|
|
27
|
+
* slash, and is not walked.
|
|
28
|
+
*/
|
|
29
|
+
readonly excludedPaths: readonly string[];
|
|
30
|
+
/**
|
|
31
|
+
* Links beneath the corpus root that were not followed: every link to a
|
|
32
|
+
* directory, every link named like a document, and every link whose target
|
|
33
|
+
* is missing.
|
|
34
|
+
*/
|
|
35
|
+
readonly notFollowedPaths: readonly string[];
|
|
36
|
+
/**
|
|
37
|
+
* Paths that could not be read. A corpus with any of these was not fully
|
|
38
|
+
* read, so its validation result cannot stand for the whole corpus.
|
|
39
|
+
*/
|
|
40
|
+
readonly unreadablePaths: readonly UnreadablePath[];
|
|
41
|
+
/**
|
|
42
|
+
* Whether the project's `.ecrignore` excludes the corpus root itself, in
|
|
43
|
+
* which case nothing beneath it was walked.
|
|
44
|
+
*/
|
|
45
|
+
readonly rootExcluded: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* A project's own ignore patterns, from its `.ecrignore`, and the directory
|
|
49
|
+
* they are relative to.
|
|
50
|
+
*/
|
|
51
|
+
export interface ProjectIgnore {
|
|
52
|
+
/** The project root: the directory the command runs from. */
|
|
53
|
+
readonly workingDirectory: string;
|
|
54
|
+
/** Patterns relative to the working directory. */
|
|
55
|
+
readonly patterns: readonly string[];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Discovers and reads the Markdown documents of a corpus.
|
|
59
|
+
*
|
|
60
|
+
* Paths are reported relative to the corpus root and normalised to forward
|
|
61
|
+
* slashes, so that ignore patterns and diagnostics read the same on every
|
|
62
|
+
* platform.
|
|
63
|
+
*
|
|
64
|
+
* Symbolic links and junctions beneath the root are not followed, because the
|
|
65
|
+
* published recursive searches (`rg`, `grep -r`) do not follow them: a
|
|
66
|
+
* document reached only through a link would be validated but could not be
|
|
67
|
+
* found (1#9.11). A root that is itself a link is followed, as both search
|
|
68
|
+
* engines follow a link named on their command line.
|
|
69
|
+
*/
|
|
70
|
+
export declare class CorpusLoader {
|
|
71
|
+
/** Absolute or relative path to the corpus root directory. */
|
|
72
|
+
private readonly corpusRoot;
|
|
73
|
+
/** Decides which discovered documents are excluded from validation. */
|
|
74
|
+
private readonly metaDocumentFilter;
|
|
75
|
+
/**
|
|
76
|
+
* Applies the project's `.ecrignore` patterns, which are relative to the
|
|
77
|
+
* working directory rather than the corpus root; absent when there are none.
|
|
78
|
+
*/
|
|
79
|
+
private readonly projectFilter;
|
|
80
|
+
/** The directory the project's patterns are relative to. */
|
|
81
|
+
private readonly workingDirectory;
|
|
82
|
+
/**
|
|
83
|
+
* Creates a loader for one corpus directory.
|
|
84
|
+
*
|
|
85
|
+
* @param corpusRoot - Path to the directory to walk
|
|
86
|
+
* @param ignorePatterns - Glob patterns relative to the corpus root, from `--ignore`
|
|
87
|
+
* @param projectIgnore - The project's `.ecrignore` patterns, relative to the working directory
|
|
88
|
+
*/
|
|
89
|
+
constructor(corpusRoot: string, ignorePatterns?: readonly string[], projectIgnore?: ProjectIgnore);
|
|
90
|
+
/**
|
|
91
|
+
* Walks the corpus root and reads every Markdown document that is not
|
|
92
|
+
* excluded.
|
|
93
|
+
*
|
|
94
|
+
* A path that cannot be read is recorded and the walk continues, so that
|
|
95
|
+
* every such path is reported at once.
|
|
96
|
+
*
|
|
97
|
+
* @returns The documents to validate, and the paths excluded, not followed, or not readable
|
|
98
|
+
*/
|
|
99
|
+
load(): LoadedCorpus;
|
|
100
|
+
/**
|
|
101
|
+
* Orders two corpus-relative paths by their UTF-16 code units, as
|
|
102
|
+
* `Array.prototype.sort` does by default.
|
|
103
|
+
*
|
|
104
|
+
* @param left - A path
|
|
105
|
+
* @param right - Another path
|
|
106
|
+
* @returns Negative, zero or positive, as for a sort comparator
|
|
107
|
+
*/
|
|
108
|
+
private static comparePaths;
|
|
109
|
+
/**
|
|
110
|
+
* Walks one directory, in name order.
|
|
111
|
+
*
|
|
112
|
+
* @param directory - Directory to walk
|
|
113
|
+
* @param walk - What the walk has found so far
|
|
114
|
+
*/
|
|
115
|
+
private walkDirectory;
|
|
116
|
+
/**
|
|
117
|
+
* Walks one directory entry: a link is recorded and not followed, a
|
|
118
|
+
* directory is descended into unless an ignore pattern excludes it whole,
|
|
119
|
+
* and a Markdown file is read unless it is excluded.
|
|
120
|
+
*
|
|
121
|
+
* @param entryPath - Path of the entry
|
|
122
|
+
* @param entryName - The entry's own name
|
|
123
|
+
* @param walk - What the walk has found so far
|
|
124
|
+
*/
|
|
125
|
+
private walkEntry;
|
|
126
|
+
/**
|
|
127
|
+
* Records a link without following it. An ignore pattern covering it
|
|
128
|
+
* excludes it instead; a link to a file that is not Markdown is of no
|
|
129
|
+
* interest, as it could never be a document.
|
|
130
|
+
*
|
|
131
|
+
* @param entryPath - Path of the link
|
|
132
|
+
* @param entryName - The link's own name
|
|
133
|
+
* @param relativePath - The link's corpus-relative path
|
|
134
|
+
* @param walk - What the walk has found so far
|
|
135
|
+
*/
|
|
136
|
+
private recordLink;
|
|
137
|
+
/**
|
|
138
|
+
* Determines whether an ignore pattern of either kind covers a path whose
|
|
139
|
+
* kind cannot or need not be known, such as a link or a vanished entry.
|
|
140
|
+
*
|
|
141
|
+
* @param relativePath - Corpus-relative path
|
|
142
|
+
* @param entryPath - Path of the entry, for the project's patterns
|
|
143
|
+
* @returns `true` when a file pattern or a whole-directory pattern covers it
|
|
144
|
+
*/
|
|
145
|
+
private tellExcludedWhateverItIs;
|
|
146
|
+
/**
|
|
147
|
+
* Determines whether a `.ecrignore` pattern excludes the corpus root, either
|
|
148
|
+
* itself or through a directory above it: with `ecr/**` ignored, a root of
|
|
149
|
+
* `ecr/sub` is excluded as surely as `ecr`.
|
|
150
|
+
*
|
|
151
|
+
* @returns `true` when the root, or any directory between it and the project root, is excluded whole
|
|
152
|
+
*/
|
|
153
|
+
private tellProjectExcludesRoot;
|
|
154
|
+
/**
|
|
155
|
+
* Determines whether a `.ecrignore` pattern excludes a whole directory.
|
|
156
|
+
*
|
|
157
|
+
* @param directoryPath - Path of the directory
|
|
158
|
+
* @returns `true` when the project's patterns cover everything beneath it
|
|
159
|
+
*/
|
|
160
|
+
private tellProjectExcludesDirectory;
|
|
161
|
+
/**
|
|
162
|
+
* Determines whether a `.ecrignore` pattern excludes a file.
|
|
163
|
+
*
|
|
164
|
+
* @param filePath - Path of the file
|
|
165
|
+
* @returns `true` when one of the project's patterns matches it
|
|
166
|
+
*/
|
|
167
|
+
private tellProjectExcludesFile;
|
|
168
|
+
/**
|
|
169
|
+
* Converts a path into one relative to the working directory, with forward
|
|
170
|
+
* slashes, which is what `.ecrignore` patterns are matched against.
|
|
171
|
+
*
|
|
172
|
+
* @param path - A path
|
|
173
|
+
* @returns The path relative to the working directory, or `undefined` when there are no project patterns or the path lies outside the project
|
|
174
|
+
*/
|
|
175
|
+
private toProjectRelativePath;
|
|
176
|
+
/**
|
|
177
|
+
* Determines whether a name is a Markdown document's.
|
|
178
|
+
*
|
|
179
|
+
* @param entryName - A file or link name
|
|
180
|
+
* @returns `true` for a `.md` name, in any case
|
|
181
|
+
*/
|
|
182
|
+
private static tellMarkdownName;
|
|
183
|
+
/**
|
|
184
|
+
* Determines whether a link resolves to something other than a directory.
|
|
185
|
+
*
|
|
186
|
+
* @param linkPath - Path of the link
|
|
187
|
+
* @returns `true` when the target exists and is not a directory
|
|
188
|
+
*/
|
|
189
|
+
private static tellLinksToFile;
|
|
190
|
+
/**
|
|
191
|
+
* Converts an absolute path into a corpus-relative path with forward slashes.
|
|
192
|
+
*
|
|
193
|
+
* @param absolutePath - A path beneath the corpus root
|
|
194
|
+
* @returns The path relative to the corpus root
|
|
195
|
+
*/
|
|
196
|
+
private toCorpusRelativePath;
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=corpus-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"corpus-loader.d.ts","sourceRoot":"","sources":["../../src/cli/corpus-loader.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,kDAAkD;IAClD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,QAAQ,CAAC,SAAS,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACnD;;;;OAIG;IACH,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C;;;OAGG;IACH,QAAQ,CAAC,eAAe,EAAE,SAAS,cAAc,EAAE,CAAC;IACpD;;;OAGG;IACH,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,6DAA6D;IAC7D,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,kDAAkD;IAClD,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAuBD;;;;;;;;;;;;GAYG;AACH,qBAAa,YAAY;IACvB,8DAA8D;IAC9D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IAEpC,uEAAuE;IACvE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqB;IAExD;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAiC;IAE/D,4DAA4D;IAC5D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;IAEtD;;;;;;OAMG;gBAED,UAAU,EAAE,MAAM,EAClB,cAAc,GAAE,SAAS,MAAM,EAAO,EACtC,aAAa,CAAC,EAAE,aAAa;IAU/B;;;;;;;;OAQG;IACI,IAAI,IAAI,YAAY;IAgC3B;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAC,YAAY;IAQ3B;;;;;OAKG;IACH,OAAO,CAAC,aAAa;IAqBrB;;;;;;;;OAQG;IACH,OAAO,CAAC,SAAS;IAyDjB;;;;;;;;;OASG;IACH,OAAO,CAAC,UAAU;IAkBlB;;;;;;;OAOG;IACH,OAAO,CAAC,wBAAwB;IAShC;;;;;;OAMG;IACH,OAAO,CAAC,uBAAuB;IAc/B;;;;;OAKG;IACH,OAAO,CAAC,4BAA4B;IAOpC;;;;;OAKG;IACH,OAAO,CAAC,uBAAuB;IAM/B;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB;IAe7B;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAI/B;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,eAAe;IAQ9B;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;CAU7B"}
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Corpus Loading
|
|
3
|
+
*
|
|
4
|
+
* File discovery is the host's responsibility, not the linter's. This module
|
|
5
|
+
* is the CLI's implementation of that responsibility: it walks a directory,
|
|
6
|
+
* excludes meta-documents, and produces the inputs the linter consumes.
|
|
7
|
+
*/
|
|
8
|
+
import { lstatSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
9
|
+
import { isAbsolute, join, relative } from 'node:path';
|
|
10
|
+
import { MetaDocumentFilter } from '../meta-documents.js';
|
|
11
|
+
/**
|
|
12
|
+
* Directory-walking characters that mark a path as hidden on every platform
|
|
13
|
+
* this runs on. Hidden directories are skipped so that `.git`, `.obsidian` and
|
|
14
|
+
* similar never reach the linter.
|
|
15
|
+
*/
|
|
16
|
+
const HIDDEN_PREFIX = '.';
|
|
17
|
+
/**
|
|
18
|
+
* The directory package managers install dependencies into. It is skipped
|
|
19
|
+
* wherever the walk meets it: an installed copy of this package carries the
|
|
20
|
+
* specification, whose DocIDs would collide with a project's own, and any
|
|
21
|
+
* other package's Markdown is not the project's documentation. A corpus root
|
|
22
|
+
* named explicitly is still walked, even inside one.
|
|
23
|
+
*/
|
|
24
|
+
const DEPENDENCY_DIRECTORY = 'node_modules';
|
|
25
|
+
/**
|
|
26
|
+
* Extension identifying a Markdown document.
|
|
27
|
+
*/
|
|
28
|
+
const MARKDOWN_EXTENSION = '.md';
|
|
29
|
+
/**
|
|
30
|
+
* Discovers and reads the Markdown documents of a corpus.
|
|
31
|
+
*
|
|
32
|
+
* Paths are reported relative to the corpus root and normalised to forward
|
|
33
|
+
* slashes, so that ignore patterns and diagnostics read the same on every
|
|
34
|
+
* platform.
|
|
35
|
+
*
|
|
36
|
+
* Symbolic links and junctions beneath the root are not followed, because the
|
|
37
|
+
* published recursive searches (`rg`, `grep -r`) do not follow them: a
|
|
38
|
+
* document reached only through a link would be validated but could not be
|
|
39
|
+
* found (1#9.11). A root that is itself a link is followed, as both search
|
|
40
|
+
* engines follow a link named on their command line.
|
|
41
|
+
*/
|
|
42
|
+
export class CorpusLoader {
|
|
43
|
+
/** Absolute or relative path to the corpus root directory. */
|
|
44
|
+
corpusRoot;
|
|
45
|
+
/** Decides which discovered documents are excluded from validation. */
|
|
46
|
+
metaDocumentFilter;
|
|
47
|
+
/**
|
|
48
|
+
* Applies the project's `.ecrignore` patterns, which are relative to the
|
|
49
|
+
* working directory rather than the corpus root; absent when there are none.
|
|
50
|
+
*/
|
|
51
|
+
projectFilter;
|
|
52
|
+
/** The directory the project's patterns are relative to. */
|
|
53
|
+
workingDirectory;
|
|
54
|
+
/**
|
|
55
|
+
* Creates a loader for one corpus directory.
|
|
56
|
+
*
|
|
57
|
+
* @param corpusRoot - Path to the directory to walk
|
|
58
|
+
* @param ignorePatterns - Glob patterns relative to the corpus root, from `--ignore`
|
|
59
|
+
* @param projectIgnore - The project's `.ecrignore` patterns, relative to the working directory
|
|
60
|
+
*/
|
|
61
|
+
constructor(corpusRoot, ignorePatterns = [], projectIgnore) {
|
|
62
|
+
this.corpusRoot = corpusRoot;
|
|
63
|
+
this.metaDocumentFilter = new MetaDocumentFilter(ignorePatterns);
|
|
64
|
+
// No meta-document names: those are already applied by the corpus filter.
|
|
65
|
+
this.projectFilter =
|
|
66
|
+
projectIgnore === undefined ? undefined : new MetaDocumentFilter(projectIgnore.patterns, []);
|
|
67
|
+
this.workingDirectory = projectIgnore?.workingDirectory;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Walks the corpus root and reads every Markdown document that is not
|
|
71
|
+
* excluded.
|
|
72
|
+
*
|
|
73
|
+
* A path that cannot be read is recorded and the walk continues, so that
|
|
74
|
+
* every such path is reported at once.
|
|
75
|
+
*
|
|
76
|
+
* @returns The documents to validate, and the paths excluded, not followed, or not readable
|
|
77
|
+
*/
|
|
78
|
+
load() {
|
|
79
|
+
const walk = new CorpusWalk();
|
|
80
|
+
const rootExcluded = this.tellProjectExcludesRoot();
|
|
81
|
+
if (!rootExcluded) {
|
|
82
|
+
this.walkDirectory(this.corpusRoot, walk);
|
|
83
|
+
}
|
|
84
|
+
// Sorted by corpus-relative path, so the order is the same on every
|
|
85
|
+
// platform whatever the path separator.
|
|
86
|
+
walk.documents.sort((left, right) => CorpusLoader.comparePaths(left.uri, right.uri));
|
|
87
|
+
walk.excludedPaths.sort((left, right) => CorpusLoader.comparePaths(left, right));
|
|
88
|
+
walk.notFollowedPaths.sort((left, right) => CorpusLoader.comparePaths(left, right));
|
|
89
|
+
walk.unreadablePaths.sort((left, right) => CorpusLoader.comparePaths(left.path, right.path));
|
|
90
|
+
return {
|
|
91
|
+
documents: walk.documents,
|
|
92
|
+
excludedPaths: walk.excludedPaths,
|
|
93
|
+
notFollowedPaths: walk.notFollowedPaths,
|
|
94
|
+
unreadablePaths: walk.unreadablePaths,
|
|
95
|
+
rootExcluded,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Orders two corpus-relative paths by their UTF-16 code units, as
|
|
100
|
+
* `Array.prototype.sort` does by default.
|
|
101
|
+
*
|
|
102
|
+
* @param left - A path
|
|
103
|
+
* @param right - Another path
|
|
104
|
+
* @returns Negative, zero or positive, as for a sort comparator
|
|
105
|
+
*/
|
|
106
|
+
static comparePaths(left, right) {
|
|
107
|
+
if (left === right) {
|
|
108
|
+
return 0;
|
|
109
|
+
}
|
|
110
|
+
return left < right ? -1 : 1;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Walks one directory, in name order.
|
|
114
|
+
*
|
|
115
|
+
* @param directory - Directory to walk
|
|
116
|
+
* @param walk - What the walk has found so far
|
|
117
|
+
*/
|
|
118
|
+
walkDirectory(directory, walk) {
|
|
119
|
+
let entryNames;
|
|
120
|
+
try {
|
|
121
|
+
entryNames = readdirSync(directory).sort((left, right) => CorpusLoader.comparePaths(left, right));
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
walk.recordUnreadable(this.toCorpusRelativePath(directory), error);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
for (const entryName of entryNames) {
|
|
128
|
+
if (entryName.startsWith(HIDDEN_PREFIX)) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
this.walkEntry(join(directory, entryName), entryName, walk);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Walks one directory entry: a link is recorded and not followed, a
|
|
136
|
+
* directory is descended into unless an ignore pattern excludes it whole,
|
|
137
|
+
* and a Markdown file is read unless it is excluded.
|
|
138
|
+
*
|
|
139
|
+
* @param entryPath - Path of the entry
|
|
140
|
+
* @param entryName - The entry's own name
|
|
141
|
+
* @param walk - What the walk has found so far
|
|
142
|
+
*/
|
|
143
|
+
walkEntry(entryPath, entryName, walk) {
|
|
144
|
+
const relativePath = this.toCorpusRelativePath(entryPath);
|
|
145
|
+
let entryStats;
|
|
146
|
+
try {
|
|
147
|
+
entryStats = lstatSync(entryPath);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
if (this.tellExcludedWhateverItIs(relativePath, entryPath)) {
|
|
151
|
+
walk.excludedPaths.push(relativePath);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
walk.recordUnreadable(relativePath, error);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (entryStats.isSymbolicLink()) {
|
|
158
|
+
this.recordLink(entryPath, entryName, relativePath, walk);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (entryStats.isDirectory()) {
|
|
162
|
+
if (entryName === DEPENDENCY_DIRECTORY ||
|
|
163
|
+
this.metaDocumentFilter.excludesDirectory(relativePath) ||
|
|
164
|
+
this.tellProjectExcludesDirectory(entryPath)) {
|
|
165
|
+
walk.excludedPaths.push(`${relativePath}/`);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
this.walkDirectory(entryPath, walk);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (!CorpusLoader.tellMarkdownName(entryName)) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (this.metaDocumentFilter.shouldExclude(relativePath) ||
|
|
175
|
+
this.tellProjectExcludesFile(entryPath)) {
|
|
176
|
+
walk.excludedPaths.push(relativePath);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
try {
|
|
180
|
+
walk.documents.push({
|
|
181
|
+
uri: relativePath,
|
|
182
|
+
markdownText: readFileSync(entryPath, 'utf8'),
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
walk.recordUnreadable(relativePath, error);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Records a link without following it. An ignore pattern covering it
|
|
191
|
+
* excludes it instead; a link to a file that is not Markdown is of no
|
|
192
|
+
* interest, as it could never be a document.
|
|
193
|
+
*
|
|
194
|
+
* @param entryPath - Path of the link
|
|
195
|
+
* @param entryName - The link's own name
|
|
196
|
+
* @param relativePath - The link's corpus-relative path
|
|
197
|
+
* @param walk - What the walk has found so far
|
|
198
|
+
*/
|
|
199
|
+
recordLink(entryPath, entryName, relativePath, walk) {
|
|
200
|
+
if (this.tellExcludedWhateverItIs(relativePath, entryPath)) {
|
|
201
|
+
walk.excludedPaths.push(relativePath);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (!CorpusLoader.tellMarkdownName(entryName) && CorpusLoader.tellLinksToFile(entryPath)) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
walk.notFollowedPaths.push(relativePath);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Determines whether an ignore pattern of either kind covers a path whose
|
|
211
|
+
* kind cannot or need not be known, such as a link or a vanished entry.
|
|
212
|
+
*
|
|
213
|
+
* @param relativePath - Corpus-relative path
|
|
214
|
+
* @param entryPath - Path of the entry, for the project's patterns
|
|
215
|
+
* @returns `true` when a file pattern or a whole-directory pattern covers it
|
|
216
|
+
*/
|
|
217
|
+
tellExcludedWhateverItIs(relativePath, entryPath) {
|
|
218
|
+
return (this.metaDocumentFilter.excludesDirectory(relativePath) ||
|
|
219
|
+
this.metaDocumentFilter.matchesIgnorePattern(relativePath) ||
|
|
220
|
+
this.tellProjectExcludesDirectory(entryPath) ||
|
|
221
|
+
this.tellProjectExcludesFile(entryPath));
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Determines whether a `.ecrignore` pattern excludes the corpus root, either
|
|
225
|
+
* itself or through a directory above it: with `ecr/**` ignored, a root of
|
|
226
|
+
* `ecr/sub` is excluded as surely as `ecr`.
|
|
227
|
+
*
|
|
228
|
+
* @returns `true` when the root, or any directory between it and the project root, is excluded whole
|
|
229
|
+
*/
|
|
230
|
+
tellProjectExcludesRoot() {
|
|
231
|
+
const projectPath = this.toProjectRelativePath(this.corpusRoot);
|
|
232
|
+
if (projectPath === undefined || projectPath === '') {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
const segments = projectPath.split('/');
|
|
236
|
+
return segments.some((_segment, index) => this.projectFilter?.excludesDirectory(segments.slice(0, index + 1).join('/')) === true);
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Determines whether a `.ecrignore` pattern excludes a whole directory.
|
|
240
|
+
*
|
|
241
|
+
* @param directoryPath - Path of the directory
|
|
242
|
+
* @returns `true` when the project's patterns cover everything beneath it
|
|
243
|
+
*/
|
|
244
|
+
tellProjectExcludesDirectory(directoryPath) {
|
|
245
|
+
const projectPath = this.toProjectRelativePath(directoryPath);
|
|
246
|
+
return projectPath !== undefined && projectPath !== '' &&
|
|
247
|
+
this.projectFilter?.excludesDirectory(projectPath) === true;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Determines whether a `.ecrignore` pattern excludes a file.
|
|
251
|
+
*
|
|
252
|
+
* @param filePath - Path of the file
|
|
253
|
+
* @returns `true` when one of the project's patterns matches it
|
|
254
|
+
*/
|
|
255
|
+
tellProjectExcludesFile(filePath) {
|
|
256
|
+
const projectPath = this.toProjectRelativePath(filePath);
|
|
257
|
+
return projectPath !== undefined && this.projectFilter?.matchesIgnorePattern(projectPath) === true;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Converts a path into one relative to the working directory, with forward
|
|
261
|
+
* slashes, which is what `.ecrignore` patterns are matched against.
|
|
262
|
+
*
|
|
263
|
+
* @param path - A path
|
|
264
|
+
* @returns The path relative to the working directory, or `undefined` when there are no project patterns or the path lies outside the project
|
|
265
|
+
*/
|
|
266
|
+
toProjectRelativePath(path) {
|
|
267
|
+
if (this.workingDirectory === undefined) {
|
|
268
|
+
return undefined;
|
|
269
|
+
}
|
|
270
|
+
const projectPath = relative(this.workingDirectory, path);
|
|
271
|
+
// The project's patterns say nothing about paths outside the project.
|
|
272
|
+
if (isAbsolute(projectPath) || /^\.\.(?:[\\/]|$)/.test(projectPath)) {
|
|
273
|
+
return undefined;
|
|
274
|
+
}
|
|
275
|
+
return projectPath.replaceAll('\\', '/');
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Determines whether a name is a Markdown document's.
|
|
279
|
+
*
|
|
280
|
+
* @param entryName - A file or link name
|
|
281
|
+
* @returns `true` for a `.md` name, in any case
|
|
282
|
+
*/
|
|
283
|
+
static tellMarkdownName(entryName) {
|
|
284
|
+
return entryName.toLowerCase().endsWith(MARKDOWN_EXTENSION);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Determines whether a link resolves to something other than a directory.
|
|
288
|
+
*
|
|
289
|
+
* @param linkPath - Path of the link
|
|
290
|
+
* @returns `true` when the target exists and is not a directory
|
|
291
|
+
*/
|
|
292
|
+
static tellLinksToFile(linkPath) {
|
|
293
|
+
try {
|
|
294
|
+
return !statSync(linkPath).isDirectory();
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Converts an absolute path into a corpus-relative path with forward slashes.
|
|
302
|
+
*
|
|
303
|
+
* @param absolutePath - A path beneath the corpus root
|
|
304
|
+
* @returns The path relative to the corpus root
|
|
305
|
+
*/
|
|
306
|
+
toCorpusRelativePath(absolutePath) {
|
|
307
|
+
const withoutRoot = absolutePath.startsWith(this.corpusRoot)
|
|
308
|
+
? absolutePath.slice(this.corpusRoot.length)
|
|
309
|
+
: absolutePath;
|
|
310
|
+
return withoutRoot
|
|
311
|
+
.split('\\')
|
|
312
|
+
.join('/')
|
|
313
|
+
.replace(/^\/+/, '');
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* What one walk of a corpus has found so far.
|
|
318
|
+
*/
|
|
319
|
+
class CorpusWalk {
|
|
320
|
+
/** Documents read, in the order reached. */
|
|
321
|
+
documents = [];
|
|
322
|
+
/** Paths excluded as meta-documents or by ignore pattern. */
|
|
323
|
+
excludedPaths = [];
|
|
324
|
+
/** Links recorded and not followed. */
|
|
325
|
+
notFollowedPaths = [];
|
|
326
|
+
/** Paths reached but not readable. */
|
|
327
|
+
unreadablePaths = [];
|
|
328
|
+
/**
|
|
329
|
+
* Records a path that could not be read.
|
|
330
|
+
*
|
|
331
|
+
* @param path - The corpus-relative path; empty for the corpus root itself
|
|
332
|
+
* @param error - What reading it threw
|
|
333
|
+
*/
|
|
334
|
+
recordUnreadable(path, error) {
|
|
335
|
+
this.unreadablePaths.push({ path: path === '' ? '.' : path, reason: CorpusWalk.showReason(error) });
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Describes a file-system error briefly.
|
|
339
|
+
*
|
|
340
|
+
* @param error - What was thrown
|
|
341
|
+
* @returns The error's code, such as `ENOENT`, or its message
|
|
342
|
+
*/
|
|
343
|
+
static showReason(error) {
|
|
344
|
+
if (error instanceof Error) {
|
|
345
|
+
const code = error.code;
|
|
346
|
+
return typeof code === 'string' ? code : error.message;
|
|
347
|
+
}
|
|
348
|
+
return String(error);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
//# sourceMappingURL=corpus-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"corpus-loader.js","sourceRoot":"","sources":["../../src/cli/corpus-loader.ts"],"names":[],"mappings":"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"}
|