@pattern-algebra/core 0.0.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/README.md +571 -0
- package/dist/automaton/complement.d.ts +20 -0
- package/dist/automaton/complement.d.ts.map +1 -0
- package/dist/automaton/complement.js +36 -0
- package/dist/automaton/complement.js.map +1 -0
- package/dist/automaton/complement.test.d.ts +2 -0
- package/dist/automaton/complement.test.d.ts.map +1 -0
- package/dist/automaton/complement.test.js +114 -0
- package/dist/automaton/complement.test.js.map +1 -0
- package/dist/automaton/determinize.d.ts +41 -0
- package/dist/automaton/determinize.d.ts.map +1 -0
- package/dist/automaton/determinize.js +310 -0
- package/dist/automaton/determinize.js.map +1 -0
- package/dist/automaton/determinize.test.d.ts +2 -0
- package/dist/automaton/determinize.test.d.ts.map +1 -0
- package/dist/automaton/determinize.test.js +134 -0
- package/dist/automaton/determinize.test.js.map +1 -0
- package/dist/automaton/emptiness.d.ts +41 -0
- package/dist/automaton/emptiness.d.ts.map +1 -0
- package/dist/automaton/emptiness.js +262 -0
- package/dist/automaton/emptiness.js.map +1 -0
- package/dist/automaton/emptiness.test.d.ts +2 -0
- package/dist/automaton/emptiness.test.d.ts.map +1 -0
- package/dist/automaton/emptiness.test.js +154 -0
- package/dist/automaton/emptiness.test.js.map +1 -0
- package/dist/automaton/index.d.ts +10 -0
- package/dist/automaton/index.d.ts.map +1 -0
- package/dist/automaton/index.js +11 -0
- package/dist/automaton/index.js.map +1 -0
- package/dist/automaton/intersect.d.ts +35 -0
- package/dist/automaton/intersect.d.ts.map +1 -0
- package/dist/automaton/intersect.js +302 -0
- package/dist/automaton/intersect.js.map +1 -0
- package/dist/automaton/pattern-algebra.d.ts +62 -0
- package/dist/automaton/pattern-algebra.d.ts.map +1 -0
- package/dist/automaton/pattern-algebra.js +309 -0
- package/dist/automaton/pattern-algebra.js.map +1 -0
- package/dist/automaton/pattern-algebra.test.d.ts +2 -0
- package/dist/automaton/pattern-algebra.test.d.ts.map +1 -0
- package/dist/automaton/pattern-algebra.test.js +223 -0
- package/dist/automaton/pattern-algebra.test.js.map +1 -0
- package/dist/compile/automaton-builder.d.ts +47 -0
- package/dist/compile/automaton-builder.d.ts.map +1 -0
- package/dist/compile/automaton-builder.js +211 -0
- package/dist/compile/automaton-builder.js.map +1 -0
- package/dist/compile/compiler.d.ts +32 -0
- package/dist/compile/compiler.d.ts.map +1 -0
- package/dist/compile/compiler.js +47 -0
- package/dist/compile/compiler.js.map +1 -0
- package/dist/compile/index.d.ts +8 -0
- package/dist/compile/index.d.ts.map +1 -0
- package/dist/compile/index.js +8 -0
- package/dist/compile/index.js.map +1 -0
- package/dist/compile/quick-reject.d.ts +28 -0
- package/dist/compile/quick-reject.d.ts.map +1 -0
- package/dist/compile/quick-reject.js +147 -0
- package/dist/compile/quick-reject.js.map +1 -0
- package/dist/containment/analysis.d.ts +60 -0
- package/dist/containment/analysis.d.ts.map +1 -0
- package/dist/containment/analysis.js +378 -0
- package/dist/containment/analysis.js.map +1 -0
- package/dist/containment/containment.d.ts +23 -0
- package/dist/containment/containment.d.ts.map +1 -0
- package/dist/containment/containment.js +681 -0
- package/dist/containment/containment.js.map +1 -0
- package/dist/containment/containment.test.d.ts +2 -0
- package/dist/containment/containment.test.d.ts.map +1 -0
- package/dist/containment/containment.test.js +209 -0
- package/dist/containment/containment.test.js.map +1 -0
- package/dist/containment/index.d.ts +7 -0
- package/dist/containment/index.d.ts.map +1 -0
- package/dist/containment/index.js +7 -0
- package/dist/containment/index.js.map +1 -0
- package/dist/core-alpha.d.ts +1253 -0
- package/dist/core-beta.d.ts +1253 -0
- package/dist/core-public.d.ts +1253 -0
- package/dist/core-unstripped.d.ts +1253 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/match/index.d.ts +8 -0
- package/dist/match/index.d.ts.map +1 -0
- package/dist/match/index.js +8 -0
- package/dist/match/index.js.map +1 -0
- package/dist/match/matcher.d.ts +40 -0
- package/dist/match/matcher.d.ts.map +1 -0
- package/dist/match/matcher.js +256 -0
- package/dist/match/matcher.js.map +1 -0
- package/dist/match/matcher.test.d.ts +2 -0
- package/dist/match/matcher.test.d.ts.map +1 -0
- package/dist/match/matcher.test.js +185 -0
- package/dist/match/matcher.test.js.map +1 -0
- package/dist/match/path-utils.d.ts +132 -0
- package/dist/match/path-utils.d.ts.map +1 -0
- package/dist/match/path-utils.js +223 -0
- package/dist/match/path-utils.js.map +1 -0
- package/dist/match/path-utils.test.d.ts +2 -0
- package/dist/match/path-utils.test.d.ts.map +1 -0
- package/dist/match/path-utils.test.js +193 -0
- package/dist/match/path-utils.test.js.map +1 -0
- package/dist/match/segment-matcher.d.ts +25 -0
- package/dist/match/segment-matcher.d.ts.map +1 -0
- package/dist/match/segment-matcher.js +267 -0
- package/dist/match/segment-matcher.js.map +1 -0
- package/dist/parse/brace-expansion.d.ts +34 -0
- package/dist/parse/brace-expansion.d.ts.map +1 -0
- package/dist/parse/brace-expansion.js +294 -0
- package/dist/parse/brace-expansion.js.map +1 -0
- package/dist/parse/brace-expansion.test.d.ts +2 -0
- package/dist/parse/brace-expansion.test.d.ts.map +1 -0
- package/dist/parse/brace-expansion.test.js +105 -0
- package/dist/parse/brace-expansion.test.js.map +1 -0
- package/dist/parse/index.d.ts +8 -0
- package/dist/parse/index.d.ts.map +1 -0
- package/dist/parse/index.js +8 -0
- package/dist/parse/index.js.map +1 -0
- package/dist/parse/parser.d.ts +15 -0
- package/dist/parse/parser.d.ts.map +1 -0
- package/dist/parse/parser.js +526 -0
- package/dist/parse/parser.js.map +1 -0
- package/dist/parse/parser.test.d.ts +2 -0
- package/dist/parse/parser.test.d.ts.map +1 -0
- package/dist/parse/parser.test.js +266 -0
- package/dist/parse/parser.test.js.map +1 -0
- package/dist/parse/validator.d.ts +30 -0
- package/dist/parse/validator.d.ts.map +1 -0
- package/dist/parse/validator.js +115 -0
- package/dist/parse/validator.js.map +1 -0
- package/dist/parse/validator.test.d.ts +2 -0
- package/dist/parse/validator.test.d.ts.map +1 -0
- package/dist/parse/validator.test.js +45 -0
- package/dist/parse/validator.test.js.map +1 -0
- package/dist/types/ast.d.ts +158 -0
- package/dist/types/ast.d.ts.map +1 -0
- package/dist/types/ast.js +2 -0
- package/dist/types/ast.js.map +1 -0
- package/dist/types/automaton.d.ts +150 -0
- package/dist/types/automaton.d.ts.map +1 -0
- package/dist/types/automaton.js +2 -0
- package/dist/types/automaton.js.map +1 -0
- package/dist/types/containment.d.ts +257 -0
- package/dist/types/containment.d.ts.map +1 -0
- package/dist/types/containment.js +5 -0
- package/dist/types/containment.js.map +1 -0
- package/dist/types/errors.d.ts +37 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +24 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Automaton emptiness checking and witness finding.
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
import type { SegmentAutomaton } from '../types';
|
|
6
|
+
/**
|
|
7
|
+
* Check if an automaton's language is empty.
|
|
8
|
+
*
|
|
9
|
+
* Uses reachability analysis from the initial state to any accepting state.
|
|
10
|
+
*
|
|
11
|
+
* @param automaton - The automaton to check
|
|
12
|
+
* @returns true if the automaton accepts no strings
|
|
13
|
+
*
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
export declare function isEmpty(automaton: SegmentAutomaton): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Find a witness string accepted by the automaton.
|
|
19
|
+
*
|
|
20
|
+
* If the automaton is non-empty, returns a path (sequence of segments)
|
|
21
|
+
* that leads to an accepting state.
|
|
22
|
+
*
|
|
23
|
+
* @param automaton - The automaton to find a witness for
|
|
24
|
+
* @returns A witness path string, or undefined if the language is empty
|
|
25
|
+
*
|
|
26
|
+
* @public
|
|
27
|
+
*/
|
|
28
|
+
export declare function findWitness(automaton: SegmentAutomaton): string | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* Count the number of accepting paths of a given length.
|
|
31
|
+
*
|
|
32
|
+
* Useful for understanding the "size" of a pattern's language.
|
|
33
|
+
*
|
|
34
|
+
* @param automaton - The automaton
|
|
35
|
+
* @param maxDepth - Maximum path length to consider
|
|
36
|
+
* @returns Object with counts per depth
|
|
37
|
+
*
|
|
38
|
+
* @public
|
|
39
|
+
*/
|
|
40
|
+
export declare function countPaths(automaton: SegmentAutomaton, maxDepth: number): Map<number, number>;
|
|
41
|
+
//# sourceMappingURL=emptiness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emptiness.d.ts","sourceRoot":"","sources":["../../src/automaton/emptiness.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAuC,MAAM,UAAU,CAAA;AAErF;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,SAAS,EAAE,gBAAgB,GAAG,OAAO,CAW5D;AA6CD;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,gBAAgB,GAAG,MAAM,GAAG,SAAS,CAoF3E;AAsED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CA4C7F"}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Automaton emptiness checking and witness finding.
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Check if an automaton's language is empty.
|
|
7
|
+
*
|
|
8
|
+
* Uses reachability analysis from the initial state to any accepting state.
|
|
9
|
+
*
|
|
10
|
+
* @param automaton - The automaton to check
|
|
11
|
+
* @returns true if the automaton accepts no strings
|
|
12
|
+
*
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
export function isEmpty(automaton) {
|
|
16
|
+
// Check if any accepting state is reachable from initial state
|
|
17
|
+
const reachable = findReachableStates(automaton);
|
|
18
|
+
for (const acceptingId of automaton.acceptingStates) {
|
|
19
|
+
if (reachable.has(acceptingId)) {
|
|
20
|
+
return false; // Found a reachable accepting state
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return true; // No accepting state is reachable
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Find all states reachable from the initial state.
|
|
27
|
+
*/
|
|
28
|
+
function findReachableStates(automaton) {
|
|
29
|
+
const reachable = new Set();
|
|
30
|
+
const worklist = [automaton.initialState];
|
|
31
|
+
while (worklist.length > 0) {
|
|
32
|
+
const stateId = worklist.pop();
|
|
33
|
+
if (reachable.has(stateId))
|
|
34
|
+
continue;
|
|
35
|
+
reachable.add(stateId);
|
|
36
|
+
const state = automaton.states[stateId];
|
|
37
|
+
if (!state)
|
|
38
|
+
continue;
|
|
39
|
+
for (const transition of state.transitions) {
|
|
40
|
+
const targets = getTransitionTargets(transition);
|
|
41
|
+
for (const target of targets) {
|
|
42
|
+
if (!reachable.has(target)) {
|
|
43
|
+
worklist.push(target);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return reachable;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Get all target states from a transition.
|
|
52
|
+
*/
|
|
53
|
+
function getTransitionTargets(transition) {
|
|
54
|
+
switch (transition.type) {
|
|
55
|
+
case 'literal':
|
|
56
|
+
case 'wildcard':
|
|
57
|
+
case 'epsilon':
|
|
58
|
+
return [transition.target];
|
|
59
|
+
case 'globstar':
|
|
60
|
+
return [transition.selfLoop, transition.exit];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Find a witness string accepted by the automaton.
|
|
65
|
+
*
|
|
66
|
+
* If the automaton is non-empty, returns a path (sequence of segments)
|
|
67
|
+
* that leads to an accepting state.
|
|
68
|
+
*
|
|
69
|
+
* @param automaton - The automaton to find a witness for
|
|
70
|
+
* @returns A witness path string, or undefined if the language is empty
|
|
71
|
+
*
|
|
72
|
+
* @public
|
|
73
|
+
*/
|
|
74
|
+
export function findWitness(automaton) {
|
|
75
|
+
const visited = new Set();
|
|
76
|
+
const queue = [{ stateId: automaton.initialState, path: [] }];
|
|
77
|
+
// First, handle epsilon closure from initial state
|
|
78
|
+
const initialClosure = epsilonClosure(automaton, automaton.initialState);
|
|
79
|
+
for (const stateId of initialClosure) {
|
|
80
|
+
if (automaton.states[stateId]?.accepting) {
|
|
81
|
+
return '/'; // Empty path matches
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Add all states in initial closure to queue
|
|
85
|
+
for (const stateId of initialClosure) {
|
|
86
|
+
if (stateId !== automaton.initialState) {
|
|
87
|
+
queue.push({ stateId, path: [] });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
while (queue.length > 0) {
|
|
91
|
+
const { stateId, path } = queue.shift();
|
|
92
|
+
if (visited.has(stateId))
|
|
93
|
+
continue;
|
|
94
|
+
visited.add(stateId);
|
|
95
|
+
const state = automaton.states[stateId];
|
|
96
|
+
if (!state)
|
|
97
|
+
continue;
|
|
98
|
+
// Check if this state is accepting
|
|
99
|
+
if (state.accepting && path.length > 0) {
|
|
100
|
+
return '/' + path.join('/');
|
|
101
|
+
}
|
|
102
|
+
// Explore transitions
|
|
103
|
+
for (const transition of state.transitions) {
|
|
104
|
+
if (transition.type === 'epsilon') {
|
|
105
|
+
// Epsilon: same path, different state
|
|
106
|
+
if (!visited.has(transition.target)) {
|
|
107
|
+
queue.push({ stateId: transition.target, path });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else if (transition.type === 'literal') {
|
|
111
|
+
// Literal: extend path with the segment
|
|
112
|
+
if (!visited.has(transition.target)) {
|
|
113
|
+
queue.push({
|
|
114
|
+
stateId: transition.target,
|
|
115
|
+
path: [...path, transition.segment],
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else if (transition.type === 'wildcard') {
|
|
120
|
+
// Wildcard: generate a sample segment that matches
|
|
121
|
+
const sample = generateMatchingSample(transition.pattern, transition.patternSource);
|
|
122
|
+
if (!visited.has(transition.target)) {
|
|
123
|
+
queue.push({
|
|
124
|
+
stateId: transition.target,
|
|
125
|
+
path: [...path, sample],
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else if (transition.type === 'globstar') {
|
|
130
|
+
// Globstar exit: try exiting immediately (zero segments)
|
|
131
|
+
const exitClosure = epsilonClosure(automaton, transition.exit);
|
|
132
|
+
for (const exitState of exitClosure) {
|
|
133
|
+
if (!visited.has(exitState)) {
|
|
134
|
+
queue.push({ stateId: exitState, path });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Globstar self-loop: consume one segment and continue
|
|
138
|
+
if (!visited.has(transition.selfLoop)) {
|
|
139
|
+
queue.push({
|
|
140
|
+
stateId: transition.selfLoop,
|
|
141
|
+
path: [...path, 'x'], // Generic segment
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return undefined; // No accepting state found
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Compute epsilon closure from a single state.
|
|
151
|
+
*/
|
|
152
|
+
function epsilonClosure(automaton, startState) {
|
|
153
|
+
const closure = new Set();
|
|
154
|
+
const worklist = [startState];
|
|
155
|
+
while (worklist.length > 0) {
|
|
156
|
+
const stateId = worklist.pop();
|
|
157
|
+
if (closure.has(stateId))
|
|
158
|
+
continue;
|
|
159
|
+
closure.add(stateId);
|
|
160
|
+
const state = automaton.states[stateId];
|
|
161
|
+
if (!state)
|
|
162
|
+
continue;
|
|
163
|
+
for (const transition of state.transitions) {
|
|
164
|
+
if (transition.type === 'epsilon') {
|
|
165
|
+
if (!closure.has(transition.target)) {
|
|
166
|
+
worklist.push(transition.target);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else if (transition.type === 'globstar') {
|
|
170
|
+
// Globstar exit is epsilon-reachable
|
|
171
|
+
if (!closure.has(transition.exit)) {
|
|
172
|
+
worklist.push(transition.exit);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return closure;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Generate a sample segment that matches a pattern.
|
|
181
|
+
*/
|
|
182
|
+
function generateMatchingSample(pattern, patternSource) {
|
|
183
|
+
// Try to generate a sensible sample based on the pattern source
|
|
184
|
+
if (patternSource.includes('.ts')) {
|
|
185
|
+
return 'file.ts';
|
|
186
|
+
}
|
|
187
|
+
if (patternSource.includes('.js')) {
|
|
188
|
+
return 'file.js';
|
|
189
|
+
}
|
|
190
|
+
if (patternSource.startsWith('*.')) {
|
|
191
|
+
const ext = patternSource.slice(1);
|
|
192
|
+
return `sample${ext}`;
|
|
193
|
+
}
|
|
194
|
+
if (patternSource.endsWith('*')) {
|
|
195
|
+
const prefix = patternSource.slice(0, -1);
|
|
196
|
+
return `${prefix}sample`;
|
|
197
|
+
}
|
|
198
|
+
if (patternSource.startsWith('*')) {
|
|
199
|
+
const suffix = patternSource.slice(1);
|
|
200
|
+
return `sample${suffix}`;
|
|
201
|
+
}
|
|
202
|
+
// Default: try some common segments
|
|
203
|
+
const samples = ['file', 'dir', 'foo', 'bar', 'test', 'src', 'index.ts'];
|
|
204
|
+
for (const sample of samples) {
|
|
205
|
+
if (pattern.test(sample)) {
|
|
206
|
+
return sample;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return 'segment';
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Count the number of accepting paths of a given length.
|
|
213
|
+
*
|
|
214
|
+
* Useful for understanding the "size" of a pattern's language.
|
|
215
|
+
*
|
|
216
|
+
* @param automaton - The automaton
|
|
217
|
+
* @param maxDepth - Maximum path length to consider
|
|
218
|
+
* @returns Object with counts per depth
|
|
219
|
+
*
|
|
220
|
+
* @public
|
|
221
|
+
*/
|
|
222
|
+
export function countPaths(automaton, maxDepth) {
|
|
223
|
+
const counts = new Map();
|
|
224
|
+
// Dynamic programming: count[state][depth] = number of paths
|
|
225
|
+
// This is exponential in worst case, so we cap at maxDepth
|
|
226
|
+
const memo = new Map();
|
|
227
|
+
const countFrom = (stateId, depth) => {
|
|
228
|
+
if (depth > maxDepth)
|
|
229
|
+
return 0;
|
|
230
|
+
const key = `${stateId}:${depth}`;
|
|
231
|
+
if (memo.has(key))
|
|
232
|
+
return memo.get(key);
|
|
233
|
+
const state = automaton.states[stateId];
|
|
234
|
+
if (!state)
|
|
235
|
+
return 0;
|
|
236
|
+
let total = 0;
|
|
237
|
+
// Count if accepting at this depth
|
|
238
|
+
if (state.accepting) {
|
|
239
|
+
total++;
|
|
240
|
+
counts.set(depth, (counts.get(depth) ?? 0) + 1);
|
|
241
|
+
}
|
|
242
|
+
// Count paths through transitions
|
|
243
|
+
for (const transition of state.transitions) {
|
|
244
|
+
if (transition.type === 'epsilon') {
|
|
245
|
+
total += countFrom(transition.target, depth);
|
|
246
|
+
}
|
|
247
|
+
else if (transition.type === 'globstar') {
|
|
248
|
+
total += countFrom(transition.exit, depth);
|
|
249
|
+
total += countFrom(transition.selfLoop, depth + 1);
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
const target = transition.type === 'literal' || transition.type === 'wildcard' ? transition.target : 0;
|
|
253
|
+
total += countFrom(target, depth + 1);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
memo.set(key, total);
|
|
257
|
+
return total;
|
|
258
|
+
};
|
|
259
|
+
countFrom(automaton.initialState, 0);
|
|
260
|
+
return counts;
|
|
261
|
+
}
|
|
262
|
+
//# sourceMappingURL=emptiness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emptiness.js","sourceRoot":"","sources":["../../src/automaton/emptiness.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emptiness.test.d.ts","sourceRoot":"","sources":["../../src/automaton/emptiness.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { isEmpty, findWitness, countPaths } from './emptiness';
|
|
3
|
+
import { buildAutomaton } from '../compile/automaton-builder';
|
|
4
|
+
import { parsePattern } from '../parse';
|
|
5
|
+
import { compilePattern } from '../compile';
|
|
6
|
+
import { matchPath } from '../match';
|
|
7
|
+
describe('isEmpty', () => {
|
|
8
|
+
describe('non-empty automata', () => {
|
|
9
|
+
it('returns false for simple pattern', () => {
|
|
10
|
+
const pattern = parsePattern('src/index.ts');
|
|
11
|
+
const automaton = buildAutomaton(pattern);
|
|
12
|
+
expect(isEmpty(automaton)).toBe(false);
|
|
13
|
+
});
|
|
14
|
+
it('returns false for wildcard pattern', () => {
|
|
15
|
+
const pattern = parsePattern('*.ts');
|
|
16
|
+
const automaton = buildAutomaton(pattern);
|
|
17
|
+
expect(isEmpty(automaton)).toBe(false);
|
|
18
|
+
});
|
|
19
|
+
it('returns false for globstar pattern', () => {
|
|
20
|
+
const pattern = parsePattern('**/*.ts');
|
|
21
|
+
const automaton = buildAutomaton(pattern);
|
|
22
|
+
expect(isEmpty(automaton)).toBe(false);
|
|
23
|
+
});
|
|
24
|
+
it('returns false for alternation pattern', () => {
|
|
25
|
+
const pattern = parsePattern('{src,lib}/*.ts');
|
|
26
|
+
const automaton = buildAutomaton(pattern);
|
|
27
|
+
expect(isEmpty(automaton)).toBe(false);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
describe('empty automata', () => {
|
|
31
|
+
// Note: isEmpty uses graph reachability, not semantic emptiness.
|
|
32
|
+
// For automata with wildcard transitions, the intersection may have
|
|
33
|
+
// reachable accepting states even if the language is semantically empty.
|
|
34
|
+
// Full semantic emptiness would require checking satisfiability of
|
|
35
|
+
// intersected wildcard patterns, which is beyond current implementation.
|
|
36
|
+
it('returns true for automaton with no accepting states', () => {
|
|
37
|
+
const pattern = parsePattern('src/index.ts');
|
|
38
|
+
const automaton = buildAutomaton(pattern);
|
|
39
|
+
// Create an automaton with no accepting states
|
|
40
|
+
const emptyAutomaton = {
|
|
41
|
+
...automaton,
|
|
42
|
+
acceptingStates: [],
|
|
43
|
+
states: automaton.states.map((s) => ({ ...s, accepting: false })),
|
|
44
|
+
};
|
|
45
|
+
expect(isEmpty(emptyAutomaton)).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
it('returns true for automaton with unreachable accepting state', () => {
|
|
48
|
+
const pattern = parsePattern('src/index.ts');
|
|
49
|
+
const automaton = buildAutomaton(pattern);
|
|
50
|
+
// Remove all transitions from initial state to make accepting states unreachable
|
|
51
|
+
const disconnectedAutomaton = {
|
|
52
|
+
...automaton,
|
|
53
|
+
states: automaton.states.map((s, i) => (i === automaton.initialState ? { ...s, transitions: [] } : s)),
|
|
54
|
+
};
|
|
55
|
+
expect(isEmpty(disconnectedAutomaton)).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
describe('findWitness', () => {
|
|
60
|
+
describe('finding witnesses', () => {
|
|
61
|
+
it('returns a matching path for simple pattern', () => {
|
|
62
|
+
const pattern = parsePattern('src/index.ts');
|
|
63
|
+
const automaton = buildAutomaton(pattern);
|
|
64
|
+
const witness = findWitness(automaton);
|
|
65
|
+
expect(witness).toBeDefined();
|
|
66
|
+
expect(witness).toContain('src');
|
|
67
|
+
expect(witness).toContain('index.ts');
|
|
68
|
+
});
|
|
69
|
+
it('returns a matching path for wildcard pattern', () => {
|
|
70
|
+
const pattern = parsePattern('*.ts');
|
|
71
|
+
const automaton = buildAutomaton(pattern);
|
|
72
|
+
const witness = findWitness(automaton);
|
|
73
|
+
expect(witness).toBeDefined();
|
|
74
|
+
expect(witness).toMatch(/\.ts$/);
|
|
75
|
+
});
|
|
76
|
+
it('returns a matching path for globstar pattern', () => {
|
|
77
|
+
const pattern = parsePattern('src/**/*.ts');
|
|
78
|
+
const automaton = buildAutomaton(pattern);
|
|
79
|
+
const witness = findWitness(automaton);
|
|
80
|
+
expect(witness).toBeDefined();
|
|
81
|
+
expect(witness).toMatch(/^\/src\//);
|
|
82
|
+
expect(witness).toMatch(/\.ts$/);
|
|
83
|
+
});
|
|
84
|
+
it('returns undefined for automaton with no accepting states', () => {
|
|
85
|
+
const pattern = parsePattern('src/index.ts');
|
|
86
|
+
const automaton = buildAutomaton(pattern);
|
|
87
|
+
// Create an automaton with no accepting states
|
|
88
|
+
const emptyAutomaton = {
|
|
89
|
+
...automaton,
|
|
90
|
+
acceptingStates: [],
|
|
91
|
+
states: automaton.states.map((s) => ({ ...s, accepting: false })),
|
|
92
|
+
};
|
|
93
|
+
const witness = findWitness(emptyAutomaton);
|
|
94
|
+
expect(witness).toBeUndefined();
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
describe('witness validity', () => {
|
|
98
|
+
it('witness actually matches the pattern', () => {
|
|
99
|
+
const compiled = compilePattern(parsePattern('src/**/*.ts'));
|
|
100
|
+
const witness = findWitness(compiled.automaton);
|
|
101
|
+
expect(witness).toBeDefined();
|
|
102
|
+
// The witness is already a path string, verify it matches
|
|
103
|
+
expect(matchPath(witness, compiled)).toBe(true);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
describe('countPaths', () => {
|
|
108
|
+
describe('bounded patterns', () => {
|
|
109
|
+
it('returns correct count for single literal', () => {
|
|
110
|
+
const pattern = parsePattern('src/index.ts');
|
|
111
|
+
const automaton = buildAutomaton(pattern);
|
|
112
|
+
const counts = countPaths(automaton, 5);
|
|
113
|
+
// Exactly one path of length 2
|
|
114
|
+
expect(counts.get(2)).toBe(1);
|
|
115
|
+
});
|
|
116
|
+
it('returns counts for multiple depths', () => {
|
|
117
|
+
const pattern = parsePattern('src/*.ts');
|
|
118
|
+
const automaton = buildAutomaton(pattern);
|
|
119
|
+
const counts = countPaths(automaton, 5);
|
|
120
|
+
// Should have paths at depth 2
|
|
121
|
+
expect(counts.get(2)).toBeGreaterThanOrEqual(1);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
describe('unbounded patterns', () => {
|
|
125
|
+
it('returns counts up to maxDepth for globstar', () => {
|
|
126
|
+
const pattern = parsePattern('src/**');
|
|
127
|
+
const automaton = buildAutomaton(pattern);
|
|
128
|
+
const counts = countPaths(automaton, 5);
|
|
129
|
+
// Should have paths at depths 1, 2, 3, 4, 5
|
|
130
|
+
expect(counts.get(1)).toBeGreaterThanOrEqual(1);
|
|
131
|
+
expect(counts.get(2)).toBeGreaterThanOrEqual(1);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
describe('empty patterns', () => {
|
|
135
|
+
it('returns zero paths for automaton with no accepting states', () => {
|
|
136
|
+
const pattern = parsePattern('src/index.ts');
|
|
137
|
+
const automaton = buildAutomaton(pattern);
|
|
138
|
+
// Create an automaton with no accepting states
|
|
139
|
+
const emptyAutomaton = {
|
|
140
|
+
...automaton,
|
|
141
|
+
acceptingStates: [],
|
|
142
|
+
states: automaton.states.map((s) => ({ ...s, accepting: false })),
|
|
143
|
+
};
|
|
144
|
+
const counts = countPaths(emptyAutomaton, 5);
|
|
145
|
+
// All counts should be 0 or map should be empty
|
|
146
|
+
let total = 0;
|
|
147
|
+
for (const count of counts.values()) {
|
|
148
|
+
total += count;
|
|
149
|
+
}
|
|
150
|
+
expect(total).toBe(0);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
//# sourceMappingURL=emptiness.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emptiness.test.js","sourceRoot":"","sources":["../../src/automaton/emptiness.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAEpC,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE;IACvB,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;YAC1C,MAAM,OAAO,GAAG,YAAY,CAAC,cAAc,CAAC,CAAA;YAC5C,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;YAEzC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACxC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;YAC5C,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAA;YACpC,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;YAEzC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACxC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;YAC5C,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,CAAC,CAAA;YACvC,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;YAEzC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACxC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;YAC/C,MAAM,OAAO,GAAG,YAAY,CAAC,gBAAgB,CAAC,CAAA;YAC9C,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;YAEzC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACxC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,iEAAiE;QACjE,oEAAoE;QACpE,yEAAyE;QACzE,mEAAmE;QACnE,yEAAyE;QAEzE,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;YAC7D,MAAM,OAAO,GAAG,YAAY,CAAC,cAAc,CAAC,CAAA;YAC5C,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;YAEzC,+CAA+C;YAC/C,MAAM,cAAc,GAAG;gBACrB,GAAG,SAAS;gBACZ,eAAe,EAAE,EAAE;gBACnB,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;aAClE,CAAA;YAED,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC5C,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;YACrE,MAAM,OAAO,GAAG,YAAY,CAAC,cAAc,CAAC,CAAA;YAC5C,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;YAEzC,iFAAiF;YACjF,MAAM,qBAAqB,GAAG;gBAC5B,GAAG,SAAS;gBACZ,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;aACvG,CAAA;YAED,MAAM,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACnD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;QACjC,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;YACpD,MAAM,OAAO,GAAG,YAAY,CAAC,cAAc,CAAC,CAAA;YAC5C,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;YAEzC,MAAM,OAAO,GAAG,WAAW,CAAC,SAAS,CAAC,CAAA;YAEtC,MAAM,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAA;YAC7B,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;YAChC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAA;QACvC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;YACtD,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAA;YACpC,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;YAEzC,MAAM,OAAO,GAAG,WAAW,CAAC,SAAS,CAAC,CAAA;YAEtC,MAAM,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAA;YAC7B,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QAClC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;YACtD,MAAM,OAAO,GAAG,YAAY,CAAC,aAAa,CAAC,CAAA;YAC3C,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;YAEzC,MAAM,OAAO,GAAG,WAAW,CAAC,SAAS,CAAC,CAAA;YAEtC,MAAM,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAA;YAC7B,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;YACnC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QAClC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;YAClE,MAAM,OAAO,GAAG,YAAY,CAAC,cAAc,CAAC,CAAA;YAC5C,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;YAEzC,+CAA+C;YAC/C,MAAM,cAAc,GAAG;gBACrB,GAAG,SAAS;gBACZ,eAAe,EAAE,EAAE;gBACnB,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;aAClE,CAAA;YAED,MAAM,OAAO,GAAG,WAAW,CAAC,cAAc,CAAC,CAAA;YAE3C,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,CAAA;QACjC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,QAAQ,GAAG,cAAc,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC,CAAA;YAC5D,MAAM,OAAO,GAAG,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;YAE/C,MAAM,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAA;YAE7B,0DAA0D;YAC1D,MAAM,CAAC,SAAS,CAAC,OAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;YAClD,MAAM,OAAO,GAAG,YAAY,CAAC,cAAc,CAAC,CAAA;YAC5C,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;YAEzC,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;YAEvC,+BAA+B;YAC/B,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAC/B,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;YAC5C,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,CAAC,CAAA;YACxC,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;YAEzC,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;YAEvC,+BAA+B;YAC/B,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAA;QACjD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;YACpD,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAA;YACtC,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;YAEzC,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;YAEvC,4CAA4C;YAC5C,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAA;YAC/C,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAA;QACjD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;YACnE,MAAM,OAAO,GAAG,YAAY,CAAC,cAAc,CAAC,CAAA;YAC5C,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;YAEzC,+CAA+C;YAC/C,MAAM,cAAc,GAAG;gBACrB,GAAG,SAAS;gBACZ,eAAe,EAAE,EAAE;gBACnB,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;aAClE,CAAA;YAED,MAAM,MAAM,GAAG,UAAU,CAAC,cAAc,EAAE,CAAC,CAAC,CAAA;YAE5C,gDAAgD;YAChD,IAAI,KAAK,GAAG,CAAC,CAAA;YACb,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;gBACpC,KAAK,IAAI,KAAK,CAAA;YAChB,CAAC;YACD,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACvB,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Automaton operations for pattern containment checking.
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
export { determinize, DEFAULT_MAX_DFA_STATES, type DeterminizeOptions } from './determinize';
|
|
6
|
+
export { complement } from './complement';
|
|
7
|
+
export { intersect, union } from './intersect';
|
|
8
|
+
export { isEmpty, findWitness, countPaths } from './emptiness';
|
|
9
|
+
export { patternIntersect, patternUnion, patternComplement, patternDifference } from './pattern-algebra';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/automaton/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAC5F,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAG9D,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Automaton operations for pattern containment checking.
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
export { determinize, DEFAULT_MAX_DFA_STATES } from './determinize';
|
|
6
|
+
export { complement } from './complement';
|
|
7
|
+
export { intersect, union } from './intersect';
|
|
8
|
+
export { isEmpty, findWitness, countPaths } from './emptiness';
|
|
9
|
+
// Pattern-level set operations
|
|
10
|
+
export { patternIntersect, patternUnion, patternComplement, patternDifference } from './pattern-algebra';
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/automaton/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAA2B,MAAM,eAAe,CAAA;AAC5F,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAE9D,+BAA+B;AAC/B,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Automaton intersection using product construction.
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
import type { SegmentAutomaton } from '../types';
|
|
6
|
+
/**
|
|
7
|
+
* Compute the intersection of two automata using product construction.
|
|
8
|
+
*
|
|
9
|
+
* The resulting automaton accepts a string iff both input automata accept it.
|
|
10
|
+
* L(A ∩ B) = L(A) ∩ L(B)
|
|
11
|
+
*
|
|
12
|
+
* @param a - First automaton
|
|
13
|
+
* @param b - Second automaton
|
|
14
|
+
* @returns Intersection automaton
|
|
15
|
+
*
|
|
16
|
+
* @public
|
|
17
|
+
*/
|
|
18
|
+
export declare function intersect(a: SegmentAutomaton, b: SegmentAutomaton): SegmentAutomaton;
|
|
19
|
+
/**
|
|
20
|
+
* Compute the union of two automata using NFA construction.
|
|
21
|
+
*
|
|
22
|
+
* The resulting automaton accepts a string iff either input automaton accepts it.
|
|
23
|
+
* L(A ∪ B) = L(A) ∪ L(B)
|
|
24
|
+
*
|
|
25
|
+
* We use NFA union: create a new initial state with epsilon transitions
|
|
26
|
+
* to both automata's initial states, then merge the states.
|
|
27
|
+
*
|
|
28
|
+
* @param a - First automaton
|
|
29
|
+
* @param b - Second automaton
|
|
30
|
+
* @returns Union automaton (NFA)
|
|
31
|
+
*
|
|
32
|
+
* @public
|
|
33
|
+
*/
|
|
34
|
+
export declare function union(a: SegmentAutomaton, b: SegmentAutomaton): SegmentAutomaton;
|
|
35
|
+
//# sourceMappingURL=intersect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intersect.d.ts","sourceRoot":"","sources":["../../src/automaton/intersect.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAuD,MAAM,UAAU,CAAA;AAErG;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,gBAAgB,GAAG,gBAAgB,CAEpF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,gBAAgB,GAAG,gBAAgB,CAyChF"}
|