@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,114 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { complement } from './complement';
|
|
3
|
+
import { buildAutomaton } from '../compile/automaton-builder';
|
|
4
|
+
import { parsePattern } from '../parse';
|
|
5
|
+
import { determinize } from './determinize';
|
|
6
|
+
import { compilePattern } from '../compile';
|
|
7
|
+
describe('complement', () => {
|
|
8
|
+
describe('basic complement', () => {
|
|
9
|
+
it('swaps accepting states', () => {
|
|
10
|
+
const pattern = parsePattern('src/index.ts');
|
|
11
|
+
const nfa = buildAutomaton(pattern);
|
|
12
|
+
const dfa = determinize(nfa);
|
|
13
|
+
const original = dfa;
|
|
14
|
+
const complemented = complement(original);
|
|
15
|
+
// Accepting states should differ
|
|
16
|
+
// Originally accepting states become non-accepting
|
|
17
|
+
const originalAccepting = new Set(original.acceptingStates);
|
|
18
|
+
const complementedAccepting = new Set(complemented.acceptingStates);
|
|
19
|
+
// They should not be the same
|
|
20
|
+
expect(complementedAccepting).not.toEqual(originalAccepting);
|
|
21
|
+
});
|
|
22
|
+
it('preserves state count', () => {
|
|
23
|
+
const pattern = parsePattern('src/*.ts');
|
|
24
|
+
const nfa = buildAutomaton(pattern);
|
|
25
|
+
const dfa = determinize(nfa);
|
|
26
|
+
const complemented = complement(dfa);
|
|
27
|
+
expect(complemented.states.length).toBe(dfa.states.length);
|
|
28
|
+
});
|
|
29
|
+
it('preserves deterministic property', () => {
|
|
30
|
+
const pattern = parsePattern('src/*.ts');
|
|
31
|
+
const nfa = buildAutomaton(pattern);
|
|
32
|
+
const dfa = determinize(nfa);
|
|
33
|
+
expect(dfa.isDeterministic).toBe(true);
|
|
34
|
+
const complemented = complement(dfa);
|
|
35
|
+
expect(complemented.isDeterministic).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
describe('accepting state inversion', () => {
|
|
39
|
+
// Note: These tests verify the automaton structure after complement.
|
|
40
|
+
// Testing actual matching behavior with complemented automata requires
|
|
41
|
+
// proper integration with matchPath, which may need additional work.
|
|
42
|
+
it('originally non-accepting states become accepting after complement', () => {
|
|
43
|
+
const pattern = parsePattern('src/index.ts');
|
|
44
|
+
const nfa = buildAutomaton(pattern);
|
|
45
|
+
const dfa = determinize(nfa);
|
|
46
|
+
const complemented = complement(dfa);
|
|
47
|
+
// Find states that were NOT accepting in original
|
|
48
|
+
const originalNonAccepting = dfa.states.filter((s) => !s.accepting).map((s) => s.id);
|
|
49
|
+
// Those states should now be accepting in complemented
|
|
50
|
+
for (const id of originalNonAccepting) {
|
|
51
|
+
const complementedState = complemented.states.find((s) => s.id === id);
|
|
52
|
+
expect(complementedState?.accepting).toBe(true);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
it('originally accepting states become non-accepting after complement', () => {
|
|
56
|
+
const pattern = parsePattern('src/index.ts');
|
|
57
|
+
const nfa = buildAutomaton(pattern);
|
|
58
|
+
const dfa = determinize(nfa);
|
|
59
|
+
const complemented = complement(dfa);
|
|
60
|
+
// Find states that WERE accepting in original
|
|
61
|
+
const originalAccepting = dfa.states.filter((s) => s.accepting).map((s) => s.id);
|
|
62
|
+
// Those states should now be non-accepting in complemented
|
|
63
|
+
for (const id of originalAccepting) {
|
|
64
|
+
const complementedState = complemented.states.find((s) => s.id === id);
|
|
65
|
+
expect(complementedState?.accepting).toBe(false);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
describe('double complement', () => {
|
|
70
|
+
it('double complement is equivalent to original (literal)', () => {
|
|
71
|
+
const original = compilePattern(parsePattern('src/index.ts'));
|
|
72
|
+
const dfa = determinize(original.automaton);
|
|
73
|
+
const complemented = complement(dfa);
|
|
74
|
+
const doubleComplemented = complement(complemented);
|
|
75
|
+
// Double complement should have same accepting states as original
|
|
76
|
+
expect(new Set(doubleComplemented.acceptingStates)).toEqual(new Set(dfa.acceptingStates));
|
|
77
|
+
});
|
|
78
|
+
it('double complement has same state accepting flags as original', () => {
|
|
79
|
+
const original = compilePattern(parsePattern('src/*.ts'));
|
|
80
|
+
const dfa = determinize(original.automaton);
|
|
81
|
+
const doubleComplemented = complement(complement(dfa));
|
|
82
|
+
// Each state should have same accepting flag as original
|
|
83
|
+
for (let i = 0; i < dfa.states.length; i++) {
|
|
84
|
+
expect(doubleComplemented.states[i].accepting).toBe(dfa.states[i].accepting);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
describe('edge cases', () => {
|
|
89
|
+
it('handles automaton with wildcard pattern', () => {
|
|
90
|
+
const pattern = parsePattern('*');
|
|
91
|
+
const nfa = buildAutomaton(pattern);
|
|
92
|
+
const dfa = determinize(nfa);
|
|
93
|
+
const complemented = complement(dfa);
|
|
94
|
+
expect(complemented.states.length).toBe(dfa.states.length);
|
|
95
|
+
});
|
|
96
|
+
it('handles complex globstar pattern', () => {
|
|
97
|
+
const pattern = parsePattern('src/**/*.ts');
|
|
98
|
+
const nfa = buildAutomaton(pattern);
|
|
99
|
+
const dfa = determinize(nfa);
|
|
100
|
+
const complemented = complement(dfa);
|
|
101
|
+
// Complement should preserve structure
|
|
102
|
+
expect(complemented.states.length).toBe(dfa.states.length);
|
|
103
|
+
expect(complemented.isDeterministic).toBe(true);
|
|
104
|
+
// Accepting states should be inverted
|
|
105
|
+
const originalAcceptingSet = new Set(dfa.acceptingStates);
|
|
106
|
+
const complementedAcceptingSet = new Set(complemented.acceptingStates);
|
|
107
|
+
// No state should be in both sets
|
|
108
|
+
for (const id of originalAcceptingSet) {
|
|
109
|
+
expect(complementedAcceptingSet.has(id)).toBe(false);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
//# sourceMappingURL=complement.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"complement.test.js","sourceRoot":"","sources":["../../src/automaton/complement.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NFA to DFA conversion using subset construction.
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
import type { SegmentAutomaton } from '../types';
|
|
6
|
+
/**
|
|
7
|
+
* Default maximum number of DFA states before throwing an error.
|
|
8
|
+
* This prevents exponential blowup from patterns with many alternations.
|
|
9
|
+
*
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
export declare const DEFAULT_MAX_DFA_STATES = 10000;
|
|
13
|
+
/**
|
|
14
|
+
* Options for DFA construction.
|
|
15
|
+
*
|
|
16
|
+
* @public
|
|
17
|
+
*/
|
|
18
|
+
export interface DeterminizeOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Maximum number of DFA states to create before throwing an error.
|
|
21
|
+
* Set to `Infinity` to disable the limit (not recommended).
|
|
22
|
+
* @defaultValue 10000
|
|
23
|
+
*/
|
|
24
|
+
maxStates?: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Convert an NFA to a DFA using subset construction.
|
|
28
|
+
*
|
|
29
|
+
* The resulting DFA has states that correspond to sets of NFA states.
|
|
30
|
+
* Globstar transitions are handled by treating them as transitions
|
|
31
|
+
* that can match any segment.
|
|
32
|
+
*
|
|
33
|
+
* @param nfa - The NFA to determinize
|
|
34
|
+
* @param options - Optional configuration for the conversion
|
|
35
|
+
* @returns An equivalent DFA
|
|
36
|
+
* @throws AutomatonLimitError if DFA state count exceeds the configured limit
|
|
37
|
+
*
|
|
38
|
+
* @public
|
|
39
|
+
*/
|
|
40
|
+
export declare function determinize(nfa: SegmentAutomaton, options?: DeterminizeOptions): SegmentAutomaton;
|
|
41
|
+
//# sourceMappingURL=determinize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"determinize.d.ts","sourceRoot":"","sources":["../../src/automaton/determinize.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAuD,MAAM,UAAU,CAAA;AAGrG;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,QAAS,CAAA;AAE5C;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAUD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,gBAAgB,EAAE,OAAO,GAAE,kBAAuB,GAAG,gBAAgB,CAoIrG"}
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NFA to DFA conversion using subset construction.
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
import { AutomatonLimitError } from '../types';
|
|
6
|
+
/**
|
|
7
|
+
* Default maximum number of DFA states before throwing an error.
|
|
8
|
+
* This prevents exponential blowup from patterns with many alternations.
|
|
9
|
+
*
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
export const DEFAULT_MAX_DFA_STATES = 10_000;
|
|
13
|
+
/**
|
|
14
|
+
* Convert an NFA to a DFA using subset construction.
|
|
15
|
+
*
|
|
16
|
+
* The resulting DFA has states that correspond to sets of NFA states.
|
|
17
|
+
* Globstar transitions are handled by treating them as transitions
|
|
18
|
+
* that can match any segment.
|
|
19
|
+
*
|
|
20
|
+
* @param nfa - The NFA to determinize
|
|
21
|
+
* @param options - Optional configuration for the conversion
|
|
22
|
+
* @returns An equivalent DFA
|
|
23
|
+
* @throws AutomatonLimitError if DFA state count exceeds the configured limit
|
|
24
|
+
*
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
export function determinize(nfa, options = {}) {
|
|
28
|
+
const maxStates = options.maxStates ?? DEFAULT_MAX_DFA_STATES;
|
|
29
|
+
// Already deterministic? Just ensure it's complete.
|
|
30
|
+
if (nfa.isDeterministic) {
|
|
31
|
+
return makeComplete(nfa);
|
|
32
|
+
}
|
|
33
|
+
// Map from state set (as string key) to DFA state ID
|
|
34
|
+
const stateSetMap = new Map();
|
|
35
|
+
const dfaStates = [];
|
|
36
|
+
// Helper to get or create a DFA state for an NFA state set
|
|
37
|
+
const getOrCreateState = (nfaStateSet) => {
|
|
38
|
+
const key = serializeStateSet(nfaStateSet);
|
|
39
|
+
let dfaStateId = stateSetMap.get(key);
|
|
40
|
+
if (dfaStateId === undefined) {
|
|
41
|
+
// Check state limit before creating new state
|
|
42
|
+
if (dfaStates.length >= maxStates) {
|
|
43
|
+
throw new AutomatonLimitError('DFA_STATE_LIMIT', `DFA construction exceeded limit of ${maxStates} states. ` +
|
|
44
|
+
`The pattern may be too complex (e.g., many alternations or wildcards). ` +
|
|
45
|
+
`Consider simplifying the pattern or increasing the maxStates limit.`, maxStates, dfaStates.length + 1);
|
|
46
|
+
}
|
|
47
|
+
dfaStateId = dfaStates.length;
|
|
48
|
+
stateSetMap.set(key, dfaStateId);
|
|
49
|
+
// Check if any NFA state in the set is accepting
|
|
50
|
+
const accepting = [...nfaStateSet].some((s) => nfa.states[s].accepting);
|
|
51
|
+
dfaStates.push({
|
|
52
|
+
id: dfaStateId,
|
|
53
|
+
transitions: [], // Will be filled later
|
|
54
|
+
accepting,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return dfaStateId;
|
|
58
|
+
};
|
|
59
|
+
// Start with epsilon closure of initial state
|
|
60
|
+
const initialClosure = epsilonClosure(nfa, new Set([nfa.initialState]));
|
|
61
|
+
const initialDfaState = getOrCreateState(initialClosure);
|
|
62
|
+
// Worklist of DFA states to process
|
|
63
|
+
const worklist = [
|
|
64
|
+
{ dfaStateId: initialDfaState, nfaStateSet: initialClosure },
|
|
65
|
+
];
|
|
66
|
+
const processed = new Set();
|
|
67
|
+
// Collect all alphabet symbols from the NFA
|
|
68
|
+
const alphabet = collectAlphabet(nfa);
|
|
69
|
+
while (worklist.length > 0) {
|
|
70
|
+
const { dfaStateId, nfaStateSet } = worklist.pop();
|
|
71
|
+
if (processed.has(dfaStateId))
|
|
72
|
+
continue;
|
|
73
|
+
processed.add(dfaStateId);
|
|
74
|
+
const transitions = [];
|
|
75
|
+
// For each symbol in the alphabet, compute the target state set
|
|
76
|
+
for (const symbol of alphabet) {
|
|
77
|
+
const targetNfaSet = computeTransition(nfa, nfaStateSet, symbol);
|
|
78
|
+
if (targetNfaSet.size > 0) {
|
|
79
|
+
const targetDfaState = getOrCreateState(targetNfaSet);
|
|
80
|
+
// Add transition
|
|
81
|
+
if (symbol.type === 'literal') {
|
|
82
|
+
transitions.push({
|
|
83
|
+
type: 'literal',
|
|
84
|
+
segment: symbol.value,
|
|
85
|
+
target: targetDfaState,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
else if (symbol.type === 'wildcard') {
|
|
89
|
+
transitions.push({
|
|
90
|
+
type: 'wildcard',
|
|
91
|
+
pattern: symbol.pattern,
|
|
92
|
+
patternSource: symbol.patternSource,
|
|
93
|
+
target: targetDfaState,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
// 'any' symbols are handled specially - they become catch-all wildcard
|
|
97
|
+
// Add to worklist if not processed
|
|
98
|
+
if (!processed.has(targetDfaState)) {
|
|
99
|
+
worklist.push({ dfaStateId: targetDfaState, nfaStateSet: targetNfaSet });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Handle "any segment" transitions (from globstar)
|
|
104
|
+
const anyTarget = computeAnyTransition(nfa, nfaStateSet);
|
|
105
|
+
if (anyTarget.size > 0) {
|
|
106
|
+
const targetDfaState = getOrCreateState(anyTarget);
|
|
107
|
+
transitions.push({
|
|
108
|
+
type: 'wildcard',
|
|
109
|
+
pattern: /^.+$/,
|
|
110
|
+
patternSource: '*',
|
|
111
|
+
target: targetDfaState,
|
|
112
|
+
});
|
|
113
|
+
if (!processed.has(targetDfaState)) {
|
|
114
|
+
worklist.push({ dfaStateId: targetDfaState, nfaStateSet: anyTarget });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Update state with transitions
|
|
118
|
+
dfaStates[dfaStateId] = {
|
|
119
|
+
...dfaStates[dfaStateId],
|
|
120
|
+
transitions,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
const acceptingStates = dfaStates.filter((s) => s.accepting).map((s) => s.id);
|
|
124
|
+
const dfa = {
|
|
125
|
+
states: dfaStates,
|
|
126
|
+
initialState: initialDfaState,
|
|
127
|
+
acceptingStates,
|
|
128
|
+
isDeterministic: true,
|
|
129
|
+
};
|
|
130
|
+
// Make the DFA complete for complement operation
|
|
131
|
+
return makeComplete(dfa);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Serialize a state set to a string key for map lookup.
|
|
135
|
+
*/
|
|
136
|
+
function serializeStateSet(stateSet) {
|
|
137
|
+
return [...stateSet].sort((a, b) => a - b).join(',');
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Compute epsilon closure of a state set.
|
|
141
|
+
*/
|
|
142
|
+
function epsilonClosure(automaton, states) {
|
|
143
|
+
const closure = new Set(states);
|
|
144
|
+
const worklist = [...states];
|
|
145
|
+
while (worklist.length > 0) {
|
|
146
|
+
const stateId = worklist.pop();
|
|
147
|
+
const state = automaton.states[stateId];
|
|
148
|
+
for (const transition of state.transitions) {
|
|
149
|
+
if (transition.type === 'epsilon') {
|
|
150
|
+
if (!closure.has(transition.target)) {
|
|
151
|
+
closure.add(transition.target);
|
|
152
|
+
worklist.push(transition.target);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
else if (transition.type === 'globstar') {
|
|
156
|
+
// Globstar's exit is an epsilon transition (can match zero segments)
|
|
157
|
+
if (!closure.has(transition.exit)) {
|
|
158
|
+
closure.add(transition.exit);
|
|
159
|
+
worklist.push(transition.exit);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return closure;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Collect all symbols from the NFA alphabet.
|
|
168
|
+
*/
|
|
169
|
+
function collectAlphabet(automaton) {
|
|
170
|
+
const symbols = [];
|
|
171
|
+
const literalSet = new Set();
|
|
172
|
+
const wildcardSet = new Map();
|
|
173
|
+
for (const state of automaton.states) {
|
|
174
|
+
for (const transition of state.transitions) {
|
|
175
|
+
if (transition.type === 'literal') {
|
|
176
|
+
if (!literalSet.has(transition.segment)) {
|
|
177
|
+
literalSet.add(transition.segment);
|
|
178
|
+
symbols.push({ type: 'literal', value: transition.segment });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else if (transition.type === 'wildcard') {
|
|
182
|
+
const key = transition.patternSource || transition.pattern.source;
|
|
183
|
+
if (!wildcardSet.has(key)) {
|
|
184
|
+
wildcardSet.set(key, transition.pattern);
|
|
185
|
+
symbols.push({
|
|
186
|
+
type: 'wildcard',
|
|
187
|
+
pattern: transition.pattern,
|
|
188
|
+
patternSource: transition.patternSource,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// Globstar contributes an implicit "any" symbol
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return symbols;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Compute the set of NFA states reachable from a state set on a symbol.
|
|
199
|
+
*/
|
|
200
|
+
function computeTransition(nfa, fromStates, symbol) {
|
|
201
|
+
const reached = new Set();
|
|
202
|
+
for (const stateId of fromStates) {
|
|
203
|
+
const state = nfa.states[stateId];
|
|
204
|
+
for (const transition of state.transitions) {
|
|
205
|
+
if (matchesSymbol(transition, symbol)) {
|
|
206
|
+
reached.add(getTarget(transition));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Return epsilon closure of reached states
|
|
211
|
+
return epsilonClosure(nfa, reached);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Compute transitions on "any segment" (from globstar self-loops).
|
|
215
|
+
*/
|
|
216
|
+
function computeAnyTransition(nfa, fromStates) {
|
|
217
|
+
const reached = new Set();
|
|
218
|
+
for (const stateId of fromStates) {
|
|
219
|
+
const state = nfa.states[stateId];
|
|
220
|
+
for (const transition of state.transitions) {
|
|
221
|
+
if (transition.type === 'globstar') {
|
|
222
|
+
// Self-loop: consuming any segment stays in same state
|
|
223
|
+
reached.add(transition.selfLoop);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return epsilonClosure(nfa, reached);
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Check if a transition matches a symbol.
|
|
231
|
+
*/
|
|
232
|
+
function matchesSymbol(transition, symbol) {
|
|
233
|
+
if (transition.type === 'literal' && symbol.type === 'literal') {
|
|
234
|
+
return transition.segment === symbol.value;
|
|
235
|
+
}
|
|
236
|
+
if (transition.type === 'wildcard' && symbol.type === 'wildcard') {
|
|
237
|
+
// Match if same pattern source
|
|
238
|
+
return transition.patternSource === symbol.patternSource;
|
|
239
|
+
}
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Get target state from a transition.
|
|
244
|
+
*/
|
|
245
|
+
function getTarget(transition) {
|
|
246
|
+
switch (transition.type) {
|
|
247
|
+
case 'literal':
|
|
248
|
+
case 'wildcard':
|
|
249
|
+
return transition.target;
|
|
250
|
+
case 'globstar':
|
|
251
|
+
return transition.selfLoop;
|
|
252
|
+
case 'epsilon':
|
|
253
|
+
return transition.target;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Make a DFA complete by adding a sink state for missing transitions.
|
|
258
|
+
*
|
|
259
|
+
* A complete DFA has exactly one transition for each symbol from each state.
|
|
260
|
+
* This is required for complement operation.
|
|
261
|
+
*
|
|
262
|
+
* For segment automata with an infinite alphabet, we add a "catch-all"
|
|
263
|
+
* wildcard transition to a sink state for any segment not explicitly handled.
|
|
264
|
+
*/
|
|
265
|
+
function makeComplete(dfa) {
|
|
266
|
+
// Create a sink state (non-accepting, transitions to self on any input)
|
|
267
|
+
const sinkStateId = dfa.states.length;
|
|
268
|
+
const sinkState = {
|
|
269
|
+
id: sinkStateId,
|
|
270
|
+
accepting: false,
|
|
271
|
+
transitions: [
|
|
272
|
+
{
|
|
273
|
+
type: 'wildcard',
|
|
274
|
+
pattern: /^.*$/,
|
|
275
|
+
patternSource: '*',
|
|
276
|
+
target: sinkStateId,
|
|
277
|
+
},
|
|
278
|
+
],
|
|
279
|
+
};
|
|
280
|
+
// For each state, add a catch-all transition to sink for unhandled inputs
|
|
281
|
+
const completedStates = dfa.states.map((state) => {
|
|
282
|
+
// Check if state already has a catch-all wildcard (pattern that matches everything)
|
|
283
|
+
const hasCatchAll = state.transitions.some((t) => t.type === 'wildcard' && /^\^?\.\*\$?$/.test(t.pattern.source));
|
|
284
|
+
if (hasCatchAll) {
|
|
285
|
+
return state;
|
|
286
|
+
}
|
|
287
|
+
// Add catch-all transition to sink state
|
|
288
|
+
return {
|
|
289
|
+
...state,
|
|
290
|
+
transitions: [
|
|
291
|
+
...state.transitions,
|
|
292
|
+
{
|
|
293
|
+
type: 'wildcard',
|
|
294
|
+
pattern: /^.*$/,
|
|
295
|
+
patternSource: '*',
|
|
296
|
+
target: sinkStateId,
|
|
297
|
+
},
|
|
298
|
+
],
|
|
299
|
+
};
|
|
300
|
+
});
|
|
301
|
+
// Add sink state
|
|
302
|
+
completedStates.push(sinkState);
|
|
303
|
+
return {
|
|
304
|
+
states: completedStates,
|
|
305
|
+
initialState: dfa.initialState,
|
|
306
|
+
acceptingStates: dfa.acceptingStates,
|
|
307
|
+
isDeterministic: true,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
//# sourceMappingURL=determinize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"determinize.js","sourceRoot":"","sources":["../../src/automaton/determinize.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAE9C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAA;AAwB5C;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,WAAW,CAAC,GAAqB,EAAE,UAA8B,EAAE;IACjF,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,sBAAsB,CAAA;IAE7D,oDAAoD;IACpD,IAAI,GAAG,CAAC,eAAe,EAAE,CAAC;QACxB,OAAO,YAAY,CAAC,GAAG,CAAC,CAAA;IAC1B,CAAC;IAED,qDAAqD;IACrD,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAA;IAC7C,MAAM,SAAS,GAAqB,EAAE,CAAA;IAEtC,2DAA2D;IAC3D,MAAM,gBAAgB,GAAG,CAAC,WAAwB,EAAU,EAAE;QAC5D,MAAM,GAAG,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAA;QAC1C,IAAI,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAErC,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,8CAA8C;YAC9C,IAAI,SAAS,CAAC,MAAM,IAAI,SAAS,EAAE,CAAC;gBAClC,MAAM,IAAI,mBAAmB,CAC3B,iBAAiB,EACjB,sCAAsC,SAAS,WAAW;oBACxD,yEAAyE;oBACzE,qEAAqE,EACvE,SAAS,EACT,SAAS,CAAC,MAAM,GAAG,CAAC,CACrB,CAAA;YACH,CAAC;YAED,UAAU,GAAG,SAAS,CAAC,MAAM,CAAA;YAC7B,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,CAAA;YAEhC,iDAAiD;YACjD,MAAM,SAAS,GAAG,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;YAEvE,SAAS,CAAC,IAAI,CAAC;gBACb,EAAE,EAAE,UAAU;gBACd,WAAW,EAAE,EAAE,EAAE,uBAAuB;gBACxC,SAAS;aACV,CAAC,CAAA;QACJ,CAAC;QAED,OAAO,UAAU,CAAA;IACnB,CAAC,CAAA;IAED,8CAA8C;IAC9C,MAAM,cAAc,GAAG,cAAc,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;IACvE,MAAM,eAAe,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAAA;IAExD,oCAAoC;IACpC,MAAM,QAAQ,GAAuD;QACnE,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,cAAc,EAAE;KAC7D,CAAA;IACD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAA;IAEnC,4CAA4C;IAC5C,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,CAAA;IAErC,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,QAAQ,CAAC,GAAG,EAAG,CAAA;QAEnD,IAAI,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC;YAAE,SAAQ;QACvC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;QAEzB,MAAM,WAAW,GAA0B,EAAE,CAAA;QAE7C,gEAAgE;QAChE,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC9B,MAAM,YAAY,GAAG,iBAAiB,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,CAAC,CAAA;YAEhE,IAAI,YAAY,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBAC1B,MAAM,cAAc,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAA;gBAErD,iBAAiB;gBACjB,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;oBAC9B,WAAW,CAAC,IAAI,CAAC;wBACf,IAAI,EAAE,SAAS;wBACf,OAAO,EAAE,MAAM,CAAC,KAAK;wBACrB,MAAM,EAAE,cAAc;qBACvB,CAAC,CAAA;gBACJ,CAAC;qBAAM,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;oBACtC,WAAW,CAAC,IAAI,CAAC;wBACf,IAAI,EAAE,UAAU;wBAChB,OAAO,EAAE,MAAM,CAAC,OAAO;wBACvB,aAAa,EAAE,MAAM,CAAC,aAAa;wBACnC,MAAM,EAAE,cAAc;qBACvB,CAAC,CAAA;gBACJ,CAAC;gBACD,uEAAuE;gBAEvE,mCAAmC;gBACnC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;oBACnC,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC,CAAA;gBAC1E,CAAC;YACH,CAAC;QACH,CAAC;QAED,mDAAmD;QACnD,MAAM,SAAS,GAAG,oBAAoB,CAAC,GAAG,EAAE,WAAW,CAAC,CAAA;QACxD,IAAI,SAAS,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,cAAc,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAA;YAClD,WAAW,CAAC,IAAI,CAAC;gBACf,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,MAAM;gBACf,aAAa,EAAE,GAAG;gBAClB,MAAM,EAAE,cAAc;aACvB,CAAC,CAAA;YAEF,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;gBACnC,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAA;YACvE,CAAC;QACH,CAAC;QAED,gCAAgC;QAChC,SAAS,CAAC,UAAU,CAAC,GAAG;YACtB,GAAG,SAAS,CAAC,UAAU,CAAC;YACxB,WAAW;SACZ,CAAA;IACH,CAAC;IAED,MAAM,eAAe,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IAE7E,MAAM,GAAG,GAAqB;QAC5B,MAAM,EAAE,SAAS;QACjB,YAAY,EAAE,eAAe;QAC7B,eAAe;QACf,eAAe,EAAE,IAAI;KACtB,CAAA;IAED,iDAAiD;IACjD,OAAO,YAAY,CAAC,GAAG,CAAC,CAAA;AAC1B,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,QAAqB;IAC9C,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACtD,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,SAA2B,EAAE,MAAmB;IACtE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAA;IAC/B,MAAM,QAAQ,GAAG,CAAC,GAAG,MAAM,CAAC,CAAA;IAE5B,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,EAAG,CAAA;QAC/B,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QAEvC,KAAK,MAAM,UAAU,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;YAC3C,IAAI,UAAU,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAClC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;oBACpC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;oBAC9B,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;gBAClC,CAAC;YACH,CAAC;iBAAM,IAAI,UAAU,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC1C,qEAAqE;gBACrE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;oBAClC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;oBAC5B,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;gBAChC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,SAA2B;IAClD,MAAM,OAAO,GAAqB,EAAE,CAAA;IACpC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAA;IACpC,MAAM,WAAW,GAAG,IAAI,GAAG,EAAmC,CAAA;IAE9D,KAAK,MAAM,KAAK,IAAI,SAAS,CAAC,MAAM,EAAE,CAAC;QACrC,KAAK,MAAM,UAAU,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;YAC3C,IAAI,UAAU,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAClC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;oBACxC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;oBAClC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,CAAA;gBAC9D,CAAC;YACH,CAAC;iBAAM,IAAI,UAAU,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC1C,MAAM,GAAG,GAAG,UAAU,CAAC,aAAa,IAAI,UAAU,CAAC,OAAO,CAAC,MAAM,CAAA;gBACjE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC1B,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,OAAO,CAAC,CAAA;oBACxC,OAAO,CAAC,IAAI,CAAC;wBACX,IAAI,EAAE,UAAU;wBAChB,OAAO,EAAE,UAAU,CAAC,OAAO;wBAC3B,aAAa,EAAE,UAAU,CAAC,aAAa;qBACxC,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC;YACD,gDAAgD;QAClD,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,GAAqB,EAAE,UAAuB,EAAE,MAAsB;IAC/F,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAA;IAEjC,KAAK,MAAM,OAAO,IAAI,UAAU,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QAEjC,KAAK,MAAM,UAAU,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;YAC3C,IAAI,aAAa,CAAC,UAAU,EAAE,MAAM,CAAC,EAAE,CAAC;gBACtC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAA;YACpC,CAAC;QACH,CAAC;IACH,CAAC;IAED,2CAA2C;IAC3C,OAAO,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;AACrC,CAAC;AAED;;GAEG;AACH,SAAS,oBAAoB,CAAC,GAAqB,EAAE,UAAuB;IAC1E,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAA;IAEjC,KAAK,MAAM,OAAO,IAAI,UAAU,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QAEjC,KAAK,MAAM,UAAU,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;YAC3C,IAAI,UAAU,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBACnC,uDAAuD;gBACvD,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAA;YAClC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;AACrC,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CAAC,UAA+B,EAAE,MAAsB;IAC5E,IAAI,UAAU,CAAC,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC/D,OAAO,UAAU,CAAC,OAAO,KAAK,MAAM,CAAC,KAAK,CAAA;IAC5C,CAAC;IACD,IAAI,UAAU,CAAC,IAAI,KAAK,UAAU,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QACjE,+BAA+B;QAC/B,OAAO,UAAU,CAAC,aAAa,KAAK,MAAM,CAAC,aAAa,CAAA;IAC1D,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;GAEG;AACH,SAAS,SAAS,CAAC,UAA+B;IAChD,QAAQ,UAAU,CAAC,IAAI,EAAE,CAAC;QACxB,KAAK,SAAS,CAAC;QACf,KAAK,UAAU;YACb,OAAO,UAAU,CAAC,MAAM,CAAA;QAC1B,KAAK,UAAU;YACb,OAAO,UAAU,CAAC,QAAQ,CAAA;QAC5B,KAAK,SAAS;YACZ,OAAO,UAAU,CAAC,MAAM,CAAA;IAC5B,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,YAAY,CAAC,GAAqB;IACzC,wEAAwE;IACxE,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAA;IACrC,MAAM,SAAS,GAAmB;QAChC,EAAE,EAAE,WAAW;QACf,SAAS,EAAE,KAAK;QAChB,WAAW,EAAE;YACX;gBACE,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,MAAM;gBACf,aAAa,EAAE,GAAG;gBAClB,MAAM,EAAE,WAAW;aACpB;SACF;KACF,CAAA;IAED,0EAA0E;IAC1E,MAAM,eAAe,GAAqB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACjE,oFAAoF;QACpF,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAA;QAEjH,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,KAAK,CAAA;QACd,CAAC;QAED,yCAAyC;QACzC,OAAO;YACL,GAAG,KAAK;YACR,WAAW,EAAE;gBACX,GAAG,KAAK,CAAC,WAAW;gBACpB;oBACE,IAAI,EAAE,UAAmB;oBACzB,OAAO,EAAE,MAAM;oBACf,aAAa,EAAE,GAAG;oBAClB,MAAM,EAAE,WAAW;iBACpB;aACF;SACF,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,iBAAiB;IACjB,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IAE/B,OAAO;QACL,MAAM,EAAE,eAAe;QACvB,YAAY,EAAE,GAAG,CAAC,YAAY;QAC9B,eAAe,EAAE,GAAG,CAAC,eAAe;QACpC,eAAe,EAAE,IAAI;KACtB,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"determinize.test.d.ts","sourceRoot":"","sources":["../../src/automaton/determinize.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { determinize, DEFAULT_MAX_DFA_STATES } from './determinize';
|
|
3
|
+
import { buildAutomaton } from '../compile/automaton-builder';
|
|
4
|
+
import { parsePattern } from '../parse';
|
|
5
|
+
import { matchPath } from '../match';
|
|
6
|
+
import { compilePattern } from '../compile';
|
|
7
|
+
import { AutomatonLimitError } from '../types';
|
|
8
|
+
describe('determinize', () => {
|
|
9
|
+
describe('basic conversion', () => {
|
|
10
|
+
it('returns already deterministic automata unchanged (except completion)', () => {
|
|
11
|
+
const pattern = parsePattern('src/index.ts');
|
|
12
|
+
const automaton = buildAutomaton(pattern);
|
|
13
|
+
// Mark as deterministic for testing
|
|
14
|
+
const dfa = { ...automaton, isDeterministic: true };
|
|
15
|
+
const result = determinize(dfa);
|
|
16
|
+
// Should have same accepting behavior
|
|
17
|
+
expect(result.isDeterministic).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
it('converts simple NFA to DFA', () => {
|
|
20
|
+
const pattern = parsePattern('src/*.ts');
|
|
21
|
+
const nfa = buildAutomaton(pattern);
|
|
22
|
+
expect(nfa.isDeterministic).toBe(false);
|
|
23
|
+
const dfa = determinize(nfa);
|
|
24
|
+
expect(dfa.isDeterministic).toBe(true);
|
|
25
|
+
expect(dfa.states.length).toBeGreaterThan(0);
|
|
26
|
+
});
|
|
27
|
+
it('preserves matching semantics for literals', () => {
|
|
28
|
+
const pattern = compilePattern(parsePattern('src/index.ts'));
|
|
29
|
+
const dfa = determinize(pattern.automaton);
|
|
30
|
+
const compiled = { ...pattern, automaton: dfa };
|
|
31
|
+
expect(matchPath('/src/index.ts', compiled)).toBe(true);
|
|
32
|
+
expect(matchPath('/src/other.ts', compiled)).toBe(false);
|
|
33
|
+
expect(matchPath('/lib/index.ts', compiled)).toBe(false);
|
|
34
|
+
});
|
|
35
|
+
it('preserves matching semantics for wildcards', () => {
|
|
36
|
+
const pattern = compilePattern(parsePattern('src/*.ts'));
|
|
37
|
+
const dfa = determinize(pattern.automaton);
|
|
38
|
+
const compiled = { ...pattern, automaton: dfa };
|
|
39
|
+
expect(matchPath('/src/index.ts', compiled)).toBe(true);
|
|
40
|
+
expect(matchPath('/src/utils.ts', compiled)).toBe(true);
|
|
41
|
+
expect(matchPath('/src/index.js', compiled)).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
it('preserves matching semantics for globstar', () => {
|
|
44
|
+
const pattern = compilePattern(parsePattern('src/**/*.ts'));
|
|
45
|
+
const dfa = determinize(pattern.automaton);
|
|
46
|
+
const compiled = { ...pattern, automaton: dfa };
|
|
47
|
+
expect(matchPath('/src/index.ts', compiled)).toBe(true);
|
|
48
|
+
expect(matchPath('/src/utils/helper.ts', compiled)).toBe(true);
|
|
49
|
+
expect(matchPath('/src/a/b/c/d.ts', compiled)).toBe(true);
|
|
50
|
+
expect(matchPath('/lib/index.ts', compiled)).toBe(false);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
describe('epsilon closure', () => {
|
|
54
|
+
it('correctly handles epsilon transitions', () => {
|
|
55
|
+
// Patterns with alternation have epsilon transitions
|
|
56
|
+
const pattern = compilePattern(parsePattern('{src,lib}/*.ts'));
|
|
57
|
+
const dfa = determinize(pattern.automaton);
|
|
58
|
+
const compiled = { ...pattern, automaton: dfa };
|
|
59
|
+
expect(matchPath('/src/index.ts', compiled)).toBe(true);
|
|
60
|
+
expect(matchPath('/lib/index.ts', compiled)).toBe(true);
|
|
61
|
+
expect(matchPath('/test/index.ts', compiled)).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
describe('DFA completeness', () => {
|
|
65
|
+
it('adds sink state for unhandled transitions', () => {
|
|
66
|
+
const pattern = compilePattern(parsePattern('src/index.ts'));
|
|
67
|
+
const dfa = determinize(pattern.automaton);
|
|
68
|
+
// The DFA should have catch-all transitions to a sink state
|
|
69
|
+
const hasCatchAll = dfa.states.some((state) => state.transitions.some((t) => t.type === 'wildcard' && /^\^?\.\*\$?$/.test(t.pattern.source)));
|
|
70
|
+
expect(hasCatchAll).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
it('sink state is non-accepting', () => {
|
|
73
|
+
const pattern = compilePattern(parsePattern('src/index.ts'));
|
|
74
|
+
const dfa = determinize(pattern.automaton);
|
|
75
|
+
// Find the sink state (state with self-loop on catch-all)
|
|
76
|
+
const sinkState = dfa.states.find((state) => !state.accepting &&
|
|
77
|
+
state.transitions.some((t) => t.type === 'wildcard' && /^\^?\.\*\$?$/.test(t.pattern.source) && t.target === state.id));
|
|
78
|
+
expect(sinkState).toBeDefined();
|
|
79
|
+
expect(sinkState.accepting).toBe(false);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
describe('state limit', () => {
|
|
83
|
+
it('exports DEFAULT_MAX_DFA_STATES constant', () => {
|
|
84
|
+
expect(DEFAULT_MAX_DFA_STATES).toBe(10_000);
|
|
85
|
+
});
|
|
86
|
+
it('accepts custom maxStates option', () => {
|
|
87
|
+
const pattern = parsePattern('src/*.ts');
|
|
88
|
+
const nfa = buildAutomaton(pattern);
|
|
89
|
+
// Should work with high limit
|
|
90
|
+
const dfa = determinize(nfa, { maxStates: 100 });
|
|
91
|
+
expect(dfa.isDeterministic).toBe(true);
|
|
92
|
+
});
|
|
93
|
+
it('throws AutomatonLimitError when state limit exceeded', () => {
|
|
94
|
+
const pattern = parsePattern('{a,b,c,d,e}/*.ts');
|
|
95
|
+
const nfa = buildAutomaton(pattern);
|
|
96
|
+
// With a very low limit, should throw
|
|
97
|
+
expect(() => determinize(nfa, { maxStates: 2 })).toThrow(AutomatonLimitError);
|
|
98
|
+
});
|
|
99
|
+
it('AutomatonLimitError contains limit info', () => {
|
|
100
|
+
const pattern = parsePattern('{a,b,c}/*.ts');
|
|
101
|
+
const nfa = buildAutomaton(pattern);
|
|
102
|
+
try {
|
|
103
|
+
determinize(nfa, { maxStates: 2 });
|
|
104
|
+
expect.fail('Should have thrown');
|
|
105
|
+
}
|
|
106
|
+
catch (e) {
|
|
107
|
+
expect(e).toBeInstanceOf(AutomatonLimitError);
|
|
108
|
+
const error = e;
|
|
109
|
+
expect(error.code).toBe('DFA_STATE_LIMIT');
|
|
110
|
+
expect(error.limit).toBe(2);
|
|
111
|
+
expect(error.actual).toBeGreaterThan(2);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
describe('complex patterns', () => {
|
|
116
|
+
it('handles multiple wildcards', () => {
|
|
117
|
+
const pattern = compilePattern(parsePattern('src/**/test-*.spec.ts'));
|
|
118
|
+
const dfa = determinize(pattern.automaton);
|
|
119
|
+
const compiled = { ...pattern, automaton: dfa };
|
|
120
|
+
expect(matchPath('/src/test-unit.spec.ts', compiled)).toBe(true);
|
|
121
|
+
expect(matchPath('/src/utils/test-integration.spec.ts', compiled)).toBe(true);
|
|
122
|
+
expect(matchPath('/src/unit.spec.ts', compiled)).toBe(false);
|
|
123
|
+
});
|
|
124
|
+
it('handles nested alternations', () => {
|
|
125
|
+
const pattern = compilePattern(parsePattern('{src,lib}/{utils,helpers}/*.ts'));
|
|
126
|
+
const dfa = determinize(pattern.automaton);
|
|
127
|
+
const compiled = { ...pattern, automaton: dfa };
|
|
128
|
+
expect(matchPath('/src/utils/foo.ts', compiled)).toBe(true);
|
|
129
|
+
expect(matchPath('/lib/helpers/bar.ts', compiled)).toBe(true);
|
|
130
|
+
expect(matchPath('/src/core/baz.ts', compiled)).toBe(false);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
//# sourceMappingURL=determinize.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"determinize.test.js","sourceRoot":"","sources":["../../src/automaton/determinize.test.ts"],"names":[],"mappings":"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"}
|