clarity-pattern-parser 9.2.5 → 10.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/dist/ast/Node.d.ts +9 -2
- package/dist/index.browser.js +70 -44
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.esm.js +71 -44
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +70 -44
- package/dist/index.js.map +1 -1
- package/dist/patterns/Cursor.d.ts +1 -1
- package/dist/patterns/CursorHistory.d.ts +1 -1
- package/dist/patterns/Literal.d.ts +3 -3
- package/dist/patterns/Pattern.d.ts +1 -1
- package/dist/patterns/Regex.d.ts +1 -1
- package/dist/types.d.ts +797 -0
- package/package.json +1 -1
- package/src/ast/Node.test.ts +60 -24
- package/src/ast/Node.ts +75 -28
- package/src/grammar/Grammar.test.ts +26 -25
- package/src/grammar/Grammar.ts +1 -1
- package/src/index.ts +0 -2
- package/src/patterns/Cursor.ts +5 -4
- package/src/patterns/CursorHistory.ts +3 -3
- package/src/patterns/FiniteRepeat.test.ts +4 -5
- package/src/patterns/InfiniteRepeat.test.ts +1 -2
- package/src/patterns/Literal.ts +12 -11
- package/src/patterns/ParseError.ts +1 -1
- package/src/patterns/Pattern.ts +1 -1
- package/src/patterns/Regex.ts +1 -1
- package/src/patterns/Repeat.test.ts +2 -3
- package/src/patterns/arePatternsEqual.ts +0 -12
package/package.json
CHANGED
package/src/ast/Node.test.ts
CHANGED
|
@@ -16,7 +16,7 @@ describe("Node", () => {
|
|
|
16
16
|
});
|
|
17
17
|
|
|
18
18
|
test("Properties", () => {
|
|
19
|
-
const child = new Node("child", "child", 0, 0, undefined, "Content")
|
|
19
|
+
const child = new Node("child", "child", 0, 0, undefined, "Content");
|
|
20
20
|
const parent = new Node("parent", "parent", 0, 0, [
|
|
21
21
|
child,
|
|
22
22
|
]);
|
|
@@ -99,7 +99,7 @@ describe("Node", () => {
|
|
|
99
99
|
parent.insertBefore(b, a);
|
|
100
100
|
|
|
101
101
|
expect(parent.children.length).toBe(2);
|
|
102
|
-
expect(parent.value).toBe("BA")
|
|
102
|
+
expect(parent.value).toBe("BA");
|
|
103
103
|
expect(parent.children[0]).toBe(b);
|
|
104
104
|
expect(parent.children[1]).toBe(a);
|
|
105
105
|
expect(a.parent).toBe(parent);
|
|
@@ -118,7 +118,7 @@ describe("Node", () => {
|
|
|
118
118
|
parent.insertBefore(b, null);
|
|
119
119
|
|
|
120
120
|
expect(parent.children.length).toBe(2);
|
|
121
|
-
expect(parent.value).toBe("AB")
|
|
121
|
+
expect(parent.value).toBe("AB");
|
|
122
122
|
expect(parent.children[0]).toBe(a);
|
|
123
123
|
expect(parent.children[1]).toBe(b);
|
|
124
124
|
expect(a.parent).toBe(parent);
|
|
@@ -137,7 +137,7 @@ describe("Node", () => {
|
|
|
137
137
|
parent.appendChild(b);
|
|
138
138
|
|
|
139
139
|
expect(parent.children.length).toBe(2);
|
|
140
|
-
expect(parent.value).toBe("AB")
|
|
140
|
+
expect(parent.value).toBe("AB");
|
|
141
141
|
expect(parent.children[0]).toBe(a);
|
|
142
142
|
expect(parent.children[1]).toBe(b);
|
|
143
143
|
expect(a.parent).toBe(parent);
|
|
@@ -156,7 +156,7 @@ describe("Node", () => {
|
|
|
156
156
|
parent.spliceChildren(0, 0, b);
|
|
157
157
|
|
|
158
158
|
expect(parent.children.length).toBe(2);
|
|
159
|
-
expect(parent.value).toBe("BA")
|
|
159
|
+
expect(parent.value).toBe("BA");
|
|
160
160
|
expect(parent.children[0]).toBe(b);
|
|
161
161
|
expect(parent.children[1]).toBe(a);
|
|
162
162
|
expect(a.parent).toBe(parent);
|
|
@@ -175,7 +175,7 @@ describe("Node", () => {
|
|
|
175
175
|
parent.spliceChildren(0, 1, b);
|
|
176
176
|
|
|
177
177
|
expect(parent.children.length).toBe(1);
|
|
178
|
-
expect(parent.value).toBe("B")
|
|
178
|
+
expect(parent.value).toBe("B");
|
|
179
179
|
expect(parent.children[0]).toBe(b);
|
|
180
180
|
expect(a.parent).toBeNull();
|
|
181
181
|
expect(b.parent).toBe(parent);
|
|
@@ -191,7 +191,7 @@ describe("Node", () => {
|
|
|
191
191
|
parent.find(p => p.name === "b")?.remove();
|
|
192
192
|
|
|
193
193
|
expect(parent.children.length).toBe(1);
|
|
194
|
-
expect(parent.value).toBe("A")
|
|
194
|
+
expect(parent.value).toBe("A");
|
|
195
195
|
expect(parent.children[0]).toBe(a);
|
|
196
196
|
expect(a.parent).toBe(parent);
|
|
197
197
|
expect(b.parent).toBeNull();
|
|
@@ -203,7 +203,7 @@ describe("Node", () => {
|
|
|
203
203
|
const b = new Node("b", "b", 0, 0, [], "B");
|
|
204
204
|
new Node("parent", "parent", 0, 0, [a, b]);
|
|
205
205
|
|
|
206
|
-
const nextSibling = a.nextSibling()
|
|
206
|
+
const nextSibling = a.nextSibling();
|
|
207
207
|
|
|
208
208
|
expect(nextSibling).toBe(b);
|
|
209
209
|
});
|
|
@@ -211,7 +211,7 @@ describe("Node", () => {
|
|
|
211
211
|
test("Next Sibling (No Parent)", () => {
|
|
212
212
|
const a = new Node("a", "a", 0, 0, [], "A");
|
|
213
213
|
|
|
214
|
-
const nextSibling = a.nextSibling()
|
|
214
|
+
const nextSibling = a.nextSibling();
|
|
215
215
|
expect(nextSibling).toBeNull;
|
|
216
216
|
});
|
|
217
217
|
|
|
@@ -220,7 +220,7 @@ describe("Node", () => {
|
|
|
220
220
|
const b = new Node("b", "b", 0, 0, [], "B");
|
|
221
221
|
new Node("parent", "parent", 0, 0, [a, b]);
|
|
222
222
|
|
|
223
|
-
const nextSibling = b.nextSibling()
|
|
223
|
+
const nextSibling = b.nextSibling();
|
|
224
224
|
expect(nextSibling).toBeNull;
|
|
225
225
|
});
|
|
226
226
|
|
|
@@ -229,14 +229,14 @@ describe("Node", () => {
|
|
|
229
229
|
const b = new Node("b", "b", 0, 0, [], "B");
|
|
230
230
|
new Node("parent", "parent", 0, 0, [a, b]);
|
|
231
231
|
|
|
232
|
-
const previousSibling = b.previousSibling()
|
|
232
|
+
const previousSibling = b.previousSibling();
|
|
233
233
|
|
|
234
234
|
expect(previousSibling).toBe(a);
|
|
235
235
|
});
|
|
236
236
|
|
|
237
237
|
test("Previous Sibling (No Parent)", () => {
|
|
238
238
|
const a = new Node("a", "a", 0, 0, [], "A");
|
|
239
|
-
const previousSibling = a.previousSibling()
|
|
239
|
+
const previousSibling = a.previousSibling();
|
|
240
240
|
expect(previousSibling).toBeNull();
|
|
241
241
|
});
|
|
242
242
|
|
|
@@ -245,7 +245,7 @@ describe("Node", () => {
|
|
|
245
245
|
const b = new Node("b", "b", 0, 0, [], "B");
|
|
246
246
|
new Node("parent", "parent", 0, 0, [a, b]);
|
|
247
247
|
|
|
248
|
-
const previousSibling = a.previousSibling()
|
|
248
|
+
const previousSibling = a.previousSibling();
|
|
249
249
|
expect(previousSibling).toBeNull;
|
|
250
250
|
});
|
|
251
251
|
|
|
@@ -256,7 +256,7 @@ describe("Node", () => {
|
|
|
256
256
|
|
|
257
257
|
const result = parent.find(n => n.name === "a");
|
|
258
258
|
|
|
259
|
-
expect(result).toBe(a)
|
|
259
|
+
expect(result).toBe(a);
|
|
260
260
|
});
|
|
261
261
|
|
|
262
262
|
test("Walk Down", () => {
|
|
@@ -266,7 +266,7 @@ describe("Node", () => {
|
|
|
266
266
|
const parent = new Node("parent", "parent", 0, 0, [a, b]);
|
|
267
267
|
|
|
268
268
|
parent.walkDown((n) => {
|
|
269
|
-
result.push(n)
|
|
269
|
+
result.push(n);
|
|
270
270
|
});
|
|
271
271
|
|
|
272
272
|
const expected = [parent, a, b];
|
|
@@ -281,7 +281,7 @@ describe("Node", () => {
|
|
|
281
281
|
const parent = new Node("parent", "parent", 0, 0, [a, b]);
|
|
282
282
|
|
|
283
283
|
parent.walkUp((n) => {
|
|
284
|
-
result.push(n)
|
|
284
|
+
result.push(n);
|
|
285
285
|
});
|
|
286
286
|
|
|
287
287
|
const expected = [a, b, parent];
|
|
@@ -295,7 +295,7 @@ describe("Node", () => {
|
|
|
295
295
|
const parent = new Node("parent", "parent", 0, 0, [a, b]);
|
|
296
296
|
const clone = parent.clone();
|
|
297
297
|
|
|
298
|
-
expect(clone).toEqual(parent)
|
|
298
|
+
expect(clone).toEqual(parent);
|
|
299
299
|
});
|
|
300
300
|
|
|
301
301
|
test("Turn Into JSON", () => {
|
|
@@ -326,7 +326,7 @@ describe("Node", () => {
|
|
|
326
326
|
}],
|
|
327
327
|
});
|
|
328
328
|
|
|
329
|
-
expect(result).toEqual(expected)
|
|
329
|
+
expect(result).toEqual(expected);
|
|
330
330
|
});
|
|
331
331
|
|
|
332
332
|
test("Reduce", () => {
|
|
@@ -337,7 +337,7 @@ describe("Node", () => {
|
|
|
337
337
|
parent.reduce();
|
|
338
338
|
|
|
339
339
|
expect(parent.hasChildren).toBeFalsy();
|
|
340
|
-
expect(parent.value).toBe("Content")
|
|
340
|
+
expect(parent.value).toBe("Content");
|
|
341
341
|
});
|
|
342
342
|
|
|
343
343
|
test("Flatten", () => {
|
|
@@ -358,22 +358,22 @@ describe("Node", () => {
|
|
|
358
358
|
const nodes = grandParent.flatten();
|
|
359
359
|
const expected = [a, b, c];
|
|
360
360
|
|
|
361
|
-
expect(nodes).toEqual(expected)
|
|
361
|
+
expect(nodes).toEqual(expected);
|
|
362
362
|
});
|
|
363
363
|
|
|
364
364
|
test("Find Ancester", () => {
|
|
365
365
|
const child = new Node("child", "child", 0, 0, []);
|
|
366
366
|
const parent = new Node("parent", "parent", 0, 0, [child]);
|
|
367
367
|
const grandParent = new Node("grand-parent", "grand-parent", 0, 0, [parent]);
|
|
368
|
-
const result = child.
|
|
368
|
+
const result = child.findAncestor(p => p.name === "grand-parent");
|
|
369
369
|
|
|
370
|
-
expect(result).toBe(grandParent)
|
|
370
|
+
expect(result).toBe(grandParent);
|
|
371
371
|
});
|
|
372
372
|
|
|
373
373
|
test("Find Ancester Without Parent", () => {
|
|
374
374
|
const child = new Node("child", "child", 0, 0, []);
|
|
375
|
-
const result = child.
|
|
376
|
-
expect(result).toBeNull()
|
|
375
|
+
const result = child.findAncestor(p => p.name === "parent");
|
|
376
|
+
expect(result).toBeNull();
|
|
377
377
|
});
|
|
378
378
|
|
|
379
379
|
test("Normalize values and index", () => {
|
|
@@ -420,4 +420,40 @@ describe("Node", () => {
|
|
|
420
420
|
|
|
421
421
|
});
|
|
422
422
|
|
|
423
|
+
test("Transform", () => {
|
|
424
|
+
const node = Node.createNode("grandparent", [
|
|
425
|
+
Node.createNode("parent", [
|
|
426
|
+
Node.createValueNode("child", "John"),
|
|
427
|
+
Node.createValueNode("child", "Jane"),
|
|
428
|
+
Node.createValueNode("child", "Jack")
|
|
429
|
+
]),
|
|
430
|
+
Node.createValueNode("aunt", "aunt")
|
|
431
|
+
]);
|
|
432
|
+
|
|
433
|
+
const result = node.transform({
|
|
434
|
+
"child": (node: Node) => {
|
|
435
|
+
return Node.createValueNode("adopted-child", node.value);
|
|
436
|
+
},
|
|
437
|
+
"parent": (node)=>{
|
|
438
|
+
return Node.createNode("adopted-parent", node.children.slice());
|
|
439
|
+
},
|
|
440
|
+
"grandparent": (node)=>{
|
|
441
|
+
return Node.createNode("adopted-grandparent", node.children.slice());
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
const expected = Node.createNode("adopted-grandparent", [
|
|
446
|
+
Node.createNode("adopted-parent", [
|
|
447
|
+
Node.createValueNode("adopted-child", "John"),
|
|
448
|
+
Node.createValueNode("adopted-child", "Jane"),
|
|
449
|
+
Node.createValueNode("adopted-child", "Jack")
|
|
450
|
+
]),
|
|
451
|
+
Node.createValueNode("aunt", "aunt")
|
|
452
|
+
]);
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
expect(result.toJson()).toBe(expected.toJson());
|
|
457
|
+
});
|
|
458
|
+
|
|
423
459
|
});
|
package/src/ast/Node.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
function defaultVisitor(node: Node) {
|
|
2
|
+
return node;
|
|
3
|
+
}
|
|
4
|
+
|
|
1
5
|
export interface CycleFreeNode {
|
|
2
6
|
type: string;
|
|
3
7
|
name: string;
|
|
@@ -52,6 +56,10 @@ export class Node {
|
|
|
52
56
|
return this._children.length > 0;
|
|
53
57
|
}
|
|
54
58
|
|
|
59
|
+
get isLeaf(): boolean {
|
|
60
|
+
return !this.hasChildren;
|
|
61
|
+
}
|
|
62
|
+
|
|
55
63
|
get value() {
|
|
56
64
|
return this.toString();
|
|
57
65
|
}
|
|
@@ -72,7 +80,7 @@ export class Node {
|
|
|
72
80
|
this._children = children;
|
|
73
81
|
this._value = value;
|
|
74
82
|
|
|
75
|
-
this._children.forEach(c => c._parent = this)
|
|
83
|
+
this._children.forEach(c => c._parent = this);
|
|
76
84
|
}
|
|
77
85
|
|
|
78
86
|
removeChild(node: Node) {
|
|
@@ -84,18 +92,28 @@ export class Node {
|
|
|
84
92
|
}
|
|
85
93
|
}
|
|
86
94
|
|
|
95
|
+
findChildIndex(node: Node) {
|
|
96
|
+
return this._children.indexOf(node);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
spliceChildren(index: number, deleteCount: number, ...items: Node[]) {
|
|
100
|
+
const removedItems = this._children.splice(index, deleteCount, ...items);
|
|
101
|
+
|
|
102
|
+
removedItems.forEach(i => i._parent = null);
|
|
103
|
+
items.forEach(i => i._parent = this);
|
|
104
|
+
|
|
105
|
+
return removedItems;
|
|
106
|
+
}
|
|
107
|
+
|
|
87
108
|
removeAllChildren() {
|
|
88
|
-
this.
|
|
89
|
-
this._children.length = 0;
|
|
109
|
+
this.spliceChildren(0, this._children.length);
|
|
90
110
|
}
|
|
91
111
|
|
|
92
112
|
replaceChild(newNode: Node, referenceNode: Node) {
|
|
93
|
-
const index = this.
|
|
113
|
+
const index = this.findChildIndex(referenceNode);
|
|
94
114
|
|
|
95
115
|
if (index > -1) {
|
|
96
|
-
this.
|
|
97
|
-
newNode._parent = this;
|
|
98
|
-
referenceNode._parent = null;
|
|
116
|
+
this.spliceChildren(index, 1, newNode);
|
|
99
117
|
}
|
|
100
118
|
}
|
|
101
119
|
|
|
@@ -113,7 +131,7 @@ export class Node {
|
|
|
113
131
|
return;
|
|
114
132
|
}
|
|
115
133
|
|
|
116
|
-
const index = this.
|
|
134
|
+
const index = this.findChildIndex(referenceNode);
|
|
117
135
|
|
|
118
136
|
if (index > -1) {
|
|
119
137
|
this._children.splice(index, 0, newNode);
|
|
@@ -121,17 +139,14 @@ export class Node {
|
|
|
121
139
|
}
|
|
122
140
|
|
|
123
141
|
appendChild(newNode: Node) {
|
|
124
|
-
newNode
|
|
125
|
-
this._children.push(newNode);
|
|
142
|
+
this.append(newNode);
|
|
126
143
|
}
|
|
127
144
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
return removedItems;
|
|
145
|
+
append(...nodes: Node[]) {
|
|
146
|
+
nodes.forEach((newNode: Node) => {
|
|
147
|
+
newNode._parent = this;
|
|
148
|
+
this._children.push(newNode);
|
|
149
|
+
});
|
|
135
150
|
}
|
|
136
151
|
|
|
137
152
|
nextSibling() {
|
|
@@ -143,10 +158,10 @@ export class Node {
|
|
|
143
158
|
const index = children.indexOf(this);
|
|
144
159
|
|
|
145
160
|
if (index > -1 && index < children.length - 1) {
|
|
146
|
-
return children[index + 1]
|
|
161
|
+
return children[index + 1];
|
|
147
162
|
}
|
|
148
163
|
|
|
149
|
-
return null
|
|
164
|
+
return null;
|
|
150
165
|
}
|
|
151
166
|
|
|
152
167
|
previousSibling() {
|
|
@@ -158,26 +173,27 @@ export class Node {
|
|
|
158
173
|
const index = children.indexOf(this);
|
|
159
174
|
|
|
160
175
|
if (index > -1 && index > 0) {
|
|
161
|
-
return children[index - 1]
|
|
176
|
+
return children[index - 1];
|
|
162
177
|
}
|
|
163
178
|
|
|
164
|
-
return null
|
|
179
|
+
return null;
|
|
165
180
|
}
|
|
166
181
|
|
|
167
182
|
find(predicate: (node: Node) => boolean): Node | null {
|
|
168
|
-
return this.findAll(predicate)[0] || null
|
|
183
|
+
return this.findAll(predicate)[0] || null;
|
|
169
184
|
}
|
|
170
185
|
|
|
171
186
|
findAll(predicate: (node: Node) => boolean): Node[] {
|
|
172
187
|
const matches: Node[] = [];
|
|
188
|
+
|
|
173
189
|
this.walkUp(n => {
|
|
174
190
|
if (predicate(n)) { matches.push(n); }
|
|
175
|
-
})
|
|
191
|
+
});
|
|
176
192
|
|
|
177
193
|
return matches;
|
|
178
194
|
}
|
|
179
195
|
|
|
180
|
-
|
|
196
|
+
findAncestor(predicate: (node: Node) => boolean) {
|
|
181
197
|
let parent = this._parent;
|
|
182
198
|
|
|
183
199
|
while (parent != null) {
|
|
@@ -194,7 +210,7 @@ export class Node {
|
|
|
194
210
|
walkUp(callback: (node: Node) => void) {
|
|
195
211
|
const childrenCopy = this._children.slice();
|
|
196
212
|
|
|
197
|
-
childrenCopy.forEach(c => c.walkUp(callback))
|
|
213
|
+
childrenCopy.forEach(c => c.walkUp(callback));
|
|
198
214
|
callback(this);
|
|
199
215
|
}
|
|
200
216
|
|
|
@@ -202,7 +218,29 @@ export class Node {
|
|
|
202
218
|
const childrenCopy = this._children.slice();
|
|
203
219
|
|
|
204
220
|
callback(this);
|
|
205
|
-
childrenCopy.forEach(c => c.walkDown(callback))
|
|
221
|
+
childrenCopy.forEach(c => c.walkDown(callback));
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
walkBreadthFirst(callback: (node: Node) => void): void {
|
|
225
|
+
const queue: Node[] = [this];
|
|
226
|
+
|
|
227
|
+
while (queue.length > 0) {
|
|
228
|
+
// biome-ignore lint/style/noNonNullAssertion: This will never be undefined.
|
|
229
|
+
const current = queue.shift()!;
|
|
230
|
+
callback(current);
|
|
231
|
+
queue.push(...current.children);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
transform(visitors: Record<string, (node: Node) => Node>) {
|
|
236
|
+
const childrenCopy = this._children.slice();
|
|
237
|
+
const visitor = visitors[this.name] == null ? defaultVisitor : visitors[this.name];
|
|
238
|
+
|
|
239
|
+
const children = childrenCopy.map(c => c.transform(visitors));
|
|
240
|
+
this.removeAllChildren();
|
|
241
|
+
this.append(...children);
|
|
242
|
+
|
|
243
|
+
return visitor(this);
|
|
206
244
|
}
|
|
207
245
|
|
|
208
246
|
flatten() {
|
|
@@ -259,7 +297,7 @@ export class Node {
|
|
|
259
297
|
return this._value;
|
|
260
298
|
}
|
|
261
299
|
|
|
262
|
-
return this._children.map(c => c.toString()).join("")
|
|
300
|
+
return this._children.map(c => c.toString()).join("");
|
|
263
301
|
}
|
|
264
302
|
|
|
265
303
|
toCycleFreeObject(): CycleFreeNode {
|
|
@@ -274,6 +312,15 @@ export class Node {
|
|
|
274
312
|
}
|
|
275
313
|
|
|
276
314
|
toJson(space?: number): string {
|
|
277
|
-
return JSON.stringify(this.toCycleFreeObject(), null, space)
|
|
315
|
+
return JSON.stringify(this.toCycleFreeObject(), null, space);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
static createValueNode(name: string, value: string) {
|
|
319
|
+
return new Node("custom-value-node", name, 0, 0, [], value);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
static createNode(name: string, children: Node[]) {
|
|
323
|
+
const value = children.map(c => c.toString()).join("");
|
|
324
|
+
return new Node("custom-node", name, 0, 0, children, value);
|
|
278
325
|
}
|
|
279
326
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Sequence } from "../patterns/Sequence";
|
|
2
|
-
import { arePatternsEqual } from "../patterns/arePatternsEqual";
|
|
3
2
|
import { Literal } from "../patterns/Literal";
|
|
4
3
|
import { Not } from "../patterns/Not";
|
|
5
4
|
import { Options } from "../patterns/Options";
|
|
@@ -20,7 +19,7 @@ describe("Grammar", () => {
|
|
|
20
19
|
const namePattern = patterns["name"];
|
|
21
20
|
const expected = new Literal("name", "John");
|
|
22
21
|
|
|
23
|
-
expect(
|
|
22
|
+
expect(namePattern.isEqual(expected)).toBeTruthy();
|
|
24
23
|
});
|
|
25
24
|
|
|
26
25
|
test("Literal With Escaped Characters", () => {
|
|
@@ -31,7 +30,7 @@ describe("Grammar", () => {
|
|
|
31
30
|
const namePattern = patterns["chars"];
|
|
32
31
|
const expected = new Literal("chars", "\n\r\t\b\f\v\0\x00\u0000\"\\");
|
|
33
32
|
|
|
34
|
-
expect(
|
|
33
|
+
expect(namePattern.isEqual(expected)).toBeTruthy();
|
|
35
34
|
});
|
|
36
35
|
|
|
37
36
|
test("Literal With Escaped Quotes", () => {
|
|
@@ -42,7 +41,7 @@ describe("Grammar", () => {
|
|
|
42
41
|
const namePattern = patterns["content"];
|
|
43
42
|
const expected = new Literal("content", "With Con\"tent");
|
|
44
43
|
|
|
45
|
-
expect(
|
|
44
|
+
expect(namePattern.isEqual(expected)).toBeTruthy();
|
|
46
45
|
});
|
|
47
46
|
|
|
48
47
|
test("Regex", () => {
|
|
@@ -54,7 +53,7 @@ describe("Grammar", () => {
|
|
|
54
53
|
const pattern = patterns["name"];
|
|
55
54
|
const name = new Regex("name", "\\w");
|
|
56
55
|
|
|
57
|
-
expect(
|
|
56
|
+
expect(pattern.isEqual(name)).toBeTruthy();
|
|
58
57
|
});
|
|
59
58
|
|
|
60
59
|
test("Or", () => {
|
|
@@ -70,7 +69,7 @@ describe("Grammar", () => {
|
|
|
70
69
|
const jane = new Literal("jane", "Jane");
|
|
71
70
|
const names = new Options("names", [john, jane], true);
|
|
72
71
|
|
|
73
|
-
expect(
|
|
72
|
+
expect(pattern.isEqual(names)).toBeTruthy();
|
|
74
73
|
});
|
|
75
74
|
|
|
76
75
|
test("And", () => {
|
|
@@ -88,7 +87,7 @@ describe("Grammar", () => {
|
|
|
88
87
|
const lastName = new Regex("last-name", "\\w");
|
|
89
88
|
const fullName = new Sequence("full-name", [firstName, space, lastName]);
|
|
90
89
|
|
|
91
|
-
expect(
|
|
90
|
+
expect(pattern.isEqual(fullName)).toBeTruthy();
|
|
92
91
|
});
|
|
93
92
|
|
|
94
93
|
test("And With Optional Pattern", () => {
|
|
@@ -110,7 +109,7 @@ describe("Grammar", () => {
|
|
|
110
109
|
const middleNameWithSpace = new Optional("optional-middle-name-with-space", new Sequence("middle-name-with-space", [middleName, space]));
|
|
111
110
|
const fullName = new Sequence("full-name", [firstName, space, middleNameWithSpace, lastName]);
|
|
112
111
|
|
|
113
|
-
expect(
|
|
112
|
+
expect(pattern.isEqual(fullName)).toBeTruthy();
|
|
114
113
|
});
|
|
115
114
|
|
|
116
115
|
test("And With Not Pattern", () => {
|
|
@@ -134,7 +133,8 @@ describe("Grammar", () => {
|
|
|
134
133
|
const notJack = new Not("not-jack", jack);
|
|
135
134
|
const middleNameWithSpace = new Optional("optional-middle-name-with-space", new Sequence("middle-name-with-space", [middleName, space]));
|
|
136
135
|
const fullName = new Sequence("full-name", [notJack, firstName, space, middleNameWithSpace, lastName]);
|
|
137
|
-
|
|
136
|
+
|
|
137
|
+
expect(pattern.isEqual(fullName)).toBeTruthy();
|
|
138
138
|
});
|
|
139
139
|
|
|
140
140
|
test("Repeat", () => {
|
|
@@ -148,7 +148,7 @@ describe("Grammar", () => {
|
|
|
148
148
|
const digit = new Regex("digit", "\\d");
|
|
149
149
|
const digits = new Repeat("digits", digit);
|
|
150
150
|
|
|
151
|
-
expect(
|
|
151
|
+
expect(pattern.isEqual(digits)).toBeTruthy();
|
|
152
152
|
});
|
|
153
153
|
|
|
154
154
|
test("Repeat Zero Or More", () => {
|
|
@@ -162,7 +162,7 @@ describe("Grammar", () => {
|
|
|
162
162
|
const digit = new Regex("digit", "\\d");
|
|
163
163
|
const digits = new Optional("digits", new Repeat("digits", digit, { min: 0 }));
|
|
164
164
|
|
|
165
|
-
expect(
|
|
165
|
+
expect(pattern.isEqual(digits)).toBeTruthy();
|
|
166
166
|
});
|
|
167
167
|
|
|
168
168
|
test("Repeat Lower Limit", () => {
|
|
@@ -176,7 +176,7 @@ describe("Grammar", () => {
|
|
|
176
176
|
const digit = new Regex("digit", "\\d+");
|
|
177
177
|
const digits = new Repeat("digits", digit, { min: 1 });
|
|
178
178
|
|
|
179
|
-
expect(
|
|
179
|
+
expect(pattern.isEqual(digits)).toBeTruthy();
|
|
180
180
|
});
|
|
181
181
|
|
|
182
182
|
test("Repeat Bounded", () => {
|
|
@@ -189,7 +189,8 @@ describe("Grammar", () => {
|
|
|
189
189
|
const pattern = patterns["digits"];
|
|
190
190
|
const digit = new Regex("digit", "\\d+");
|
|
191
191
|
const digits = new Repeat("digits", digit, { min: 1, max: 3 });
|
|
192
|
-
|
|
192
|
+
|
|
193
|
+
expect(pattern.isEqual(digits)).toBeTruthy();
|
|
193
194
|
});
|
|
194
195
|
|
|
195
196
|
test("Repeat Upper Limit", () => {
|
|
@@ -203,7 +204,7 @@ describe("Grammar", () => {
|
|
|
203
204
|
const digit = new Regex("digit", "\\d+");
|
|
204
205
|
const digits = new Repeat("digits", digit, { min: 0, max: 3 });
|
|
205
206
|
|
|
206
|
-
expect(
|
|
207
|
+
expect(pattern.isEqual(digits)).toBeTruthy();
|
|
207
208
|
});
|
|
208
209
|
|
|
209
210
|
test("Repeat Exact", () => {
|
|
@@ -217,7 +218,7 @@ describe("Grammar", () => {
|
|
|
217
218
|
const digit = new Regex("digit", "\\d+");
|
|
218
219
|
const digits = new Repeat("digits", digit, { min: 3, max: 3 });
|
|
219
220
|
|
|
220
|
-
expect(
|
|
221
|
+
expect(pattern.isEqual(digits)).toBeTruthy();
|
|
221
222
|
});
|
|
222
223
|
|
|
223
224
|
test("Repeat Divider", () => {
|
|
@@ -233,7 +234,7 @@ describe("Grammar", () => {
|
|
|
233
234
|
const divider = new Literal("comma", ",");
|
|
234
235
|
const digits = new Repeat("digits", digit, { divider, min: 3, max: 3 });
|
|
235
236
|
|
|
236
|
-
expect(
|
|
237
|
+
expect(pattern.isEqual(digits)).toBeTruthy();
|
|
237
238
|
});
|
|
238
239
|
|
|
239
240
|
test("Repeat Divider With Trim Divider", () => {
|
|
@@ -248,8 +249,8 @@ describe("Grammar", () => {
|
|
|
248
249
|
const digit = new Regex("digit", "\\d+");
|
|
249
250
|
const divider = new Literal("comma", ",");
|
|
250
251
|
const digits = new Repeat("digits", digit, { divider, min: 1, trimDivider: true });
|
|
251
|
-
|
|
252
|
-
expect(
|
|
252
|
+
|
|
253
|
+
expect(pattern.isEqual(digits)).toBeTruthy();
|
|
253
254
|
});
|
|
254
255
|
|
|
255
256
|
test("Repeat Divider With Trim Divider And Bounds", () => {
|
|
@@ -265,7 +266,7 @@ describe("Grammar", () => {
|
|
|
265
266
|
const divider = new Literal("comma", ",");
|
|
266
267
|
const digits = new Repeat("digits", digit, { divider, min: 3, max: 3, trimDivider: true });
|
|
267
268
|
|
|
268
|
-
expect(
|
|
269
|
+
expect(pattern.isEqual(digits)).toBeTruthy();
|
|
269
270
|
});
|
|
270
271
|
|
|
271
272
|
test("Reference", () => {
|
|
@@ -303,8 +304,8 @@ describe("Grammar", () => {
|
|
|
303
304
|
const alias = patterns["alias"];
|
|
304
305
|
const expectedAlias = new Regex("alias", "regex");
|
|
305
306
|
|
|
306
|
-
expect(
|
|
307
|
-
expect(
|
|
307
|
+
expect(name.isEqual(expectedName)).toBeTruthy();
|
|
308
|
+
expect(alias.isEqual(expectedAlias)).toBeTruthy();
|
|
308
309
|
});
|
|
309
310
|
|
|
310
311
|
test("Bad Grammar At Beginning", () => {
|
|
@@ -497,17 +498,17 @@ describe("Grammar", () => {
|
|
|
497
498
|
])
|
|
498
499
|
]);
|
|
499
500
|
|
|
500
|
-
expect(
|
|
501
|
+
expect(patterns["complex-expression"].isEqual(expected)).toBeTruthy();
|
|
501
502
|
});
|
|
502
503
|
|
|
503
|
-
test("Grammar With Spaces", ()=>{
|
|
504
|
+
test("Grammar With Spaces", () => {
|
|
504
505
|
const expression = `
|
|
505
506
|
john = "John"
|
|
506
507
|
|
|
507
508
|
jane = "Jane"
|
|
508
509
|
`;
|
|
509
510
|
const patterns = Grammar.parseString(expression);
|
|
510
|
-
expect(patterns.john).not.toBeNull();
|
|
511
|
-
expect(patterns.jane).not.toBeNull();
|
|
511
|
+
expect(patterns.john).not.toBeNull();
|
|
512
|
+
expect(patterns.jane).not.toBeNull();
|
|
512
513
|
});
|
|
513
514
|
});
|
package/src/grammar/Grammar.ts
CHANGED
|
@@ -131,7 +131,7 @@ export class Grammar {
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
private _buildPatterns(ast: Node) {
|
|
134
|
-
const body = ast.find(n => n.name === "body" && n.
|
|
134
|
+
const body = ast.find(n => n.name === "body" && n.findAncestor(n => n.name === "head") == null);
|
|
135
135
|
|
|
136
136
|
if (body == null) {
|
|
137
137
|
return;
|
package/src/index.ts
CHANGED
|
@@ -17,7 +17,6 @@ import { Reference } from "./patterns/Reference";
|
|
|
17
17
|
import { CursorHistory, Match } from "./patterns/CursorHistory";
|
|
18
18
|
import { ParseResult } from "./patterns/ParseResult";
|
|
19
19
|
import { grammar } from "./grammar/patterns/grammar";
|
|
20
|
-
import { arePatternsEqual } from "./patterns/arePatternsEqual";
|
|
21
20
|
import { patterns } from "./grammar/patterns";
|
|
22
21
|
|
|
23
22
|
export {
|
|
@@ -42,6 +41,5 @@ export {
|
|
|
42
41
|
Regex,
|
|
43
42
|
Repeat,
|
|
44
43
|
grammar,
|
|
45
|
-
arePatternsEqual,
|
|
46
44
|
patterns,
|
|
47
45
|
};
|
package/src/patterns/Cursor.ts
CHANGED
|
@@ -77,7 +77,7 @@ export class Cursor {
|
|
|
77
77
|
constructor(text: string) {
|
|
78
78
|
this._text = text;
|
|
79
79
|
this._index = 0;
|
|
80
|
-
this._length = text.length;
|
|
80
|
+
this._length = [...text].length;
|
|
81
81
|
this._history = new CursorHistory();
|
|
82
82
|
this._stackTrace = [];
|
|
83
83
|
}
|
|
@@ -128,8 +128,8 @@ export class Cursor {
|
|
|
128
128
|
this._history.recordMatch(pattern, node);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
recordErrorAt(
|
|
132
|
-
this._history.recordErrorAt(
|
|
131
|
+
recordErrorAt(startIndex: number, endIndex: number, onPattern: Pattern): void {
|
|
132
|
+
this._history.recordErrorAt(startIndex, endIndex, onPattern);
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
resolveError(): void {
|
|
@@ -152,7 +152,8 @@ export class Cursor {
|
|
|
152
152
|
cursorIndex: this.index
|
|
153
153
|
};
|
|
154
154
|
|
|
155
|
-
|
|
155
|
+
const hasCycle = this._stackTrace.find(t => t.pattern.id === pattern.id && this.index === t.cursorIndex);
|
|
156
|
+
if (hasCycle) {
|
|
156
157
|
throw new Error(`Cyclical Pattern: ${this._stackTrace.map(t => `${t.pattern.name}#${t.pattern.id}{${t.cursorIndex}}`).join(" -> ")} -> ${patternName}#${pattern.id}{${this.index}}.`);
|
|
157
158
|
}
|
|
158
159
|
|