clarity-pattern-parser 5.0.0 → 6.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 +328 -38
- package/TODO.md +55 -1
- package/dist/ast/Node.d.ts +8 -2
- package/dist/index.browser.js +470 -205
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.esm.js +469 -206
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +470 -205
- package/dist/index.js.map +1 -1
- package/dist/intellisense/AutoComplete.d.ts +28 -0
- package/dist/intellisense/Suggestion.d.ts +11 -0
- package/dist/intellisense/SuggestionOption.d.ts +4 -0
- package/dist/patterns/And.d.ts +7 -7
- package/dist/patterns/Cursor.d.ts +6 -4
- package/dist/patterns/CursorHistory.d.ts +2 -2
- package/dist/patterns/Literal.d.ts +7 -8
- package/dist/patterns/Not.d.ts +8 -5
- package/dist/patterns/Or.d.ts +7 -5
- package/dist/patterns/Pattern.d.ts +7 -4
- package/dist/patterns/Reference.d.ts +10 -7
- package/dist/patterns/Regex.d.ts +7 -8
- package/dist/patterns/Repeat.d.ts +7 -7
- package/package.json +1 -1
- package/src/ast/Node.test.ts +110 -0
- package/src/ast/Node.ts +71 -5
- package/src/index.ts +14 -3
- package/src/intellisense/AutoComplete.test.ts +90 -12
- package/src/intellisense/AutoComplete.ts +66 -12
- package/src/intellisense/Suggestion.ts +3 -4
- package/src/intellisense/javascript/Javascript.test.ts +56 -56
- package/src/intellisense/javascript/escapedCharacter.ts +0 -1
- package/src/intellisense/javascript/exponent.ts +0 -2
- package/src/intellisense/javascript/fraction.ts +0 -2
- package/src/patterns/And.test.ts +63 -52
- package/src/patterns/And.ts +58 -36
- package/src/patterns/Cursor.ts +17 -14
- package/src/patterns/CursorHistory.ts +8 -8
- package/src/patterns/Literal.test.ts +70 -38
- package/src/patterns/Literal.ts +31 -42
- package/src/patterns/Not.test.ts +88 -8
- package/src/patterns/Not.ts +54 -14
- package/src/patterns/Or.test.ts +117 -13
- package/src/patterns/Or.ts +36 -13
- package/src/patterns/Pattern.ts +7 -4
- package/src/patterns/Reference.test.ts +117 -28
- package/src/patterns/Reference.ts +58 -32
- package/src/patterns/Regex.test.ts +67 -35
- package/src/patterns/Regex.ts +31 -43
- package/src/patterns/Repeat.test.ts +63 -41
- package/src/patterns/Repeat.ts +51 -38
- package/src/patterns/getNextPattern.test.ts +0 -39
- package/src/patterns/getNextPattern.ts +0 -18
|
@@ -3,6 +3,7 @@ import { And } from "./And";
|
|
|
3
3
|
import { Cursor } from "./Cursor";
|
|
4
4
|
import { findPattern } from "./findPattern";
|
|
5
5
|
import { Literal } from "./Literal";
|
|
6
|
+
import { Pattern } from "./Pattern";
|
|
6
7
|
import { Regex } from "./Regex";
|
|
7
8
|
import { Repeat } from "./Repeat";
|
|
8
9
|
|
|
@@ -96,31 +97,6 @@ describe("Repeat", () => {
|
|
|
96
97
|
expect(cursor.hasError).toBeFalsy()
|
|
97
98
|
});
|
|
98
99
|
|
|
99
|
-
test("Ast Reduction", () => {
|
|
100
|
-
const digit = new Regex("digit", "\\d");
|
|
101
|
-
const integer = new Repeat("number", digit);
|
|
102
|
-
const cursor = new Cursor("337");
|
|
103
|
-
|
|
104
|
-
integer.enableAstReduction();
|
|
105
|
-
|
|
106
|
-
let result = integer.parse(cursor);
|
|
107
|
-
let expected = new Node("repeat", "number", 0, 2, [], "337");
|
|
108
|
-
|
|
109
|
-
expect(result).toEqual(expected)
|
|
110
|
-
|
|
111
|
-
integer.disableAstReduction()
|
|
112
|
-
cursor.moveTo(0)
|
|
113
|
-
|
|
114
|
-
result = integer.parse(cursor);
|
|
115
|
-
expected = new Node("repeat", "number", 0, 2, [
|
|
116
|
-
new Node("regex", "digit", 0, 0, [], "3"),
|
|
117
|
-
new Node("regex", "digit", 1, 1, [], "3"),
|
|
118
|
-
new Node("regex", "digit", 2, 2, [], "7"),
|
|
119
|
-
]);
|
|
120
|
-
|
|
121
|
-
expect(result).toEqual(expected)
|
|
122
|
-
});
|
|
123
|
-
|
|
124
100
|
test("Get Tokens", () => {
|
|
125
101
|
const a = new Literal("a", "A");
|
|
126
102
|
const manyA = new Repeat("number", a);
|
|
@@ -130,16 +106,16 @@ describe("Repeat", () => {
|
|
|
130
106
|
expect(tokens).toEqual(expected)
|
|
131
107
|
});
|
|
132
108
|
|
|
133
|
-
test("Get
|
|
109
|
+
test("Get Tokens After With Bogus Pattern", () => {
|
|
134
110
|
const a = new Literal("a", "A");
|
|
135
111
|
const manyA = new Repeat("many-a", a);
|
|
136
|
-
const tokens = manyA.
|
|
112
|
+
const tokens = manyA.getTokensAfter(new Literal("bogus", "bogus"));
|
|
137
113
|
const expected: string[] = [];
|
|
138
114
|
|
|
139
115
|
expect(tokens).toEqual(expected)
|
|
140
116
|
});
|
|
141
117
|
|
|
142
|
-
test("Get
|
|
118
|
+
test("Get Tokens After With Divider", () => {
|
|
143
119
|
const a = new Literal("a", "A");
|
|
144
120
|
const b = new Literal("b", "B");
|
|
145
121
|
const divider = new Literal("divider", ",");
|
|
@@ -147,37 +123,30 @@ describe("Repeat", () => {
|
|
|
147
123
|
const parent = new And("parent", [manyA, b]);
|
|
148
124
|
|
|
149
125
|
const clonedManyA = findPattern(parent, p => p.name == "many-a");
|
|
150
|
-
let tokens = clonedManyA?.
|
|
126
|
+
let tokens = clonedManyA?.getTokensAfter(clonedManyA.children[0]);
|
|
151
127
|
let expected = [",", "B"];
|
|
152
128
|
|
|
153
129
|
expect(tokens).toEqual(expected)
|
|
154
130
|
|
|
155
|
-
tokens = clonedManyA?.
|
|
131
|
+
tokens = clonedManyA?.getTokensAfter(clonedManyA.children[1]);
|
|
156
132
|
expected = ["A"];
|
|
157
133
|
|
|
158
134
|
expect(tokens).toEqual(expected)
|
|
159
135
|
});
|
|
160
136
|
|
|
161
|
-
test("Get
|
|
137
|
+
test("Get Tokens After Without Divider", () => {
|
|
162
138
|
const a = new Literal("a", "A");
|
|
163
139
|
const b = new Literal("b", "B");
|
|
164
140
|
const manyA = new Repeat("many-a", a);
|
|
165
141
|
const parent = new And("parent", [manyA, b]);
|
|
166
142
|
|
|
167
143
|
const clonedManyA = findPattern(parent, p => p.name == "many-a");
|
|
168
|
-
const tokens = clonedManyA?.
|
|
144
|
+
const tokens = clonedManyA?.getTokensAfter(clonedManyA.children[0]);
|
|
169
145
|
const expected = ["A", "B"];
|
|
170
146
|
|
|
171
147
|
expect(tokens).toEqual(expected)
|
|
172
148
|
});
|
|
173
149
|
|
|
174
|
-
test("Get Next Pattern", () => {
|
|
175
|
-
const repeat = new Repeat("many-a", new Literal("a", "A"));
|
|
176
|
-
const nextPattern = repeat.getNextPattern();
|
|
177
|
-
|
|
178
|
-
expect(nextPattern).toBeNull()
|
|
179
|
-
});
|
|
180
|
-
|
|
181
150
|
test("Properties", () => {
|
|
182
151
|
const integer = new Repeat("integer", new Regex("digit", "\\d"));
|
|
183
152
|
|
|
@@ -188,9 +157,62 @@ describe("Repeat", () => {
|
|
|
188
157
|
expect(integer.children[0].name).toBe("digit");
|
|
189
158
|
});
|
|
190
159
|
|
|
191
|
-
test("
|
|
160
|
+
test("Exec", () => {
|
|
192
161
|
const integer = new Repeat("integer", new Regex("digit", "\\d"));
|
|
193
|
-
const { ast: result } = integer.
|
|
162
|
+
const { ast: result } = integer.exec("B");
|
|
194
163
|
expect(result).toBeNull()
|
|
195
164
|
});
|
|
165
|
+
|
|
166
|
+
test("Test With Match", () => {
|
|
167
|
+
const integer = new Repeat("integer", new Regex("digit", "\\d"));
|
|
168
|
+
const result = integer.test("1");
|
|
169
|
+
expect(result).toBeTruthy()
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test("Test With No Match", () => {
|
|
173
|
+
const integer = new Repeat("integer", new Regex("digit", "\\d"));
|
|
174
|
+
const result = integer.test("b");
|
|
175
|
+
expect(result).toBeFalsy()
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("Get Next Tokens", () => {
|
|
179
|
+
const integer = new Repeat("integer", new Regex("digit", "\\d"));
|
|
180
|
+
const parent = new And("parent", [integer, new Literal("pow", "!")]);
|
|
181
|
+
const integerClone = parent.findPattern(p => p.name === "integer") as Pattern;
|
|
182
|
+
const tokens = integerClone.getNextTokens();
|
|
183
|
+
|
|
184
|
+
expect(tokens).toEqual(["!"])
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test("Get Next Tokens With Null Parents", () => {
|
|
188
|
+
const integer = new Repeat("integer", new Regex("digit", "\\d"));
|
|
189
|
+
const tokens = integer.getNextTokens();
|
|
190
|
+
|
|
191
|
+
expect(tokens.length).toBe(0);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test("Find Pattern", () => {
|
|
195
|
+
const integer = new Repeat("integer", new Regex("digit", "\\d"));
|
|
196
|
+
const digitClone = integer.findPattern(p => p.name === "digit") as Pattern;
|
|
197
|
+
|
|
198
|
+
expect(digitClone).not.toBeNull();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
test("Get Next Patterns", () => {
|
|
202
|
+
const integer = new Repeat("integer", new Regex("digit", "\\d"));
|
|
203
|
+
const parent = new And("parent", [integer, new Literal("pow", "!")]);
|
|
204
|
+
const integerClone = parent.findPattern(p => p.name === "integer") as Pattern;
|
|
205
|
+
const powClone = parent.findPattern(p => p.name === "pow") as Pattern;
|
|
206
|
+
const patterns = integerClone.getNextPatterns();
|
|
207
|
+
|
|
208
|
+
expect(patterns.length).toBe(1);
|
|
209
|
+
expect(patterns[0]).toBe(powClone);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
test("Get Next Patterns With Null Parents", () => {
|
|
213
|
+
const integer = new Repeat("integer", new Regex("digit", "\\d"));
|
|
214
|
+
const patterns = integer.getNextPatterns();
|
|
215
|
+
|
|
216
|
+
expect(patterns.length).toBe(0);
|
|
217
|
+
});
|
|
196
218
|
});
|
package/src/patterns/Repeat.ts
CHANGED
|
@@ -2,7 +2,6 @@ import { Node } from "../ast/Node";
|
|
|
2
2
|
import { Cursor } from "./Cursor";
|
|
3
3
|
import { Pattern } from "./Pattern";
|
|
4
4
|
import { clonePatterns } from "./clonePatterns";
|
|
5
|
-
import { getNextPattern } from "./getNextPattern";
|
|
6
5
|
import { findPattern } from "./findPattern";
|
|
7
6
|
|
|
8
7
|
export class Repeat implements Pattern {
|
|
@@ -15,7 +14,6 @@ export class Repeat implements Pattern {
|
|
|
15
14
|
private _isOptional: boolean;
|
|
16
15
|
private _nodes: Node[];
|
|
17
16
|
private _firstIndex: number;
|
|
18
|
-
private _shouldReduceAst: boolean;
|
|
19
17
|
|
|
20
18
|
get type(): string {
|
|
21
19
|
return this._type;
|
|
@@ -54,7 +52,6 @@ export class Repeat implements Pattern {
|
|
|
54
52
|
this._pattern = children[0];
|
|
55
53
|
this._divider = children[1];
|
|
56
54
|
this._firstIndex = -1
|
|
57
|
-
this._shouldReduceAst = false
|
|
58
55
|
this._nodes = [];
|
|
59
56
|
}
|
|
60
57
|
|
|
@@ -64,12 +61,19 @@ export class Repeat implements Pattern {
|
|
|
64
61
|
}
|
|
65
62
|
}
|
|
66
63
|
|
|
67
|
-
|
|
64
|
+
test(text: string) {
|
|
68
65
|
const cursor = new Cursor(text);
|
|
69
|
-
const ast = this.parse(cursor)
|
|
66
|
+
const ast = this.parse(cursor);
|
|
67
|
+
|
|
68
|
+
return ast?.value === text;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
exec(text: string) {
|
|
72
|
+
const cursor = new Cursor(text);
|
|
73
|
+
const ast = this.parse(cursor);
|
|
70
74
|
|
|
71
75
|
return {
|
|
72
|
-
ast,
|
|
76
|
+
ast: ast?.value === text ? ast : null,
|
|
73
77
|
cursor
|
|
74
78
|
};
|
|
75
79
|
}
|
|
@@ -84,7 +88,7 @@ export class Repeat implements Pattern {
|
|
|
84
88
|
cursor.resolveError();
|
|
85
89
|
const node = this.createNode(cursor);
|
|
86
90
|
|
|
87
|
-
if (node) {
|
|
91
|
+
if (node != null) {
|
|
88
92
|
cursor.recordMatch(this, node);
|
|
89
93
|
}
|
|
90
94
|
|
|
@@ -110,7 +114,7 @@ export class Repeat implements Pattern {
|
|
|
110
114
|
if (cursor.hasError) {
|
|
111
115
|
const lastValidNode = this.getLastValidNode();
|
|
112
116
|
|
|
113
|
-
if (lastValidNode) {
|
|
117
|
+
if (lastValidNode != null) {
|
|
114
118
|
passed = true;
|
|
115
119
|
} else {
|
|
116
120
|
cursor.moveTo(runningCursorIndex);
|
|
@@ -129,13 +133,13 @@ export class Repeat implements Pattern {
|
|
|
129
133
|
|
|
130
134
|
cursor.next();
|
|
131
135
|
|
|
132
|
-
if (this._divider) {
|
|
136
|
+
if (this._divider != null) {
|
|
133
137
|
const dividerNode = this._divider.parse(cursor);
|
|
134
138
|
|
|
135
139
|
if (cursor.hasError) {
|
|
136
140
|
passed = true;
|
|
137
141
|
break;
|
|
138
|
-
} else if (dividerNode) {
|
|
142
|
+
} else if (dividerNode != null) {
|
|
139
143
|
this._nodes.push(dividerNode);
|
|
140
144
|
|
|
141
145
|
if (!cursor.hasNext()) {
|
|
@@ -171,17 +175,13 @@ export class Repeat implements Pattern {
|
|
|
171
175
|
const value = cursor.getChars(this._firstIndex, lastIndex);
|
|
172
176
|
cursor.moveTo(lastIndex);
|
|
173
177
|
|
|
174
|
-
if (this._shouldReduceAst) {
|
|
175
|
-
children = [];
|
|
176
|
-
}
|
|
177
|
-
|
|
178
178
|
return new Node(
|
|
179
179
|
"repeat",
|
|
180
180
|
this._name,
|
|
181
181
|
this._firstIndex,
|
|
182
182
|
lastIndex,
|
|
183
183
|
children,
|
|
184
|
-
|
|
184
|
+
undefined
|
|
185
185
|
);
|
|
186
186
|
}
|
|
187
187
|
|
|
@@ -195,65 +195,78 @@ export class Repeat implements Pattern {
|
|
|
195
195
|
return nodes[nodes.length - 1];
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
|
|
199
|
-
this.
|
|
198
|
+
getTokens(): string[] {
|
|
199
|
+
return this._pattern.getTokens();
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
|
|
203
|
-
|
|
202
|
+
getTokensAfter(childReference: Pattern): string[] {
|
|
203
|
+
const patterns = this.getPatternsAfter(childReference);
|
|
204
|
+
const tokens: string[] = [];
|
|
205
|
+
|
|
206
|
+
patterns.forEach(p => tokens.push(...p.getTokens()));
|
|
207
|
+
|
|
208
|
+
return tokens;
|
|
204
209
|
}
|
|
205
210
|
|
|
206
|
-
|
|
207
|
-
|
|
211
|
+
getNextTokens(): string[] {
|
|
212
|
+
if (this.parent == null) {
|
|
213
|
+
return []
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return this.parent.getTokensAfter(this);
|
|
208
217
|
}
|
|
209
218
|
|
|
210
|
-
|
|
219
|
+
getPatternsAfter(childReference: Pattern): Pattern[] {
|
|
211
220
|
let index = -1;
|
|
212
|
-
const
|
|
221
|
+
const patterns: Pattern[] = [];
|
|
213
222
|
|
|
214
223
|
for (let i = 0; i < this._children.length; i++) {
|
|
215
|
-
if (this._children[i] ===
|
|
224
|
+
if (this._children[i] === childReference) {
|
|
216
225
|
index = i;
|
|
217
226
|
}
|
|
218
227
|
}
|
|
219
228
|
|
|
229
|
+
// If the last match isn't a child of this pattern.
|
|
220
230
|
if (index === -1) {
|
|
221
231
|
return [];
|
|
222
232
|
}
|
|
223
233
|
|
|
234
|
+
// If the last match was the repeated patterns, then suggest the divider.
|
|
224
235
|
if (index === 0 && this._divider) {
|
|
225
|
-
|
|
236
|
+
patterns.push(this._children[1]);
|
|
226
237
|
|
|
227
238
|
if (this._parent) {
|
|
228
|
-
|
|
239
|
+
patterns.push(...this._parent.getPatternsAfter(this));
|
|
229
240
|
}
|
|
230
241
|
}
|
|
231
242
|
|
|
243
|
+
// Suggest the pattern because the divider was the last match.
|
|
232
244
|
if (index === 1) {
|
|
233
|
-
|
|
245
|
+
patterns.push(this._children[0]);
|
|
234
246
|
}
|
|
235
247
|
|
|
236
248
|
if (index === 0 && !this._divider && this._parent) {
|
|
237
|
-
|
|
238
|
-
|
|
249
|
+
patterns.push(this._children[0]);
|
|
250
|
+
patterns.push(...this._parent.getPatternsAfter(this));
|
|
239
251
|
}
|
|
240
252
|
|
|
241
|
-
return
|
|
253
|
+
return patterns;
|
|
242
254
|
}
|
|
243
255
|
|
|
244
|
-
|
|
245
|
-
|
|
256
|
+
getNextPatterns(): Pattern[] {
|
|
257
|
+
if (this.parent == null) {
|
|
258
|
+
return [];
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return this.parent.getPatternsAfter(this)
|
|
246
262
|
}
|
|
247
263
|
|
|
248
|
-
findPattern(
|
|
249
|
-
return findPattern(this,
|
|
264
|
+
findPattern(predicate: (p: Pattern) => boolean): Pattern | null {
|
|
265
|
+
return findPattern(this, predicate);
|
|
250
266
|
}
|
|
251
267
|
|
|
252
268
|
clone(name = this._name, isOptional = this._isOptional): Pattern {
|
|
253
|
-
|
|
254
|
-
repeat._shouldReduceAst = this._shouldReduceAst;
|
|
255
|
-
|
|
256
|
-
return repeat;
|
|
269
|
+
return new Repeat(name, this._pattern, this._divider, isOptional);
|
|
257
270
|
}
|
|
258
271
|
}
|
|
259
272
|
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { And } from "./And";
|
|
2
|
-
import { findPattern } from "./findPattern";
|
|
3
|
-
import { Literal } from "./Literal";
|
|
4
|
-
|
|
5
|
-
describe("getNextPatter", ()=>{
|
|
6
|
-
test("No Parent", ()=>{
|
|
7
|
-
const a = new Literal("a", "A");
|
|
8
|
-
const nextPattern = a.getNextPattern();
|
|
9
|
-
|
|
10
|
-
expect(nextPattern).toBe(null);
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
test("No Next Sibling", ()=>{
|
|
14
|
-
const a = new Literal("a", "A");
|
|
15
|
-
const parent = new And("parent", [a]);
|
|
16
|
-
const nextPattern = parent.children[0].getNextPattern();
|
|
17
|
-
|
|
18
|
-
expect(nextPattern).toBe(null);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
test("Get Parents Sibling", ()=>{
|
|
22
|
-
const a = new Literal("a", "A");
|
|
23
|
-
const parent = new And("parent", [a]);
|
|
24
|
-
const grandParent = new And("grand-parent", [parent]);
|
|
25
|
-
const clonedA = findPattern(grandParent, p=>p.name === "a");
|
|
26
|
-
const nextPattern = clonedA?.getNextPattern();
|
|
27
|
-
|
|
28
|
-
expect(nextPattern).toBe(null);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
test("Get Sibling", ()=>{
|
|
32
|
-
const a = new Literal("a", "A");
|
|
33
|
-
const b = new Literal("b", "B");
|
|
34
|
-
const parent = new And("parent", [a, b]);
|
|
35
|
-
|
|
36
|
-
const nextPattern = parent.children[0].getNextPattern();
|
|
37
|
-
expect(nextPattern?.name).toBe("b");
|
|
38
|
-
});
|
|
39
|
-
});
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { Pattern } from "./Pattern";
|
|
2
|
-
|
|
3
|
-
export function getNextPattern(pattern: Pattern): Pattern | null {
|
|
4
|
-
const parent = pattern.parent;
|
|
5
|
-
|
|
6
|
-
if (parent == null) {
|
|
7
|
-
return null;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const patternIndex = parent.children.indexOf(pattern);
|
|
11
|
-
const nextPattern = parent.children[patternIndex + 1] || null;
|
|
12
|
-
|
|
13
|
-
if (nextPattern == null) {
|
|
14
|
-
return parent.getNextPattern();
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return nextPattern;
|
|
18
|
-
}
|