clarity-pattern-parser 6.0.2 → 7.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/TODO.md +1 -78
- package/dist/ast/Node.d.ts +1 -0
- package/dist/grammar/Grammar.d.ts +17 -0
- package/dist/grammar/patterns/andLiteral.d.ts +2 -0
- package/dist/grammar/patterns/comment.d.ts +2 -0
- package/dist/grammar/patterns/grammar.d.ts +2 -0
- package/dist/grammar/patterns/literal.d.ts +2 -0
- package/dist/grammar/patterns/name.d.ts +2 -0
- package/dist/grammar/patterns/orLiteral.d.ts +2 -0
- package/dist/grammar/patterns/pattern.d.ts +2 -0
- package/dist/grammar/patterns/regexLiteral.d.ts +2 -0
- package/dist/grammar/patterns/repeatLiteral.d.ts +3 -0
- package/dist/grammar/patterns/spaces.d.ts +2 -0
- package/dist/grammar/patterns/statement.d.ts +2 -0
- package/dist/index.browser.js +1161 -556
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.esm.js +1159 -555
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1159 -554
- package/dist/index.js.map +1 -1
- package/dist/intellisense/AutoComplete.d.ts +2 -6
- package/dist/patterns/And.d.ts +1 -1
- package/dist/patterns/Cursor.d.ts +1 -0
- package/dist/patterns/CursorHistory.d.ts +2 -1
- package/dist/patterns/FiniteRepeat.d.ts +39 -0
- package/dist/patterns/InfiniteRepeat.d.ts +47 -0
- package/dist/patterns/Literal.d.ts +1 -1
- package/dist/patterns/Not.d.ts +1 -1
- package/dist/patterns/Or.d.ts +1 -1
- package/dist/patterns/Pattern.d.ts +1 -1
- package/dist/patterns/Reference.d.ts +1 -1
- package/dist/patterns/Regex.d.ts +1 -1
- package/dist/patterns/Repeat.d.ts +18 -22
- package/jest.config.js +0 -1
- package/jest.coverage.config.js +13 -0
- package/package.json +3 -3
- package/src/ast/Node.test.ts +15 -0
- package/src/ast/Node.ts +12 -6
- package/src/grammar/Grammar.test.ts +306 -0
- package/src/grammar/Grammar.ts +249 -0
- package/src/grammar/patterns/andLiteral.ts +8 -0
- package/src/grammar/patterns/comment.ts +3 -0
- package/src/grammar/patterns/grammar.ts +19 -0
- package/src/grammar/patterns/literal.ts +5 -0
- package/src/grammar/patterns/name.ts +3 -0
- package/src/grammar/patterns/orLiteral.ts +8 -0
- package/src/grammar/patterns/pattern.ts +13 -0
- package/src/grammar/patterns/regexLiteral.ts +4 -0
- package/src/grammar/patterns/repeatLiteral.ts +72 -0
- package/src/grammar/patterns/spaces.ts +4 -0
- package/src/grammar/patterns/statement.ts +36 -0
- package/src/grammar/spec.md +142 -0
- package/src/index.ts +6 -3
- package/src/intellisense/AutoComplete.test.ts +21 -2
- package/src/intellisense/AutoComplete.ts +14 -25
- package/src/intellisense/Suggestion.ts +0 -1
- package/src/intellisense/css/cssValue.ts +1 -1
- package/src/intellisense/css/method.ts +1 -1
- package/src/intellisense/css/values.ts +1 -1
- package/src/intellisense/javascript/Javascript.test.ts +0 -1
- package/src/intellisense/javascript/arrayLiteral.ts +1 -1
- package/src/intellisense/javascript/expression.ts +1 -1
- package/src/intellisense/javascript/invocation.ts +1 -1
- package/src/intellisense/javascript/objectLiteral.ts +1 -1
- package/src/intellisense/javascript/parameters.ts +1 -1
- package/src/intellisense/javascript/stringLiteral.ts +2 -4
- package/src/patterns/And.test.ts +5 -5
- package/src/patterns/And.ts +11 -17
- package/src/patterns/Cursor.ts +4 -0
- package/src/patterns/CursorHistory.ts +34 -5
- package/src/patterns/FiniteRepeat.test.ts +481 -0
- package/src/patterns/FiniteRepeat.ts +231 -0
- package/src/patterns/InfiniteRepeat.test.ts +296 -0
- package/src/patterns/InfiniteRepeat.ts +329 -0
- package/src/patterns/Literal.test.ts +4 -4
- package/src/patterns/Literal.ts +1 -1
- package/src/patterns/Not.test.ts +11 -11
- package/src/patterns/Not.ts +1 -1
- package/src/patterns/Or.test.ts +9 -9
- package/src/patterns/Or.ts +1 -1
- package/src/patterns/Pattern.ts +1 -1
- package/src/patterns/Reference.test.ts +8 -8
- package/src/patterns/Reference.ts +1 -1
- package/src/patterns/Regex.test.ts +4 -4
- package/src/patterns/Regex.ts +1 -1
- package/src/patterns/Repeat.test.ts +160 -165
- package/src/patterns/Repeat.ts +95 -230
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { Node } from "../ast/Node";
|
|
2
|
+
import { Cursor } from "./Cursor";
|
|
3
|
+
import { Pattern } from "./Pattern";
|
|
4
|
+
import { clonePatterns } from "./clonePatterns";
|
|
5
|
+
import { findPattern } from "./findPattern";
|
|
6
|
+
|
|
7
|
+
export interface InfiniteRepeatOptions {
|
|
8
|
+
divider?: Pattern;
|
|
9
|
+
min?: number;
|
|
10
|
+
trimDivider?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class InfiniteRepeat implements Pattern {
|
|
14
|
+
private _type: string;
|
|
15
|
+
private _name: string;
|
|
16
|
+
private _parent: Pattern | null;
|
|
17
|
+
private _children: Pattern[];
|
|
18
|
+
private _pattern: Pattern;
|
|
19
|
+
private _divider: Pattern | null;
|
|
20
|
+
private _nodes: Node[];
|
|
21
|
+
private _firstIndex: number;
|
|
22
|
+
private _min: number;
|
|
23
|
+
private _trimDivider: boolean;
|
|
24
|
+
|
|
25
|
+
get type(): string {
|
|
26
|
+
return this._type;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get name(): string {
|
|
30
|
+
return this._name;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get parent(): Pattern | null {
|
|
34
|
+
return this._parent;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
set parent(pattern: Pattern | null) {
|
|
38
|
+
this._parent = pattern;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get children(): Pattern[] {
|
|
42
|
+
return this._children;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get isOptional(): boolean {
|
|
46
|
+
return this._min === 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get min(): number {
|
|
50
|
+
return this._min;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
constructor(name: string, pattern: Pattern, options: InfiniteRepeatOptions = {}) {
|
|
54
|
+
const min = options.min != null ? options.min : 1;
|
|
55
|
+
const divider = options.divider;
|
|
56
|
+
let children: Pattern[];
|
|
57
|
+
|
|
58
|
+
if (divider != null) {
|
|
59
|
+
children = [pattern.clone(), divider.clone(divider.name, false)]
|
|
60
|
+
} else {
|
|
61
|
+
children = [pattern.clone()]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
this._assignChildrenToParent(children);
|
|
65
|
+
|
|
66
|
+
this._type = "infinite-repeat";
|
|
67
|
+
this._name = name;
|
|
68
|
+
this._min = min;
|
|
69
|
+
this._parent = null;
|
|
70
|
+
this._children = children;
|
|
71
|
+
this._pattern = children[0];
|
|
72
|
+
this._divider = children[1];
|
|
73
|
+
this._firstIndex = -1
|
|
74
|
+
this._nodes = [];
|
|
75
|
+
this._trimDivider = options.trimDivider == null ? false : options.trimDivider;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private _assignChildrenToParent(children: Pattern[]): void {
|
|
79
|
+
for (const child of children) {
|
|
80
|
+
child.parent = this;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
test(text: string) {
|
|
85
|
+
const cursor = new Cursor(text);
|
|
86
|
+
const ast = this.parse(cursor);
|
|
87
|
+
|
|
88
|
+
return ast?.value === text;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
exec(text: string) {
|
|
92
|
+
const cursor = new Cursor(text);
|
|
93
|
+
const ast = this.parse(cursor);
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
ast: ast?.value === text ? ast : null,
|
|
97
|
+
cursor
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
parse(cursor: Cursor): Node | null {
|
|
102
|
+
this._firstIndex = cursor.index;
|
|
103
|
+
this._nodes = [];
|
|
104
|
+
|
|
105
|
+
const passed = this._tryToParse(cursor);
|
|
106
|
+
|
|
107
|
+
if (passed) {
|
|
108
|
+
cursor.resolveError();
|
|
109
|
+
const node = this._createNode(cursor);
|
|
110
|
+
|
|
111
|
+
if (node != null) {
|
|
112
|
+
cursor.moveTo(node.lastIndex);
|
|
113
|
+
cursor.recordMatch(this, node);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return node;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (this._min > 0) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
cursor.resolveError();
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private _meetsMin() {
|
|
128
|
+
if (this._divider != null) {
|
|
129
|
+
return Math.ceil(this._nodes.length / 2) >= this._min;
|
|
130
|
+
}
|
|
131
|
+
return this._nodes.length >= this._min;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private _tryToParse(cursor: Cursor): boolean {
|
|
135
|
+
let passed = false;
|
|
136
|
+
|
|
137
|
+
while (true) {
|
|
138
|
+
const runningCursorIndex = cursor.index;
|
|
139
|
+
const repeatedNode = this._pattern.parse(cursor);
|
|
140
|
+
|
|
141
|
+
if (cursor.hasError) {
|
|
142
|
+
const lastValidNode = this._getLastValidNode();
|
|
143
|
+
|
|
144
|
+
if (lastValidNode != null) {
|
|
145
|
+
passed = true;
|
|
146
|
+
} else {
|
|
147
|
+
cursor.moveTo(runningCursorIndex);
|
|
148
|
+
cursor.recordErrorAt(runningCursorIndex, this._pattern);
|
|
149
|
+
passed = false;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
break;
|
|
153
|
+
} else {
|
|
154
|
+
if (repeatedNode != null) {
|
|
155
|
+
this._nodes.push(repeatedNode);
|
|
156
|
+
|
|
157
|
+
if (!cursor.hasNext()) {
|
|
158
|
+
passed = true;
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
cursor.next();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (this._divider != null) {
|
|
166
|
+
const dividerNode = this._divider.parse(cursor);
|
|
167
|
+
|
|
168
|
+
if (cursor.hasError) {
|
|
169
|
+
passed = true;
|
|
170
|
+
break;
|
|
171
|
+
} else if (dividerNode != null) {
|
|
172
|
+
this._nodes.push(dividerNode);
|
|
173
|
+
|
|
174
|
+
if (!cursor.hasNext()) {
|
|
175
|
+
passed = true;
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
cursor.next();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const hasMinimum = this._meetsMin();
|
|
186
|
+
|
|
187
|
+
if (hasMinimum) {
|
|
188
|
+
return passed;
|
|
189
|
+
} else if (!hasMinimum && passed) {
|
|
190
|
+
cursor.recordErrorAt(cursor.index, this);
|
|
191
|
+
cursor.moveTo(this._firstIndex);
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return passed;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private _createNode(cursor: Cursor): Node | null {
|
|
199
|
+
const hasDivider = this._divider != null;
|
|
200
|
+
|
|
201
|
+
if (
|
|
202
|
+
hasDivider &&
|
|
203
|
+
this._trimDivider &&
|
|
204
|
+
cursor.leafMatch.pattern === this._divider
|
|
205
|
+
) {
|
|
206
|
+
const dividerNode = this._nodes.pop() as Node;
|
|
207
|
+
cursor.moveTo(dividerNode.firstIndex);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const lastIndex = this._nodes[this._nodes.length - 1].lastIndex;
|
|
211
|
+
cursor.moveTo(lastIndex);
|
|
212
|
+
|
|
213
|
+
return new Node(
|
|
214
|
+
this._type,
|
|
215
|
+
this._name,
|
|
216
|
+
this._firstIndex,
|
|
217
|
+
lastIndex,
|
|
218
|
+
this._nodes
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
private _getLastValidNode(): Node | null {
|
|
223
|
+
const nodes = this._nodes.filter((node) => node !== null);
|
|
224
|
+
|
|
225
|
+
if (nodes.length === 0) {
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return nodes[nodes.length - 1];
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
getTokens(): string[] {
|
|
233
|
+
return this._pattern.getTokens();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
getTokensAfter(childReference: Pattern): string[] {
|
|
237
|
+
const patterns = this.getPatternsAfter(childReference);
|
|
238
|
+
const tokens: string[] = [];
|
|
239
|
+
|
|
240
|
+
patterns.forEach(p => tokens.push(...p.getTokens()));
|
|
241
|
+
|
|
242
|
+
return tokens;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
getNextTokens(): string[] {
|
|
246
|
+
if (this._parent == null) {
|
|
247
|
+
return []
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return this._parent.getTokensAfter(this);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
getPatterns(): Pattern[] {
|
|
254
|
+
return this._pattern.getPatterns();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
getPatternsAfter(childReference: Pattern): Pattern[] {
|
|
258
|
+
let index = -1;
|
|
259
|
+
const patterns: Pattern[] = [];
|
|
260
|
+
|
|
261
|
+
for (let i = 0; i < this._children.length; i++) {
|
|
262
|
+
if (this._children[i] === childReference) {
|
|
263
|
+
index = i;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// If the last match isn't a child of this pattern.
|
|
268
|
+
if (index === -1) {
|
|
269
|
+
return [];
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// If the last match was the repeated patterns, then suggest the divider.
|
|
273
|
+
if (index === 0 && this._divider) {
|
|
274
|
+
patterns.push(this._children[1]);
|
|
275
|
+
|
|
276
|
+
if (this._parent) {
|
|
277
|
+
patterns.push(...this._parent.getPatternsAfter(this));
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Suggest the pattern because the divider was the last match.
|
|
282
|
+
if (index === 1) {
|
|
283
|
+
patterns.push(this._children[0]);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// If there is no divider then suggest the repeating pattern and the next pattern after.
|
|
287
|
+
if (index === 0 && !this._divider && this._parent) {
|
|
288
|
+
patterns.push(this._children[0]);
|
|
289
|
+
patterns.push(...this._parent.getPatternsAfter(this));
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return patterns;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
getNextPatterns(): Pattern[] {
|
|
296
|
+
if (this._parent == null) {
|
|
297
|
+
return [];
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return this._parent.getPatternsAfter(this)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
find(predicate: (p: Pattern) => boolean): Pattern | null {
|
|
304
|
+
return findPattern(this, predicate);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
clone(name = this._name, isOptional?: boolean): Pattern {
|
|
308
|
+
let min = this._min;
|
|
309
|
+
|
|
310
|
+
if (isOptional != null) {
|
|
311
|
+
if (isOptional) {
|
|
312
|
+
min = 0
|
|
313
|
+
} else {
|
|
314
|
+
min = Math.max(this._min, 1);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return new InfiniteRepeat(
|
|
319
|
+
name,
|
|
320
|
+
this._pattern,
|
|
321
|
+
{
|
|
322
|
+
divider: this._divider == null ? undefined : this._divider,
|
|
323
|
+
min: min,
|
|
324
|
+
trimDivider: this._trimDivider
|
|
325
|
+
}
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
@@ -119,7 +119,7 @@ describe("Literal", () => {
|
|
|
119
119
|
const sequence = new And("sequence", [new Literal("a", "A")]);
|
|
120
120
|
const parent = new And("parent", [sequence, new Literal("b", "B")]);
|
|
121
121
|
|
|
122
|
-
const a = parent.
|
|
122
|
+
const a = parent.find(p => p.name === "a");
|
|
123
123
|
const tokens = a?.getNextTokens() || [];
|
|
124
124
|
|
|
125
125
|
expect(tokens[0]).toBe("B");
|
|
@@ -145,9 +145,9 @@ describe("Literal", () => {
|
|
|
145
145
|
const sequence = new And("sequence", [new Literal("a", "A")]);
|
|
146
146
|
const parent = new And("parent", [sequence, new Literal("b", "B")]);
|
|
147
147
|
|
|
148
|
-
const a = parent.
|
|
148
|
+
const a = parent.find(p => p.name === "a");
|
|
149
149
|
const nextPatterns = a?.getNextPatterns() || [];
|
|
150
|
-
const b = parent.
|
|
150
|
+
const b = parent.find(p => p.name === "b")
|
|
151
151
|
|
|
152
152
|
expect(nextPatterns[0]).toBe(b);
|
|
153
153
|
});
|
|
@@ -168,7 +168,7 @@ describe("Literal", () => {
|
|
|
168
168
|
|
|
169
169
|
test("Find Pattern", () => {
|
|
170
170
|
const a = new Literal("a", "A");
|
|
171
|
-
const pattern = a.
|
|
171
|
+
const pattern = a.find(p => p.name === "nada");
|
|
172
172
|
|
|
173
173
|
expect(pattern).toBeNull();
|
|
174
174
|
});
|
package/src/patterns/Literal.ts
CHANGED
|
@@ -167,7 +167,7 @@ export class Literal implements Pattern {
|
|
|
167
167
|
return this.parent.getPatternsAfter(this)
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
-
|
|
170
|
+
find(_predicate: (p: Pattern) => boolean): Pattern | null {
|
|
171
171
|
return null;
|
|
172
172
|
}
|
|
173
173
|
|
package/src/patterns/Not.test.ts
CHANGED
|
@@ -88,7 +88,7 @@ describe("Not", () => {
|
|
|
88
88
|
const notAboutUs = new Not("not-about-us", new Literal("about-us", "About Us"));
|
|
89
89
|
const sequence = new And("sequence", [notAboutUs, new Literal("about-them", "About Them")]);
|
|
90
90
|
|
|
91
|
-
const cloneNotAboutUs = sequence.
|
|
91
|
+
const cloneNotAboutUs = sequence.find(p => p.name === "not-about-us") as Pattern;
|
|
92
92
|
const nextTokens = cloneNotAboutUs.getNextTokens() || [];
|
|
93
93
|
|
|
94
94
|
expect(nextTokens[0]).toBe("About Them");
|
|
@@ -105,7 +105,7 @@ describe("Not", () => {
|
|
|
105
105
|
const notAboutUs = new Not("not-about-us", new Literal("about-us", "About Us"));
|
|
106
106
|
const sequence = new And("sequence", [notAboutUs, new Literal("about-them", "About Them")]);
|
|
107
107
|
|
|
108
|
-
const cloneNotAboutUs = sequence.
|
|
108
|
+
const cloneNotAboutUs = sequence.find(p => p.name === "not-about-us") as Pattern;
|
|
109
109
|
const nextTokens = cloneNotAboutUs.getTokens() || [];
|
|
110
110
|
|
|
111
111
|
expect(nextTokens[0]).toBe("About Them");
|
|
@@ -114,8 +114,8 @@ describe("Not", () => {
|
|
|
114
114
|
test("Get Tokens After", () => {
|
|
115
115
|
const notAboutUs = new Not("not-about-us", new Literal("about-us", "About Us"));
|
|
116
116
|
const sequence = new And("sequence", [notAboutUs, new Literal("about-them", "About Them")]);
|
|
117
|
-
const notAboutUsClone = sequence.
|
|
118
|
-
const aboutUsClone = sequence.
|
|
117
|
+
const notAboutUsClone = sequence.find(p => p.name === "not-about-us") as Pattern;
|
|
118
|
+
const aboutUsClone = sequence.find(p => p.name === "about-us") as Pattern;
|
|
119
119
|
const nextTokens = notAboutUsClone.getTokensAfter(aboutUsClone) || [];
|
|
120
120
|
|
|
121
121
|
expect(nextTokens[0]).toBe("About Them");
|
|
@@ -123,7 +123,7 @@ describe("Not", () => {
|
|
|
123
123
|
|
|
124
124
|
test("Find Pattern", () => {
|
|
125
125
|
const notAboutUs = new Not("not-about-us", new Literal("about-us", "About Us"));
|
|
126
|
-
const child = notAboutUs.
|
|
126
|
+
const child = notAboutUs.find(p => p.name === "about-us")
|
|
127
127
|
|
|
128
128
|
expect(child).not.toBeNull();
|
|
129
129
|
});
|
|
@@ -132,9 +132,9 @@ describe("Not", () => {
|
|
|
132
132
|
const notAboutUs = new Not("not-about-us", new Literal("about-us", "About Us"));
|
|
133
133
|
const sequence = new And("sequence", [notAboutUs, new Literal("about-them", "About Them")]);
|
|
134
134
|
|
|
135
|
-
const cloneNotAboutUs = sequence.
|
|
135
|
+
const cloneNotAboutUs = sequence.find(p => p.name === "not-about-us") as Pattern;
|
|
136
136
|
const nextPatterns = cloneNotAboutUs.getPatterns();
|
|
137
|
-
const expected = [sequence.
|
|
137
|
+
const expected = [sequence.find(p=>p.name === "about-them")];
|
|
138
138
|
|
|
139
139
|
expect(nextPatterns).toEqual(expected);
|
|
140
140
|
});
|
|
@@ -143,7 +143,7 @@ describe("Not", () => {
|
|
|
143
143
|
const notAboutUs = new Not("not-about-us", new Literal("about-us", "About Us"));
|
|
144
144
|
const sequence = new And("sequence", [notAboutUs, new Literal("about-them", "About Them")]);
|
|
145
145
|
|
|
146
|
-
const cloneNotAboutUs = sequence.
|
|
146
|
+
const cloneNotAboutUs = sequence.find(p => p.name === "not-about-us") as Pattern;
|
|
147
147
|
const patterns = cloneNotAboutUs.getNextPatterns() || [];
|
|
148
148
|
|
|
149
149
|
expect(patterns.length).toBe(1);
|
|
@@ -160,8 +160,8 @@ describe("Not", () => {
|
|
|
160
160
|
test("Get Patterns After", () => {
|
|
161
161
|
const notAboutUs = new Not("not-about-us", new Literal("about-us", "About Us"));
|
|
162
162
|
const sequence = new And("sequence", [notAboutUs, new Literal("about-them", "About Them")]);
|
|
163
|
-
const notAboutUsClone = sequence.
|
|
164
|
-
const aboutUsClone = sequence.
|
|
163
|
+
const notAboutUsClone = sequence.find(p => p.name === "not-about-us") as Pattern;
|
|
164
|
+
const aboutUsClone = sequence.find(p => p.name === "about-us") as Pattern;
|
|
165
165
|
const patterns = notAboutUsClone.getPatternsAfter(aboutUsClone) || [];
|
|
166
166
|
|
|
167
167
|
expect(patterns.length).toBe(1);
|
|
@@ -170,7 +170,7 @@ describe("Not", () => {
|
|
|
170
170
|
|
|
171
171
|
test("Get Patterns After With Null Parent", () => {
|
|
172
172
|
const notAboutUs = new Not("not-about-us", new Literal("about-us", "About Us"));
|
|
173
|
-
const aboutUsClone = notAboutUs.
|
|
173
|
+
const aboutUsClone = notAboutUs.find(p => p.name === "about-us") as Pattern;
|
|
174
174
|
const patterns = notAboutUs.getPatternsAfter(aboutUsClone) || [];
|
|
175
175
|
|
|
176
176
|
expect(patterns.length).toBe(0);
|
package/src/patterns/Not.ts
CHANGED
|
@@ -128,7 +128,7 @@ export class Not implements Pattern {
|
|
|
128
128
|
return this.parent.getPatternsAfter(this)
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
|
|
131
|
+
find(predicate: (p: Pattern) => boolean): Pattern | null {
|
|
132
132
|
return predicate(this._children[0]) ? this._children[0] : null;
|
|
133
133
|
}
|
|
134
134
|
|
package/src/patterns/Or.test.ts
CHANGED
|
@@ -118,7 +118,7 @@ describe("Or", () => {
|
|
|
118
118
|
new Literal("c", "C")
|
|
119
119
|
]);
|
|
120
120
|
|
|
121
|
-
const orClone = sequence.
|
|
121
|
+
const orClone = sequence.find(p => p.name === "a-or-b") as Pattern;
|
|
122
122
|
const tokens = orClone.getNextTokens();
|
|
123
123
|
|
|
124
124
|
expect(tokens.length).toBe(1);
|
|
@@ -145,8 +145,8 @@ describe("Or", () => {
|
|
|
145
145
|
new Literal("c", "C")
|
|
146
146
|
]);
|
|
147
147
|
|
|
148
|
-
const aClone = sequence.
|
|
149
|
-
const orClone = sequence.
|
|
148
|
+
const aClone = sequence.find(p => p.name === "a") as Pattern;
|
|
149
|
+
const orClone = sequence.find(p => p.name === "a-or-b") as Pattern;
|
|
150
150
|
const tokens = orClone.getTokensAfter(aClone);
|
|
151
151
|
|
|
152
152
|
expect(tokens.length).toBe(1);
|
|
@@ -157,8 +157,8 @@ describe("Or", () => {
|
|
|
157
157
|
const aOrB = new Or("a-b", [new Literal("a", "A"), new Literal("b", "B")]);
|
|
158
158
|
const patterns = aOrB.getPatterns();
|
|
159
159
|
const expected = [
|
|
160
|
-
aOrB.
|
|
161
|
-
aOrB.
|
|
160
|
+
aOrB.find(p => p.name === "a"),
|
|
161
|
+
aOrB.find(p => p.name === "b")
|
|
162
162
|
];
|
|
163
163
|
|
|
164
164
|
expect(patterns).toEqual(expected);
|
|
@@ -173,8 +173,8 @@ describe("Or", () => {
|
|
|
173
173
|
new Literal("c", "C")
|
|
174
174
|
]);
|
|
175
175
|
|
|
176
|
-
const aClone = sequence.
|
|
177
|
-
const orClone = sequence.
|
|
176
|
+
const aClone = sequence.find(p => p.name === "a") as Pattern;
|
|
177
|
+
const orClone = sequence.find(p => p.name === "a-or-b") as Pattern;
|
|
178
178
|
const patterns = orClone.getPatternsAfter(aClone);
|
|
179
179
|
|
|
180
180
|
expect(patterns.length).toBe(1);
|
|
@@ -186,7 +186,7 @@ describe("Or", () => {
|
|
|
186
186
|
new Literal("a", "A"),
|
|
187
187
|
new Literal("b", "B")
|
|
188
188
|
])
|
|
189
|
-
const aClone = or.
|
|
189
|
+
const aClone = or.find(p => p.name === "a") as Pattern;
|
|
190
190
|
const patterns = or.getPatternsAfter(aClone);
|
|
191
191
|
|
|
192
192
|
expect(patterns.length).toBe(0);
|
|
@@ -201,7 +201,7 @@ describe("Or", () => {
|
|
|
201
201
|
new Literal("c", "C")
|
|
202
202
|
]);
|
|
203
203
|
|
|
204
|
-
const orClone = sequence.
|
|
204
|
+
const orClone = sequence.find(p => p.name === "a-or-b") as Pattern;
|
|
205
205
|
const patterns = orClone.getNextPatterns();
|
|
206
206
|
|
|
207
207
|
expect(patterns.length).toBe(1);
|
package/src/patterns/Or.ts
CHANGED
|
@@ -162,7 +162,7 @@ export class Or implements Pattern {
|
|
|
162
162
|
return this.parent.getPatternsAfter(this)
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
|
|
165
|
+
find(predicate: (p: Pattern) => boolean): Pattern | null {
|
|
166
166
|
return findPattern(this, predicate);
|
|
167
167
|
}
|
|
168
168
|
|
package/src/patterns/Pattern.ts
CHANGED
|
@@ -19,5 +19,5 @@ export interface Pattern {
|
|
|
19
19
|
getPatterns(): Pattern[];
|
|
20
20
|
getPatternsAfter(childReference: Pattern): Pattern[];
|
|
21
21
|
getNextPatterns(): Pattern[];
|
|
22
|
-
|
|
22
|
+
find(predicate: (p: Pattern) => boolean): Pattern | null;
|
|
23
23
|
}
|
|
@@ -19,7 +19,7 @@ function createValuePattern() {
|
|
|
19
19
|
divider.setTokens([", "]);
|
|
20
20
|
|
|
21
21
|
const valueRef = new Reference("value");
|
|
22
|
-
const values = new Repeat("values", valueRef, divider);
|
|
22
|
+
const values = new Repeat("values", valueRef, { divider });
|
|
23
23
|
const array = new And("array", [openBracket, values, closeBracket]);
|
|
24
24
|
const value = new Or("value", [number, array]);
|
|
25
25
|
|
|
@@ -34,7 +34,7 @@ describe("Reference", () => {
|
|
|
34
34
|
|
|
35
35
|
const expected = new Node("and", "array", 0, 5, [
|
|
36
36
|
new Node("literal", "open-bracket", 0, 0, [], "["),
|
|
37
|
-
new Node("repeat", "values", 1, 4, [
|
|
37
|
+
new Node("infinite-repeat", "values", 1, 4, [
|
|
38
38
|
new Node("regex", "number", 1, 1, [], "1"),
|
|
39
39
|
new Node("regex", "divider", 2, 3, [], ", "),
|
|
40
40
|
new Node("regex", "number", 4, 4, [], "2")
|
|
@@ -114,9 +114,9 @@ describe("Reference", () => {
|
|
|
114
114
|
|
|
115
115
|
test("Find Pattern", () => {
|
|
116
116
|
const value = createValuePattern();
|
|
117
|
-
const reference = value.
|
|
117
|
+
const reference = value.find(p => p.type === "reference") as Pattern;
|
|
118
118
|
|
|
119
|
-
const pattern = reference?.
|
|
119
|
+
const pattern = reference?.find(p => p.name === "Nada");
|
|
120
120
|
|
|
121
121
|
expect(pattern).toBe(null);
|
|
122
122
|
});
|
|
@@ -124,7 +124,7 @@ describe("Reference", () => {
|
|
|
124
124
|
|
|
125
125
|
test("Get Next Tokens", () => {
|
|
126
126
|
const value = createValuePattern();
|
|
127
|
-
const reference = value.
|
|
127
|
+
const reference = value.find(p => p.type === "reference") as Pattern;
|
|
128
128
|
const tokens = reference.getNextTokens();
|
|
129
129
|
|
|
130
130
|
expect(tokens).toEqual([", ", "]"]);
|
|
@@ -139,7 +139,7 @@ describe("Reference", () => {
|
|
|
139
139
|
|
|
140
140
|
test("Get Tokens After", () => {
|
|
141
141
|
const value = createValuePattern();
|
|
142
|
-
const reference = value.
|
|
142
|
+
const reference = value.find(p => p.type === "reference") as Pattern;
|
|
143
143
|
const tokens = reference.getTokensAfter(new Literal("bogus", "Bogus"));
|
|
144
144
|
|
|
145
145
|
expect(tokens).toEqual([", ", "]"]);
|
|
@@ -164,7 +164,7 @@ describe("Reference", () => {
|
|
|
164
164
|
|
|
165
165
|
test("Get Patterns After", () => {
|
|
166
166
|
const value = createValuePattern();
|
|
167
|
-
const reference = value.
|
|
167
|
+
const reference = value.find(p => p.type === "reference") as Pattern;
|
|
168
168
|
const patterns = reference.getPatternsAfter(new Literal("bogus", "Bogus"));
|
|
169
169
|
|
|
170
170
|
expect(patterns.length).toEqual(2);
|
|
@@ -183,7 +183,7 @@ describe("Reference", () => {
|
|
|
183
183
|
|
|
184
184
|
test("Get Next Patterns", () => {
|
|
185
185
|
const value = createValuePattern();
|
|
186
|
-
const reference = value.
|
|
186
|
+
const reference = value.find(p => p.type === "reference") as Pattern;
|
|
187
187
|
const patterns = reference.getNextPatterns();
|
|
188
188
|
|
|
189
189
|
expect(patterns.length).toEqual(2);
|
|
@@ -147,7 +147,7 @@ export class Reference implements Pattern {
|
|
|
147
147
|
return this.parent.getPatternsAfter(this)
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
|
|
150
|
+
find(_predicate: (p: Pattern) => boolean): Pattern | null {
|
|
151
151
|
return null;
|
|
152
152
|
}
|
|
153
153
|
|
|
@@ -86,7 +86,7 @@ describe("Regex", () => {
|
|
|
86
86
|
|
|
87
87
|
test("Get Next Tokens", () => {
|
|
88
88
|
const parent = new And("parent", [new Regex("a", "A"), new Literal("b", "B")]);
|
|
89
|
-
const aClone = parent.
|
|
89
|
+
const aClone = parent.find(p => p.name === "a") as Pattern;
|
|
90
90
|
const tokens = aClone.getNextTokens();
|
|
91
91
|
|
|
92
92
|
expect(tokens).toEqual(["B"]);
|
|
@@ -117,15 +117,15 @@ describe("Regex", () => {
|
|
|
117
117
|
|
|
118
118
|
test("Find Pattern", () => {
|
|
119
119
|
const a = new Regex("a", "A")
|
|
120
|
-
const pattern = a.
|
|
120
|
+
const pattern = a.find(p => p.name === "other");
|
|
121
121
|
|
|
122
122
|
expect(pattern).toBeNull();
|
|
123
123
|
});
|
|
124
124
|
|
|
125
125
|
test("Get Next Patterns", () => {
|
|
126
126
|
const parent = new And("parent", [new Regex("a", "A"), new Literal("b", "B")]);
|
|
127
|
-
const aClone = parent.
|
|
128
|
-
const bClone = parent.
|
|
127
|
+
const aClone = parent.find(p => p.name === "a") as Pattern;
|
|
128
|
+
const bClone = parent.find(p => p.name === "b") as Pattern;
|
|
129
129
|
const patterns = aClone.getNextPatterns();
|
|
130
130
|
|
|
131
131
|
expect(patterns.length).toBe(1);
|
package/src/patterns/Regex.ts
CHANGED
|
@@ -173,7 +173,7 @@ export class Regex implements Pattern {
|
|
|
173
173
|
return this.parent.getPatternsAfter(this)
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
|
|
176
|
+
find(_predicate: (p: Pattern) => boolean): Pattern | null {
|
|
177
177
|
return null;
|
|
178
178
|
}
|
|
179
179
|
|