@descent-vtt/spec-guard 0.10.3 → 0.12.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/CHANGELOG.md +410 -0
- package/README.md +385 -27
- package/dist/cites.d.ts +192 -0
- package/dist/cites.d.ts.map +1 -0
- package/dist/cites.js +599 -0
- package/dist/cites.js.map +1 -0
- package/dist/cli.d.ts +14 -6
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +315 -22
- package/dist/cli.js.map +1 -1
- package/dist/comments.d.ts +51 -2
- package/dist/comments.d.ts.map +1 -1
- package/dist/comments.js +353 -57
- package/dist/comments.js.map +1 -1
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +46 -5
- package/dist/config.js.map +1 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +38 -14
- package/dist/engine.js.map +1 -1
- package/dist/glob.d.ts +128 -24
- package/dist/glob.d.ts.map +1 -1
- package/dist/glob.js +304 -61
- package/dist/glob.js.map +1 -1
- package/dist/impact.d.ts +179 -0
- package/dist/impact.d.ts.map +1 -0
- package/dist/impact.js +360 -0
- package/dist/impact.js.map +1 -0
- package/dist/imports.d.ts.map +1 -1
- package/dist/imports.js +5 -58
- package/dist/imports.js.map +1 -1
- package/dist/index.d.ts +13 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts +16 -75
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +198 -370
- package/dist/mcp.js.map +1 -1
- package/dist/overlay.d.ts +39 -0
- package/dist/overlay.d.ts.map +1 -0
- package/dist/overlay.js +133 -0
- package/dist/overlay.js.map +1 -0
- package/dist/parser.d.ts +41 -24
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +217 -160
- package/dist/parser.js.map +1 -1
- package/dist/prove.d.ts +46 -0
- package/dist/prove.d.ts.map +1 -0
- package/dist/prove.js +549 -0
- package/dist/prove.js.map +1 -0
- package/dist/query.d.ts +11 -0
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +9 -3
- package/dist/query.js.map +1 -1
- package/dist/reporter.d.ts +139 -1
- package/dist/reporter.d.ts.map +1 -1
- package/dist/reporter.js +593 -21
- package/dist/reporter.js.map +1 -1
- package/dist/rules.js +3 -3
- package/dist/rules.js.map +1 -1
- package/dist/runner.d.ts +24 -1
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +84 -21
- package/dist/runner.js.map +1 -1
- package/dist/specs.d.ts +5 -1
- package/dist/specs.d.ts.map +1 -1
- package/dist/specs.js +5 -1
- package/dist/specs.js.map +1 -1
- package/dist/structure.d.ts.map +1 -1
- package/dist/structure.js +7 -6
- package/dist/structure.js.map +1 -1
- package/dist/types.d.ts +193 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/vendor/spec-core/jsonrpc/index.d.ts +3 -0
- package/dist/vendor/spec-core/jsonrpc/index.d.ts.map +1 -0
- package/dist/vendor/spec-core/jsonrpc/index.js +2 -0
- package/dist/vendor/spec-core/jsonrpc/index.js.map +1 -0
- package/dist/vendor/spec-core/jsonrpc/mcp.d.ts +158 -0
- package/dist/vendor/spec-core/jsonrpc/mcp.d.ts.map +1 -0
- package/dist/vendor/spec-core/jsonrpc/mcp.js +353 -0
- package/dist/vendor/spec-core/jsonrpc/mcp.js.map +1 -0
- package/dist/vendor/spec-core/markdown/frontmatter.d.ts +104 -0
- package/dist/vendor/spec-core/markdown/frontmatter.d.ts.map +1 -0
- package/dist/vendor/spec-core/markdown/frontmatter.js +459 -0
- package/dist/vendor/spec-core/markdown/frontmatter.js.map +1 -0
- package/dist/vendor/spec-core/markdown/headings.d.ts +46 -0
- package/dist/vendor/spec-core/markdown/headings.d.ts.map +1 -0
- package/dist/vendor/spec-core/markdown/headings.js +199 -0
- package/dist/vendor/spec-core/markdown/headings.js.map +1 -0
- package/dist/vendor/spec-core/markdown/index.d.ts +6 -0
- package/dist/vendor/spec-core/markdown/index.d.ts.map +1 -0
- package/dist/vendor/spec-core/markdown/index.js +4 -0
- package/dist/vendor/spec-core/markdown/index.js.map +1 -0
- package/dist/vendor/spec-core/markdown/layout.d.ts +40 -0
- package/dist/vendor/spec-core/markdown/layout.d.ts.map +1 -0
- package/dist/vendor/spec-core/markdown/layout.js +28 -0
- package/dist/vendor/spec-core/markdown/layout.js.map +1 -0
- package/dist/vendor/spec-core/markdown/links.d.ts +23 -0
- package/dist/vendor/spec-core/markdown/links.d.ts.map +1 -0
- package/dist/vendor/spec-core/markdown/links.js +364 -0
- package/dist/vendor/spec-core/markdown/links.js.map +1 -0
- package/dist/vendor/spec-core/markdown/lists.d.ts +23 -0
- package/dist/vendor/spec-core/markdown/lists.d.ts.map +1 -0
- package/dist/vendor/spec-core/markdown/lists.js +127 -0
- package/dist/vendor/spec-core/markdown/lists.js.map +1 -0
- package/dist/vendor/spec-core/markdown/scan.d.ts +37 -0
- package/dist/vendor/spec-core/markdown/scan.d.ts.map +1 -0
- package/dist/vendor/spec-core/markdown/scan.js +439 -0
- package/dist/vendor/spec-core/markdown/scan.js.map +1 -0
- package/dist/vendor/spec-core/markdown/syntax.d.ts +76 -0
- package/dist/vendor/spec-core/markdown/syntax.d.ts.map +1 -0
- package/dist/vendor/spec-core/markdown/syntax.js +181 -0
- package/dist/vendor/spec-core/markdown/syntax.js.map +1 -0
- package/dist/vendor/spec-core/markdown/tables.d.ts +19 -0
- package/dist/vendor/spec-core/markdown/tables.d.ts.map +1 -0
- package/dist/vendor/spec-core/markdown/tables.js +86 -0
- package/dist/vendor/spec-core/markdown/tables.js.map +1 -0
- package/dist/vendor/spec-core/markdown/types.d.ts +288 -0
- package/dist/vendor/spec-core/markdown/types.d.ts.map +1 -0
- package/dist/vendor/spec-core/markdown/types.js +9 -0
- package/dist/vendor/spec-core/markdown/types.js.map +1 -0
- package/dist/vendor/spec-core/path/index.d.ts +2 -0
- package/dist/vendor/spec-core/path/index.d.ts.map +1 -0
- package/dist/vendor/spec-core/path/index.js +2 -0
- package/dist/vendor/spec-core/path/index.js.map +1 -0
- package/dist/vendor/spec-core/path/posix.d.ts +84 -0
- package/dist/vendor/spec-core/path/posix.d.ts.map +1 -0
- package/dist/vendor/spec-core/path/posix.js +150 -0
- package/dist/vendor/spec-core/path/posix.js.map +1 -0
- package/dist/vendor/spec-core/pattern/automaton.d.ts +130 -0
- package/dist/vendor/spec-core/pattern/automaton.d.ts.map +1 -0
- package/dist/vendor/spec-core/pattern/automaton.js +340 -0
- package/dist/vendor/spec-core/pattern/automaton.js.map +1 -0
- package/dist/vendor/spec-core/pattern/charset.d.ts +59 -0
- package/dist/vendor/spec-core/pattern/charset.d.ts.map +1 -0
- package/dist/vendor/spec-core/pattern/charset.js +116 -0
- package/dist/vendor/spec-core/pattern/charset.js.map +1 -0
- package/dist/vendor/spec-core/pattern/glob.d.ts +122 -0
- package/dist/vendor/spec-core/pattern/glob.d.ts.map +1 -0
- package/dist/vendor/spec-core/pattern/glob.js +481 -0
- package/dist/vendor/spec-core/pattern/glob.js.map +1 -0
- package/dist/vendor/spec-core/pattern/index.d.ts +7 -0
- package/dist/vendor/spec-core/pattern/index.d.ts.map +1 -0
- package/dist/vendor/spec-core/pattern/index.js +4 -0
- package/dist/vendor/spec-core/pattern/index.js.map +1 -0
- package/dist/vendor/spec-core/pattern/regex.d.ts +68 -0
- package/dist/vendor/spec-core/pattern/regex.d.ts.map +1 -0
- package/dist/vendor/spec-core/pattern/regex.js +813 -0
- package/dist/vendor/spec-core/pattern/regex.js.map +1 -0
- package/dist/vendor/spec-core/text/index.d.ts +3 -0
- package/dist/vendor/spec-core/text/index.d.ts.map +1 -0
- package/dist/vendor/spec-core/text/index.js +2 -0
- package/dist/vendor/spec-core/text/index.js.map +1 -0
- package/dist/vendor/spec-core/text/lines.d.ts +73 -0
- package/dist/vendor/spec-core/text/lines.d.ts.map +1 -0
- package/dist/vendor/spec-core/text/lines.js +156 -0
- package/dist/vendor/spec-core/text/lines.js.map +1 -0
- package/package.json +8 -1
- package/src/vendor/spec-core/LICENSE +21 -0
- package/src/vendor/spec-core/README.md +8 -0
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Non-deterministic finite automata over code points: built by Thompson's
|
|
3
|
+
* construction, run by keeping a set of live states, and searched for a
|
|
4
|
+
* shortest string several of them accept and several others refuse.
|
|
5
|
+
*
|
|
6
|
+
* Why an automaton rather than a `RegExp`: a glob such as `*-*-*-*-*-*x`
|
|
7
|
+
* handed to a backtracking engine tries every way of dividing a long name
|
|
8
|
+
* between its stars, and one spec-* tool measured 28 seconds for one path. A
|
|
9
|
+
* set of live states visits each state at most once per character, so a match
|
|
10
|
+
* costs at most the pattern's size times the path's length, whatever the
|
|
11
|
+
* pattern says.
|
|
12
|
+
*
|
|
13
|
+
* Why the same automaton for the witness: whether two scopes can name the same
|
|
14
|
+
* file, and whether one lies wholly inside another, are questions about the
|
|
15
|
+
* languages the patterns accept. Asked of the automata that do the matching,
|
|
16
|
+
* the answers cannot drift from what matching does.
|
|
17
|
+
*/
|
|
18
|
+
import { accepts, acceptsIgnoringCase, boundaryPoints, DOT, SLASH } from './charset.js';
|
|
19
|
+
const CHAR = 0;
|
|
20
|
+
const SPLIT = 1;
|
|
21
|
+
const JUMP = 2;
|
|
22
|
+
const MATCH = 3;
|
|
23
|
+
/**
|
|
24
|
+
* Ceiling on the size of one automaton.
|
|
25
|
+
*
|
|
26
|
+
* Brace alternatives are compiled side by side, so a pattern's size is the
|
|
27
|
+
* sum of its alternatives'. Far above anything a scope list says; it exists
|
|
28
|
+
* so that a pathological pattern is refused while compiling rather than
|
|
29
|
+
* matched slowly.
|
|
30
|
+
*/
|
|
31
|
+
export const MAX_STATES = 65_536;
|
|
32
|
+
export class AutomatonTooLarge extends Error {
|
|
33
|
+
constructor() {
|
|
34
|
+
super(`the pattern compiles to more than ${MAX_STATES} states`);
|
|
35
|
+
this.name = 'AutomatonTooLarge';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Thompson's construction, one fragment at a time. */
|
|
39
|
+
export class Builder {
|
|
40
|
+
kinds = [];
|
|
41
|
+
first = [];
|
|
42
|
+
second = [];
|
|
43
|
+
sets = [];
|
|
44
|
+
add(kind, set, first, second) {
|
|
45
|
+
if (this.kinds.length >= MAX_STATES)
|
|
46
|
+
throw new AutomatonTooLarge();
|
|
47
|
+
this.kinds.push(kind);
|
|
48
|
+
this.first.push(first);
|
|
49
|
+
this.second.push(second);
|
|
50
|
+
this.sets.push(set);
|
|
51
|
+
return this.kinds.length - 1;
|
|
52
|
+
}
|
|
53
|
+
patch(holes, target) {
|
|
54
|
+
for (const hole of holes) {
|
|
55
|
+
if (hole.slot === 1)
|
|
56
|
+
this.first[hole.state] = target;
|
|
57
|
+
else
|
|
58
|
+
this.second[hole.state] = target;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** One character from a set. */
|
|
62
|
+
char(set) {
|
|
63
|
+
const state = this.add(CHAR, set, -1, -1);
|
|
64
|
+
return { start: state, holes: [{ state, slot: 1 }] };
|
|
65
|
+
}
|
|
66
|
+
/** The empty string. */
|
|
67
|
+
empty() {
|
|
68
|
+
const state = this.add(JUMP, null, -1, -1);
|
|
69
|
+
return { start: state, holes: [{ state, slot: 1 }] };
|
|
70
|
+
}
|
|
71
|
+
/** Each fragment after the one before it. */
|
|
72
|
+
sequence(parts) {
|
|
73
|
+
if (parts.length === 0)
|
|
74
|
+
return this.empty();
|
|
75
|
+
let current = parts[0];
|
|
76
|
+
for (let i = 1; i < parts.length; i += 1) {
|
|
77
|
+
const next = parts[i];
|
|
78
|
+
this.patch(current.holes, next.start);
|
|
79
|
+
current = { start: current.start, holes: next.holes };
|
|
80
|
+
}
|
|
81
|
+
return current;
|
|
82
|
+
}
|
|
83
|
+
/** Any one of the fragments. */
|
|
84
|
+
either(options) {
|
|
85
|
+
if (options.length === 0)
|
|
86
|
+
throw new Error('an alternation needs at least one option');
|
|
87
|
+
let current = options[options.length - 1];
|
|
88
|
+
for (let i = options.length - 2; i >= 0; i -= 1) {
|
|
89
|
+
const option = options[i];
|
|
90
|
+
const split = this.add(SPLIT, null, option.start, current.start);
|
|
91
|
+
current = { start: split, holes: [...option.holes, ...current.holes] };
|
|
92
|
+
}
|
|
93
|
+
return current;
|
|
94
|
+
}
|
|
95
|
+
/** Zero or more of a fragment. */
|
|
96
|
+
star(body) {
|
|
97
|
+
const split = this.add(SPLIT, null, body.start, -1);
|
|
98
|
+
this.patch(body.holes, split);
|
|
99
|
+
return { start: split, holes: [{ state: split, slot: 2 }] };
|
|
100
|
+
}
|
|
101
|
+
/** One or more of a fragment. */
|
|
102
|
+
plus(body) {
|
|
103
|
+
const split = this.add(SPLIT, null, body.start, -1);
|
|
104
|
+
this.patch(body.holes, split);
|
|
105
|
+
return { start: body.start, holes: [{ state: split, slot: 2 }] };
|
|
106
|
+
}
|
|
107
|
+
/** Zero or one of a fragment. */
|
|
108
|
+
optional(body) {
|
|
109
|
+
const empty = this.empty();
|
|
110
|
+
return this.either([body, empty]);
|
|
111
|
+
}
|
|
112
|
+
/** Closes the automaton: every unaimed arrow reaches acceptance. */
|
|
113
|
+
finish(body, caseSensitive) {
|
|
114
|
+
const match = this.add(MATCH, null, -1, -1);
|
|
115
|
+
this.patch(body.holes, match);
|
|
116
|
+
return {
|
|
117
|
+
kinds: Uint8Array.from(this.kinds),
|
|
118
|
+
first: Int32Array.from(this.first),
|
|
119
|
+
second: Int32Array.from(this.second),
|
|
120
|
+
sets: [...this.sets],
|
|
121
|
+
start: body.start,
|
|
122
|
+
caseSensitive,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Follows every empty arrow out of the states on a stack, appending each
|
|
128
|
+
* CHAR or MATCH state reached to `into`. `visited[state] === stamp` marks a
|
|
129
|
+
* state already taken this round, which is what bounds the work.
|
|
130
|
+
*/
|
|
131
|
+
function close(automaton, stack, visited, stamp, into) {
|
|
132
|
+
const { kinds, first, second } = automaton;
|
|
133
|
+
while (stack.length > 0) {
|
|
134
|
+
const state = stack.pop();
|
|
135
|
+
if (visited[state] === stamp)
|
|
136
|
+
continue;
|
|
137
|
+
visited[state] = stamp;
|
|
138
|
+
switch (kinds[state]) {
|
|
139
|
+
case SPLIT:
|
|
140
|
+
stack.push(second[state], first[state]);
|
|
141
|
+
break;
|
|
142
|
+
case JUMP:
|
|
143
|
+
stack.push(first[state]);
|
|
144
|
+
break;
|
|
145
|
+
default:
|
|
146
|
+
into.push(state);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* A reusable matcher over one automaton.
|
|
152
|
+
*
|
|
153
|
+
* Holds its buffers between subjects; it is not reentrant, and nothing needs
|
|
154
|
+
* it to be - matching calls out to nothing.
|
|
155
|
+
*/
|
|
156
|
+
export class Matcher {
|
|
157
|
+
automaton;
|
|
158
|
+
visited;
|
|
159
|
+
stamp = 0;
|
|
160
|
+
stack = [];
|
|
161
|
+
live = [];
|
|
162
|
+
next = [];
|
|
163
|
+
constructor(automaton) {
|
|
164
|
+
this.automaton = automaton;
|
|
165
|
+
this.visited = new Int32Array(automaton.kinds.length).fill(-1);
|
|
166
|
+
}
|
|
167
|
+
/** Whether the automaton accepts the whole of a subject. */
|
|
168
|
+
test(subject) {
|
|
169
|
+
const { automaton } = this;
|
|
170
|
+
const accept = automaton.caseSensitive ? accepts : acceptsIgnoringCase;
|
|
171
|
+
this.live.length = 0;
|
|
172
|
+
this.stack.length = 0;
|
|
173
|
+
this.stack.push(automaton.start);
|
|
174
|
+
this.stamp += 1;
|
|
175
|
+
close(automaton, this.stack, this.visited, this.stamp, this.live);
|
|
176
|
+
for (let i = 0; i < subject.length; i += 1) {
|
|
177
|
+
const point = subject.codePointAt(i);
|
|
178
|
+
if (point > 0xffff)
|
|
179
|
+
i += 1;
|
|
180
|
+
this.next.length = 0;
|
|
181
|
+
this.stamp += 1;
|
|
182
|
+
for (const state of this.live) {
|
|
183
|
+
if (automaton.kinds[state] !== CHAR)
|
|
184
|
+
continue;
|
|
185
|
+
if (!accept(automaton.sets[state], point))
|
|
186
|
+
continue;
|
|
187
|
+
this.stack.push(automaton.first[state]);
|
|
188
|
+
close(automaton, this.stack, this.visited, this.stamp, this.next);
|
|
189
|
+
}
|
|
190
|
+
if (this.next.length === 0)
|
|
191
|
+
return false;
|
|
192
|
+
const spent = this.live;
|
|
193
|
+
this.live = this.next;
|
|
194
|
+
this.next = spent;
|
|
195
|
+
}
|
|
196
|
+
return this.live.some((state) => automaton.kinds[state] === MATCH);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* How many distinct search states a witness search may visit. The search is
|
|
201
|
+
* polynomial in the sizes of the automata it must satisfy and, for the ones
|
|
202
|
+
* it must avoid, bounded by the subsets of their states it reaches; scope
|
|
203
|
+
* patterns reach a handful. The bound turns a pathological input into an
|
|
204
|
+
* `undecided` rather than a hang.
|
|
205
|
+
*/
|
|
206
|
+
export const WITNESS_BUDGET = 200_000;
|
|
207
|
+
/**
|
|
208
|
+
* Path validity as a four-state machine: at the start of a segment, inside a
|
|
209
|
+
* segment reading `.` or `..` so far, or inside a segment that is a name. A
|
|
210
|
+
* witness must end inside a name, and a `/` is only legal after one, so no
|
|
211
|
+
* witness has an empty segment, a `.` or `..` segment, or a slash at either
|
|
212
|
+
* end - which a pattern such as `a/*\/b` would otherwise produce as `a//b`.
|
|
213
|
+
* NUL is refused outright: no filesystem and no git tree holds a path with one.
|
|
214
|
+
*/
|
|
215
|
+
const SEGMENT_START = 0;
|
|
216
|
+
const ONE_DOT = 1;
|
|
217
|
+
const TWO_DOTS = 2;
|
|
218
|
+
const IN_NAME = 3;
|
|
219
|
+
const INVALID = -1;
|
|
220
|
+
const NUL = 0;
|
|
221
|
+
function stepValidity(state, point) {
|
|
222
|
+
if (point === NUL)
|
|
223
|
+
return INVALID;
|
|
224
|
+
if (point === SLASH)
|
|
225
|
+
return state === IN_NAME ? SEGMENT_START : INVALID;
|
|
226
|
+
if (point === DOT)
|
|
227
|
+
return state === SEGMENT_START ? ONE_DOT : state === ONE_DOT ? TWO_DOTS : IN_NAME;
|
|
228
|
+
return IN_NAME;
|
|
229
|
+
}
|
|
230
|
+
function closureOf(automaton, seeds) {
|
|
231
|
+
const visited = new Int32Array(automaton.kinds.length).fill(-1);
|
|
232
|
+
const out = [];
|
|
233
|
+
close(automaton, [...seeds], visited, 0, out);
|
|
234
|
+
return out;
|
|
235
|
+
}
|
|
236
|
+
function stepSet(automaton, states, point) {
|
|
237
|
+
const seeds = [];
|
|
238
|
+
for (const state of states) {
|
|
239
|
+
if (automaton.kinds[state] === CHAR && accepts(automaton.sets[state], point)) {
|
|
240
|
+
seeds.push(automaton.first[state]);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return closureOf(automaton, seeds).sort((a, b) => a - b);
|
|
244
|
+
}
|
|
245
|
+
/** Every way of choosing one element from each list. */
|
|
246
|
+
function combinations(lists) {
|
|
247
|
+
let out = [[]];
|
|
248
|
+
for (const list of lists) {
|
|
249
|
+
const grown = [];
|
|
250
|
+
for (const prefix of out)
|
|
251
|
+
for (const state of list)
|
|
252
|
+
grown.push([...prefix, state]);
|
|
253
|
+
out = grown;
|
|
254
|
+
}
|
|
255
|
+
return out;
|
|
256
|
+
}
|
|
257
|
+
function isMatch(automaton, state) {
|
|
258
|
+
return automaton.kinds[state] === MATCH;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* A shortest path every automaton in `include` accepts and none in `exclude`
|
|
262
|
+
* does, spelled with readable characters where there is a choice.
|
|
263
|
+
*
|
|
264
|
+
* Breadth-first over the product of one live state per included automaton
|
|
265
|
+
* (existential: some run of each must accept) and the whole live set per
|
|
266
|
+
* excluded one (universal: no run of it may). Characters are tried at the
|
|
267
|
+
* boundary points of every set in play, which meets every combination of
|
|
268
|
+
* answers those sets can give, so the search is exact: `none` means no path
|
|
269
|
+
* exists, not that none was found. The first path reached is a shortest one.
|
|
270
|
+
*
|
|
271
|
+
* Case-sensitive automata only. Every scope comparison in the family is
|
|
272
|
+
* case-sensitive, and folding case exactly would need every set's closure
|
|
273
|
+
* under case mapping.
|
|
274
|
+
*/
|
|
275
|
+
export function findWitness(include, exclude = [], budget = WITNESS_BUDGET) {
|
|
276
|
+
if (include.length === 0)
|
|
277
|
+
throw new Error('a witness search needs at least one automaton to satisfy');
|
|
278
|
+
for (const automaton of [...include, ...exclude]) {
|
|
279
|
+
if (!automaton.caseSensitive)
|
|
280
|
+
throw new Error('a witness search is defined for case-sensitive patterns only');
|
|
281
|
+
}
|
|
282
|
+
const startPositive = include.map((automaton) => closureOf(automaton, [automaton.start]));
|
|
283
|
+
const startNegative = exclude.map((automaton) => closureOf(automaton, [automaton.start]).sort((a, b) => a - b));
|
|
284
|
+
const nodes = [];
|
|
285
|
+
const seen = new Set();
|
|
286
|
+
const key = (positive, negative, validity) => `${positive.join(',')}|${validity}|${negative.map((set) => set.join(',')).join('|')}`;
|
|
287
|
+
const enqueue = (positive, negative, validity, parent, point) => {
|
|
288
|
+
const id = key(positive, negative, validity);
|
|
289
|
+
if (seen.has(id))
|
|
290
|
+
return;
|
|
291
|
+
seen.add(id);
|
|
292
|
+
nodes.push({ positive, negative, validity, parent, point });
|
|
293
|
+
};
|
|
294
|
+
for (const positive of combinations(startPositive))
|
|
295
|
+
enqueue(positive, startNegative, SEGMENT_START, -1, 0);
|
|
296
|
+
for (let cursor = 0; cursor < nodes.length; cursor += 1) {
|
|
297
|
+
if (cursor >= budget)
|
|
298
|
+
return { kind: 'undecided' };
|
|
299
|
+
const node = nodes[cursor];
|
|
300
|
+
const accepted = node.positive.every((state, i) => isMatch(include[i], state));
|
|
301
|
+
const refused = node.negative.every((set, i) => !set.some((state) => isMatch(exclude[i], state)));
|
|
302
|
+
if (accepted && refused && node.validity === IN_NAME)
|
|
303
|
+
return { kind: 'found', path: spell(nodes, cursor) };
|
|
304
|
+
// A MATCH state reads nothing more: an included automaton sitting on one
|
|
305
|
+
// can only accept here, so no longer path extends this node.
|
|
306
|
+
if (node.positive.some((state, i) => include[i].kinds[state] !== CHAR))
|
|
307
|
+
continue;
|
|
308
|
+
const sets = [];
|
|
309
|
+
node.positive.forEach((state, i) => sets.push(include[i].sets[state]));
|
|
310
|
+
node.negative.forEach((set, i) => {
|
|
311
|
+
const automaton = exclude[i];
|
|
312
|
+
for (const state of set)
|
|
313
|
+
if (automaton.kinds[state] === CHAR)
|
|
314
|
+
sets.push(automaton.sets[state]);
|
|
315
|
+
});
|
|
316
|
+
// Where each included automaton goes next does not depend on the
|
|
317
|
+
// character, only whether it may go; what the excluded ones reach does.
|
|
318
|
+
const successors = combinations(node.positive.map((state, i) => closureOf(include[i], [include[i].first[state]])));
|
|
319
|
+
for (const point of boundaryPoints(sets)) {
|
|
320
|
+
const validity = stepValidity(node.validity, point);
|
|
321
|
+
if (validity === INVALID)
|
|
322
|
+
continue;
|
|
323
|
+
if (!node.positive.every((state, i) => accepts(include[i].sets[state], point))) {
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
const negative = node.negative.map((set, i) => stepSet(exclude[i], set, point));
|
|
327
|
+
for (const positive of successors)
|
|
328
|
+
enqueue(positive, negative, validity, cursor, point);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return { kind: 'none' };
|
|
332
|
+
}
|
|
333
|
+
function spell(nodes, index) {
|
|
334
|
+
const points = [];
|
|
335
|
+
for (let i = index; nodes[i].parent >= 0; i = nodes[i].parent) {
|
|
336
|
+
points.push(nodes[i].point);
|
|
337
|
+
}
|
|
338
|
+
return String.fromCodePoint(...points.reverse());
|
|
339
|
+
}
|
|
340
|
+
//# sourceMappingURL=automaton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"automaton.js","sourceRoot":"","sources":["../../../../src/vendor/spec-core/pattern/automaton.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sets of characters a glob position accepts, over Unicode code points.
|
|
3
|
+
*
|
|
4
|
+
* A glob matches a path one character at a time, and a character is a code
|
|
5
|
+
* point: `?` matches `é` whether it is stored as one UTF-16 unit or not, and an
|
|
6
|
+
* emoji as one. That is what a person counting characters in a file name
|
|
7
|
+
* expects, and it is the same on every host.
|
|
8
|
+
*
|
|
9
|
+
* No set but the separator's accepts `/`. A path is matched a segment at a
|
|
10
|
+
* time, and a `*` or a `[!a]` that swallowed a slash would let one segment of
|
|
11
|
+
* a pattern match two of a path.
|
|
12
|
+
*/
|
|
13
|
+
/** An inclusive range of code points. */
|
|
14
|
+
export type CodeRange = readonly [number, number];
|
|
15
|
+
export interface CharSet {
|
|
16
|
+
readonly negated: boolean;
|
|
17
|
+
readonly ranges: readonly CodeRange[];
|
|
18
|
+
/** True only for the path separator itself. */
|
|
19
|
+
readonly separator: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare const SLASH = 47;
|
|
22
|
+
export declare const DOT = 46;
|
|
23
|
+
export declare const MAX_CODE_POINT = 1114111;
|
|
24
|
+
/** The separator, and nothing else. */
|
|
25
|
+
export declare const SEPARATOR: CharSet;
|
|
26
|
+
/** Any character but the separator: `?`, and the body of `*`. */
|
|
27
|
+
export declare const ANY: CharSet;
|
|
28
|
+
export declare function literalSet(point: number): CharSet;
|
|
29
|
+
export declare function classSet(ranges: readonly CodeRange[], negated: boolean): CharSet;
|
|
30
|
+
/** Whether a set accepts a code point as written. */
|
|
31
|
+
export declare function accepts(set: CharSet, point: number): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* The code points a code point is the same letter as, ignoring case: itself,
|
|
34
|
+
* and its lower- and upper-case forms where each is a single code point.
|
|
35
|
+
*
|
|
36
|
+
* Simple case mapping, which is what `toLowerCase` and `toUpperCase` give one
|
|
37
|
+
* character at a time. It is locale-free, so two hosts agree; `ß` has no single
|
|
38
|
+
* upper-case code point and so matches only itself.
|
|
39
|
+
*/
|
|
40
|
+
export declare function caseVariants(point: number): readonly number[];
|
|
41
|
+
/**
|
|
42
|
+
* Whether a set accepts a code point with case ignored: whether it accepts
|
|
43
|
+
* the point or one of its case variants. A negated set is negated over the
|
|
44
|
+
* same question, so `[!a]` refuses `A` as well as `a`.
|
|
45
|
+
*/
|
|
46
|
+
export declare function acceptsIgnoringCase(set: CharSet, point: number): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Every code point at which the answer "which of these sets accept it" can
|
|
49
|
+
* change, readable ones first.
|
|
50
|
+
*
|
|
51
|
+
* Each set accepts a union of intervals, so the sets' memberships are constant
|
|
52
|
+
* between consecutive interval ends. The start of each interval and the point
|
|
53
|
+
* after its end therefore meet every distinct combination of answers, and
|
|
54
|
+
* trying them all decides every question a witness search can ask of one
|
|
55
|
+
* character. The separator and the dot are always included: path validity
|
|
56
|
+
* turns on them.
|
|
57
|
+
*/
|
|
58
|
+
export declare function boundaryPoints(sets: readonly CharSet[]): number[];
|
|
59
|
+
//# sourceMappingURL=charset.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"charset.d.ts","sourceRoot":"","sources":["../../../../src/vendor/spec-core/pattern/charset.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,yCAAyC;AACzC,MAAM,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAElD,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAC;IACtC,+CAA+C;IAC/C,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED,eAAO,MAAM,KAAK,KAAO,CAAC;AAC1B,eAAO,MAAM,GAAG,KAAO,CAAC;AACxB,eAAO,MAAM,cAAc,UAAW,CAAC;AAEvC,uCAAuC;AACvC,eAAO,MAAM,SAAS,EAAE,OAAuE,CAAC;AAEhG,iEAAiE;AACjE,eAAO,MAAM,GAAG,EAAE,OAAyD,CAAC;AAE5E,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAEhF;AAUD,qDAAqD;AACrD,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAG5D;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAa7D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAMxE;AASD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,EAAE,CAiBjE"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sets of characters a glob position accepts, over Unicode code points.
|
|
3
|
+
*
|
|
4
|
+
* A glob matches a path one character at a time, and a character is a code
|
|
5
|
+
* point: `?` matches `é` whether it is stored as one UTF-16 unit or not, and an
|
|
6
|
+
* emoji as one. That is what a person counting characters in a file name
|
|
7
|
+
* expects, and it is the same on every host.
|
|
8
|
+
*
|
|
9
|
+
* No set but the separator's accepts `/`. A path is matched a segment at a
|
|
10
|
+
* time, and a `*` or a `[!a]` that swallowed a slash would let one segment of
|
|
11
|
+
* a pattern match two of a path.
|
|
12
|
+
*/
|
|
13
|
+
export const SLASH = 0x2f;
|
|
14
|
+
export const DOT = 0x2e;
|
|
15
|
+
export const MAX_CODE_POINT = 0x10ffff;
|
|
16
|
+
/** The separator, and nothing else. */
|
|
17
|
+
export const SEPARATOR = { negated: false, ranges: [[SLASH, SLASH]], separator: true };
|
|
18
|
+
/** Any character but the separator: `?`, and the body of `*`. */
|
|
19
|
+
export const ANY = { negated: true, ranges: [], separator: false };
|
|
20
|
+
export function literalSet(point) {
|
|
21
|
+
return { negated: false, ranges: [[point, point]], separator: point === SLASH };
|
|
22
|
+
}
|
|
23
|
+
export function classSet(ranges, negated) {
|
|
24
|
+
return { negated, ranges, separator: false };
|
|
25
|
+
}
|
|
26
|
+
function within(ranges, point) {
|
|
27
|
+
for (let i = 0; i < ranges.length; i += 1) {
|
|
28
|
+
const range = ranges[i];
|
|
29
|
+
if (point >= range[0] && point <= range[1])
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
/** Whether a set accepts a code point as written. */
|
|
35
|
+
export function accepts(set, point) {
|
|
36
|
+
if (point === SLASH)
|
|
37
|
+
return set.separator;
|
|
38
|
+
return within(set.ranges, point) !== set.negated;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The code points a code point is the same letter as, ignoring case: itself,
|
|
42
|
+
* and its lower- and upper-case forms where each is a single code point.
|
|
43
|
+
*
|
|
44
|
+
* Simple case mapping, which is what `toLowerCase` and `toUpperCase` give one
|
|
45
|
+
* character at a time. It is locale-free, so two hosts agree; `ß` has no single
|
|
46
|
+
* upper-case code point and so matches only itself.
|
|
47
|
+
*/
|
|
48
|
+
export function caseVariants(point) {
|
|
49
|
+
if (point < 0x80) {
|
|
50
|
+
if (point >= 0x41 && point <= 0x5a)
|
|
51
|
+
return [point, point + 32];
|
|
52
|
+
if (point >= 0x61 && point <= 0x7a)
|
|
53
|
+
return [point, point - 32];
|
|
54
|
+
return [point];
|
|
55
|
+
}
|
|
56
|
+
const char = String.fromCodePoint(point);
|
|
57
|
+
const out = [point];
|
|
58
|
+
for (const variant of [char.toLowerCase(), char.toUpperCase()]) {
|
|
59
|
+
const code = variant.codePointAt(0);
|
|
60
|
+
if (variant.length === String.fromCodePoint(code).length && !out.includes(code))
|
|
61
|
+
out.push(code);
|
|
62
|
+
}
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Whether a set accepts a code point with case ignored: whether it accepts
|
|
67
|
+
* the point or one of its case variants. A negated set is negated over the
|
|
68
|
+
* same question, so `[!a]` refuses `A` as well as `a`.
|
|
69
|
+
*/
|
|
70
|
+
export function acceptsIgnoringCase(set, point) {
|
|
71
|
+
if (point === SLASH)
|
|
72
|
+
return set.separator;
|
|
73
|
+
const variants = caseVariants(point);
|
|
74
|
+
let inside = false;
|
|
75
|
+
for (let i = 0; i < variants.length && !inside; i += 1)
|
|
76
|
+
inside = within(set.ranges, variants[i]);
|
|
77
|
+
return inside !== set.negated;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Characters a witness is spelled with when any of them will do, in order of
|
|
81
|
+
* preference. A witness is read by a person deciding whether two scopes really
|
|
82
|
+
* overlap, and `src/x.ts` reads better than `src/\u0000.ts`.
|
|
83
|
+
*/
|
|
84
|
+
const READABLE = [0x78, 0x61, 0x62, 0x30, 0x5f, 0x2d, 0x7e, 0x21, DOT, SLASH];
|
|
85
|
+
/**
|
|
86
|
+
* Every code point at which the answer "which of these sets accept it" can
|
|
87
|
+
* change, readable ones first.
|
|
88
|
+
*
|
|
89
|
+
* Each set accepts a union of intervals, so the sets' memberships are constant
|
|
90
|
+
* between consecutive interval ends. The start of each interval and the point
|
|
91
|
+
* after its end therefore meet every distinct combination of answers, and
|
|
92
|
+
* trying them all decides every question a witness search can ask of one
|
|
93
|
+
* character. The separator and the dot are always included: path validity
|
|
94
|
+
* turns on them.
|
|
95
|
+
*/
|
|
96
|
+
export function boundaryPoints(sets) {
|
|
97
|
+
// 1, not 0: no path holds a NUL, so the least character worth trying is the next.
|
|
98
|
+
const points = [...READABLE, 1];
|
|
99
|
+
for (const set of sets) {
|
|
100
|
+
for (const [low, high] of set.ranges) {
|
|
101
|
+
points.push(low);
|
|
102
|
+
if (high < MAX_CODE_POINT)
|
|
103
|
+
points.push(high + 1);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const seen = new Set();
|
|
107
|
+
const out = [];
|
|
108
|
+
for (const point of points) {
|
|
109
|
+
if (seen.has(point))
|
|
110
|
+
continue;
|
|
111
|
+
seen.add(point);
|
|
112
|
+
out.push(point);
|
|
113
|
+
}
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=charset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"charset.js","sourceRoot":"","sources":["../../../../src/vendor/spec-core/pattern/charset.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Globs, in the three dialects the spec-* tools speak, compiled to one kind of
|
|
3
|
+
* automaton.
|
|
4
|
+
*
|
|
5
|
+
* The syntax is the part people type: `*`, `**`, `?`, `[abc]`, `[!a-z]`,
|
|
6
|
+
* `{a,b}`, and `\` to escape. What differs between the tools is not the
|
|
7
|
+
* syntax but what a pattern is matched against, and those differences are
|
|
8
|
+
* deliberate, so each has a name (docs/adr/0003-glob-dialects.md):
|
|
9
|
+
*
|
|
10
|
+
* - `path` - the whole repository-relative path, anchored at the root. A
|
|
11
|
+
* pattern with no glob syntax names a file, a directory, or either, as the
|
|
12
|
+
* caller says; `src/auth` may cover `src/auth/login.ts`.
|
|
13
|
+
* - `ripgrep` - as ripgrep's `-g`: a pattern with no `/` is matched against
|
|
14
|
+
* the last segment at any depth, so `*.ts` matches `src/deep/a.ts`; one with
|
|
15
|
+
* a `/` is matched against the whole path.
|
|
16
|
+
* - `gitignore` - as an exclusion list reads: a pattern matches a path or any
|
|
17
|
+
* directory above it, so `tests` excludes everything under any `tests`; one
|
|
18
|
+
* with a `/` other than a trailing one is anchored at the root, and a
|
|
19
|
+
* leading `/` only anchors.
|
|
20
|
+
*
|
|
21
|
+
* Shared by all three:
|
|
22
|
+
*
|
|
23
|
+
* - `**` is a globstar only as a whole segment. `a/**\/b` matches `a/b` and
|
|
24
|
+
* `a/x/y/b`; a trailing `/**` matches everything inside a directory and not
|
|
25
|
+
* the directory itself. Two stars inside a name, `**.md`, are refused: the
|
|
26
|
+
* tools read it three ways, and the quiet reading narrowed their scope.
|
|
27
|
+
* - `*`, `?` and classes never match `/`, and `*` matches a leading dot.
|
|
28
|
+
* - Case is the caller's decision, stated every time. A result must not
|
|
29
|
+
* depend on the host it ran on.
|
|
30
|
+
* - A malformed pattern is an error, never a literal. An unclosed `[` or `{`,
|
|
31
|
+
* an extended glob, a `..` - each is refused with a reason, because a typo
|
|
32
|
+
* read as a literal is a scope that silently matches nothing. An extended
|
|
33
|
+
* glob is a group holding a `|`, `+(a|b)`: without one, `C++(notes).md` is
|
|
34
|
+
* a name with parentheses in it, as ripgrep and `.gitignore` read it.
|
|
35
|
+
*/
|
|
36
|
+
import { type Automaton, type Witness } from './automaton.js';
|
|
37
|
+
export type GlobDialect = 'path' | 'ripgrep' | 'gitignore';
|
|
38
|
+
/** How a `path` pattern with no glob syntax is read. */
|
|
39
|
+
export type LiteralReading = 'file' | 'directory' | 'either';
|
|
40
|
+
export interface GlobOptions {
|
|
41
|
+
readonly dialect: GlobDialect;
|
|
42
|
+
/** Whether `A` and `a` differ. No default: the caller decides, every time. */
|
|
43
|
+
readonly caseSensitive: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* `path` dialect only: how a pattern with no glob syntax is read - as a
|
|
46
|
+
* file, as a directory and everything beneath it, or as either. A function
|
|
47
|
+
* is asked per literal path, for a caller that knows the tree. `either` when
|
|
48
|
+
* unset. A trailing `/` always means a directory.
|
|
49
|
+
*/
|
|
50
|
+
readonly literal?: LiteralReading | ((path: string) => LiteralReading) | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* `escape` (the default): `\` escapes the next character, and a `\` before a
|
|
53
|
+
* letter or digit is refused as a Windows separator typed by mistake.
|
|
54
|
+
* `separator`: every `\` is a `/`, for patterns typed on a Windows shell.
|
|
55
|
+
*/
|
|
56
|
+
readonly backslash?: 'escape' | 'separator' | undefined;
|
|
57
|
+
}
|
|
58
|
+
export interface Glob {
|
|
59
|
+
readonly source: string;
|
|
60
|
+
readonly dialect: GlobDialect;
|
|
61
|
+
readonly caseSensitive: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* The directories a walk must enter to find every match: one per
|
|
64
|
+
* alternative, the leading literal segments. `''` for an alternative that
|
|
65
|
+
* can match at any depth.
|
|
66
|
+
*/
|
|
67
|
+
readonly bases: readonly string[];
|
|
68
|
+
readonly automaton: Automaton;
|
|
69
|
+
/** Whether a canonical path - POSIX, no `.`, no empty or trailing segment - matches. */
|
|
70
|
+
match(path: string): boolean;
|
|
71
|
+
}
|
|
72
|
+
export type GlobParse = {
|
|
73
|
+
readonly ok: true;
|
|
74
|
+
readonly glob: Glob;
|
|
75
|
+
} | {
|
|
76
|
+
readonly ok: false;
|
|
77
|
+
readonly error: string;
|
|
78
|
+
};
|
|
79
|
+
export declare class GlobError extends Error {
|
|
80
|
+
readonly source: string;
|
|
81
|
+
constructor(source: string, reason: string);
|
|
82
|
+
}
|
|
83
|
+
/** More alternatives than this is a pattern nobody meant. */
|
|
84
|
+
export declare const MAX_ALTERNATIVES = 256;
|
|
85
|
+
/** Whether a string uses glob syntax at all. */
|
|
86
|
+
export declare function isGlobSyntax(source: string): boolean;
|
|
87
|
+
/** Parses and compiles a glob, or says why it cannot. */
|
|
88
|
+
export declare function parseGlob(source: string, options: GlobOptions): GlobParse;
|
|
89
|
+
/** Parses and compiles a glob, throwing {@link GlobError} when it cannot. */
|
|
90
|
+
export declare function compileGlob(source: string, options: GlobOptions): Glob;
|
|
91
|
+
/**
|
|
92
|
+
* A shortest path every glob in `include` matches and no glob in `exclude`
|
|
93
|
+
* does: the file two scopes would both write, less what either protects.
|
|
94
|
+
* `none` is a proof that there is no such path. Case-sensitive globs only.
|
|
95
|
+
*/
|
|
96
|
+
export declare function globWitness(include: readonly Glob[], exclude?: readonly Glob[], budget?: number): Witness;
|
|
97
|
+
/**
|
|
98
|
+
* Whether every path `inner` matches is matched by one of `outer`: `true`,
|
|
99
|
+
* `false`, or `undecided` when the search met its budget.
|
|
100
|
+
*/
|
|
101
|
+
export declare function globCovers(outer: readonly Glob[], inner: Glob, budget?: number): boolean | 'undecided';
|
|
102
|
+
export interface GlobList {
|
|
103
|
+
/** Whether a path is in: the last entry that matches it decides, and a `!` entry takes it out. */
|
|
104
|
+
match(path: string): boolean;
|
|
105
|
+
readonly entries: readonly {
|
|
106
|
+
readonly negated: boolean;
|
|
107
|
+
readonly glob: Glob;
|
|
108
|
+
}[];
|
|
109
|
+
}
|
|
110
|
+
export type GlobListParse = {
|
|
111
|
+
readonly ok: true;
|
|
112
|
+
readonly list: GlobList;
|
|
113
|
+
} | {
|
|
114
|
+
readonly ok: false;
|
|
115
|
+
readonly error: string;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* A list of patterns read the way a `.gitignore` reads: in order, each entry
|
|
119
|
+
* deciding the paths it matches, a leading `!` taking them back out.
|
|
120
|
+
*/
|
|
121
|
+
export declare function parseGlobList(patterns: readonly string[], options: GlobOptions): GlobListParse;
|
|
122
|
+
//# sourceMappingURL=glob.d.ts.map
|