@descent-vtt/spec-guard 0.4.0 → 0.5.1
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/CHANGELOG.md +283 -150
- package/README.md +868 -644
- package/dist/cli.d.ts +8 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +40 -7
- package/dist/cli.js.map +1 -1
- package/dist/comments.d.ts +23 -4
- package/dist/comments.d.ts.map +1 -1
- package/dist/comments.js +75 -27
- package/dist/comments.js.map +1 -1
- package/dist/engine.d.ts +126 -6
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +301 -154
- package/dist/engine.js.map +1 -1
- package/dist/glob.d.ts +11 -1
- package/dist/glob.d.ts.map +1 -1
- package/dist/glob.js +20 -5
- package/dist/glob.js.map +1 -1
- package/dist/imports.d.ts +28 -4
- package/dist/imports.d.ts.map +1 -1
- package/dist/imports.js +46 -8
- package/dist/imports.js.map +1 -1
- package/dist/index.d.ts +11 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -5
- package/dist/index.js.map +1 -1
- package/dist/parser.d.ts +12 -1
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +39 -26
- package/dist/parser.js.map +1 -1
- package/dist/polyglot.d.ts +139 -0
- package/dist/polyglot.d.ts.map +1 -0
- package/dist/polyglot.js +548 -0
- package/dist/polyglot.js.map +1 -0
- package/dist/reporter.d.ts +41 -0
- package/dist/reporter.d.ts.map +1 -1
- package/dist/reporter.js +154 -1
- package/dist/reporter.js.map +1 -1
- package/dist/runner.d.ts +54 -2
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +321 -73
- package/dist/runner.js.map +1 -1
- package/dist/text.d.ts +34 -0
- package/dist/text.d.ts.map +1 -0
- package/dist/text.js +80 -0
- package/dist/text.js.map +1 -0
- package/dist/types.d.ts +76 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +73 -73
package/dist/engine.d.ts
CHANGED
|
@@ -19,18 +19,70 @@
|
|
|
19
19
|
* flags are answered by a single pass.
|
|
20
20
|
*/
|
|
21
21
|
import { type CommentMask } from './comments.js';
|
|
22
|
+
import { type DirectoryReader } from './glob.js';
|
|
22
23
|
import { type SkippedPath } from './scope.js';
|
|
23
24
|
import type { EngineName, MatchLocation, SearchOptions, SearchResult } from './types.js';
|
|
24
25
|
/** Files larger than this are skipped by both engines, keeping them in sync. */
|
|
25
26
|
export declare const MAX_FILE_SIZE: number;
|
|
26
|
-
|
|
27
|
+
/**
|
|
28
|
+
* One rule about file size, in one place.
|
|
29
|
+
*
|
|
30
|
+
* It used to be written twice and spelled differently each time - `size <=
|
|
31
|
+
* MAX_FILE_SIZE` where a file was admitted and `size > MAX_FILE_SIZE` where one
|
|
32
|
+
* was skipped - so the boundary was defined by two expressions that had to be
|
|
33
|
+
* kept complementary by hand. ripgrep is given the same number as
|
|
34
|
+
* `--max-filesize`, which is also inclusive, so all three now agree by
|
|
35
|
+
* construction rather than by inspection.
|
|
36
|
+
*/
|
|
37
|
+
export declare function withinSizeLimit(size: number): boolean;
|
|
38
|
+
/** Hard cap on collected locations; the reporter only ever shows a handful. */
|
|
39
|
+
export declare const MAX_COLLECTED_MATCHES = 500;
|
|
40
|
+
/** Most files read at once. Enough to keep a disk busy, few enough to be polite. */
|
|
41
|
+
export declare const MAX_CONCURRENT_READS = 16;
|
|
42
|
+
/** How many readers to start for a file list: never more than there are files. */
|
|
43
|
+
export declare function readConcurrency(fileCount: number): number;
|
|
44
|
+
/**
|
|
45
|
+
* The target list for a request that names none: the root itself.
|
|
46
|
+
*
|
|
47
|
+
* Shared by the walker and the ripgrep argv rather than written out at each,
|
|
48
|
+
* because the two must agree on what "no target" means - ripgrep given an empty
|
|
49
|
+
* path argument searches nothing at all, and a walk given one searches
|
|
50
|
+
* everything.
|
|
51
|
+
*/
|
|
52
|
+
export declare const ROOT_TARGETS: readonly string[];
|
|
53
|
+
/**
|
|
54
|
+
* Total ordering on POSIX paths, ties included.
|
|
55
|
+
*
|
|
56
|
+
* Three call sites used to inline `a < b ? -1 : 1`, which is correct only
|
|
57
|
+
* because no caller can produce two equal paths - and therefore had no
|
|
58
|
+
* behaviour to test at the tie. Stating the tie makes the function total, the
|
|
59
|
+
* ordering identical, and the comparison something a test can pin down.
|
|
60
|
+
*/
|
|
61
|
+
export declare function comparePaths(a: string, b: string): number;
|
|
62
|
+
/**
|
|
63
|
+
* Everything a walk of the tree depends on - which is everything except the
|
|
64
|
+
* pattern, since enumeration never looks inside a file.
|
|
65
|
+
*
|
|
66
|
+
* A separate type because callers that only want the file list had to invent a
|
|
67
|
+
* symbol to ask for one, and an invented value is a value no test can be wrong
|
|
68
|
+
* about. The import assertions passed `symbol: ""`.
|
|
69
|
+
*/
|
|
70
|
+
export interface WalkRequest {
|
|
27
71
|
/** Absolute root directory. All targets are resolved against it. */
|
|
28
72
|
root: string;
|
|
29
|
-
/** Literal string or regular expression source. */
|
|
30
|
-
symbol: string;
|
|
31
73
|
/** Existing target paths, relative to root, POSIX separators. */
|
|
32
74
|
targets: string[];
|
|
33
75
|
options: SearchOptions;
|
|
76
|
+
/**
|
|
77
|
+
* Ignored here. Declared optional so that a `SearchRequest` written inline -
|
|
78
|
+
* which every existing caller of `enumerateCandidates` does - still satisfies
|
|
79
|
+
* TypeScript's excess-property check.
|
|
80
|
+
*/
|
|
81
|
+
symbol?: string;
|
|
82
|
+
}
|
|
83
|
+
export interface SearchRequest extends WalkRequest {
|
|
84
|
+
/** Literal string or regular expression source. */
|
|
85
|
+
symbol: string;
|
|
34
86
|
}
|
|
35
87
|
export interface Engine {
|
|
36
88
|
readonly name: EngineName;
|
|
@@ -43,6 +95,16 @@ export interface Engine {
|
|
|
43
95
|
}
|
|
44
96
|
export type EnginePreference = 'auto' | 'ripgrep' | 'javascript';
|
|
45
97
|
export declare function escapeRegExp(value: string): string;
|
|
98
|
+
/**
|
|
99
|
+
* Trims a line to snippet length, and takes the line terminator off it.
|
|
100
|
+
*
|
|
101
|
+
* The terminator is a lone CR, not a newline: the caller slices up to the
|
|
102
|
+
* `\n`, so on a CRLF file the carriage return is the one byte that survives.
|
|
103
|
+
* This used to strip `\r?\n$`, which cannot match anything the caller passes -
|
|
104
|
+
* so every snippet from a Windows-authored file carried a CR into the report,
|
|
105
|
+
* where it returns the terminal cursor to column 0 and overwrites the line.
|
|
106
|
+
*/
|
|
107
|
+
export declare function truncate(value: string): string;
|
|
46
108
|
/**
|
|
47
109
|
* Orders matches by path, then by line. ripgrep searches in parallel and emits
|
|
48
110
|
* files in no fixed order, so this is what makes snippet output stable.
|
|
@@ -55,6 +117,17 @@ interface Tally {
|
|
|
55
117
|
/** Matches skipped because they were inside a comment. */
|
|
56
118
|
commentCount: number;
|
|
57
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* One walk, plus everything that decides what counts as a match within it.
|
|
122
|
+
*
|
|
123
|
+
* Exported because the runner groups assertions before handing them here, and
|
|
124
|
+
* it used to do so against a list of its own that was missing four of these
|
|
125
|
+
* fields. Being too coarse there costs no correctness - `sharesOnePass` checks
|
|
126
|
+
* again and declines - but it did cost the batching: a group of five where two
|
|
127
|
+
* requests disagreed was refused as a whole and run as five separate searches,
|
|
128
|
+
* rather than as the three-and-two it actually was.
|
|
129
|
+
*/
|
|
130
|
+
export declare function passKey(request: SearchRequest): string;
|
|
58
131
|
/** Runs requests through the batch API when the engine has one. */
|
|
59
132
|
export declare function runSearches(engine: Engine, requests: SearchRequest[]): Promise<SearchResult[]>;
|
|
60
133
|
export declare function resetRipgrepProbe(): void;
|
|
@@ -81,6 +154,25 @@ export declare function findRipgrep(): Promise<string | null>;
|
|
|
81
154
|
* must not be undone by a user's `glob="*.ts"`.
|
|
82
155
|
*/
|
|
83
156
|
export declare function buildRipgrepArgs(request: SearchRequest, patterns?: readonly string[]): string[];
|
|
157
|
+
/**
|
|
158
|
+
* What a run says when ripgrep exits with a code that is neither 0 nor 1.
|
|
159
|
+
*
|
|
160
|
+
* Separate from the spawn because it is the only part a reader ever sees, and
|
|
161
|
+
* inside the promise the only way to produce one was to break a real
|
|
162
|
+
* subprocess - so the exact text, including whether the trailing newline every
|
|
163
|
+
* command writes ends up in the middle of the sentence, was never asserted.
|
|
164
|
+
*/
|
|
165
|
+
export declare function ripgrepFailureMessage(code: number | null, errors: string): string;
|
|
166
|
+
/**
|
|
167
|
+
* Turns ripgrep's `--files-with-matches --null` output into candidate files.
|
|
168
|
+
*
|
|
169
|
+
* Split out from the spawn so that the parsing has somewhere to be tested from:
|
|
170
|
+
* inside the promise it could only be reached by running a real subprocess,
|
|
171
|
+
* which is why the separator handling, the exclusion filter and the ordering
|
|
172
|
+
* were all covered only incidentally, by whatever a real tree happened to
|
|
173
|
+
* contain.
|
|
174
|
+
*/
|
|
175
|
+
export declare function parseRipgrepFiles(stdout: string, root: string, excludeFiles: ReadonlySet<string>): CandidateFile[];
|
|
84
176
|
/**
|
|
85
177
|
* Pulls the paths out of ripgrep's stderr.
|
|
86
178
|
*
|
|
@@ -105,12 +197,21 @@ export interface Enumeration {
|
|
|
105
197
|
exceeded: boolean;
|
|
106
198
|
bytes: number;
|
|
107
199
|
/** Paths the walk declined to inspect, with the reason for each. */
|
|
108
|
-
skipped: SkippedPath[];
|
|
200
|
+
skipped: readonly SkippedPath[];
|
|
109
201
|
}
|
|
110
202
|
export interface EnumerationBudget {
|
|
111
203
|
maxFiles: number;
|
|
112
204
|
maxBytes: number;
|
|
113
205
|
}
|
|
206
|
+
/**
|
|
207
|
+
* A budget that abandons the walk at the first file it finds.
|
|
208
|
+
*
|
|
209
|
+
* Used to answer one question - "is there anything here at all?" - without
|
|
210
|
+
* walking a tree to count files nobody asked about. The answer is the same
|
|
211
|
+
* whichever engine will do the searching, which is the point: an assertion that
|
|
212
|
+
* covers nothing has to be recognised identically by both.
|
|
213
|
+
*/
|
|
214
|
+
export declare const ANY_FILE_PROBE: EnumerationBudget;
|
|
114
215
|
/**
|
|
115
216
|
* Lists the files a request would search, sorted by relative path.
|
|
116
217
|
*
|
|
@@ -119,7 +220,15 @@ export interface EnumerationBudget {
|
|
|
119
220
|
* work, so finding out a tree is "too big" costs a bounded number of stats
|
|
120
221
|
* rather than a full traversal.
|
|
121
222
|
*/
|
|
122
|
-
export declare function enumerateCandidates(request:
|
|
223
|
+
export declare function enumerateCandidates(request: WalkRequest, budget?: EnumerationBudget,
|
|
224
|
+
/**
|
|
225
|
+
* Directory reader, forwarded to the walk. Exists for the same reason
|
|
226
|
+
* `walkFiles` takes one: the interesting behaviour here is what the
|
|
227
|
+
* enumeration does with a directory it *cannot* read, and there is no
|
|
228
|
+
* portable way to create one - Windows has no chmod, and a permission bit set
|
|
229
|
+
* by a test is a permission bit a failed test leaves behind.
|
|
230
|
+
*/
|
|
231
|
+
readDirectory?: DirectoryReader): Promise<Enumeration>;
|
|
123
232
|
/** Counts matches in one file and records per-line snippets. */
|
|
124
233
|
export declare function scanContent(content: string, relativePath: string, regexp: RegExp,
|
|
125
234
|
/**
|
|
@@ -150,14 +259,25 @@ export declare const javascriptEngine: BatchEngine;
|
|
|
150
259
|
* The budget is set just below each crossover, so choosing JavaScript is never
|
|
151
260
|
* the slower option by more than a few milliseconds, while a small tree on
|
|
152
261
|
* Windows avoids a spawn that would cost ten times the whole search.
|
|
262
|
+
*
|
|
263
|
+
* Taking the platform as an argument rather than reading it: a decision that is
|
|
264
|
+
* explicitly about two platforms cannot be verified on one of them if the other
|
|
265
|
+
* branch is only reachable by being that other platform. Both are now asserted
|
|
266
|
+
* everywhere the suite runs.
|
|
153
267
|
*/
|
|
268
|
+
export declare function smallTreeBudget(platform: NodeJS.Platform): EnumerationBudget;
|
|
154
269
|
export declare const SMALL_TREE_BUDGET: EnumerationBudget;
|
|
155
270
|
/** Exported so the code list can be asserted; EACCES and friends are not
|
|
156
271
|
* reproducible on demand from a real spawn. */
|
|
157
272
|
export declare function isMissingBinary(error: unknown): boolean;
|
|
158
273
|
/** Resolves the engine to use, honouring an explicit preference. */
|
|
159
274
|
export declare function resolveEngine(preference?: EnginePreference): Promise<Engine>;
|
|
160
|
-
|
|
275
|
+
/**
|
|
276
|
+
* `searchBatch` is required rather than optional: `createCachedEngine` always
|
|
277
|
+
* supplies one, and typing it as maybe-absent only meant every caller that
|
|
278
|
+
* wanted it wrote a cast asserting what the factory already guaranteed.
|
|
279
|
+
*/
|
|
280
|
+
export type CachedEngine = Engine & Required<Pick<Engine, 'searchBatch'>> & {
|
|
161
281
|
fallbacks: string[];
|
|
162
282
|
};
|
|
163
283
|
/**
|
package/dist/engine.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
|