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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clarity-pattern-parser",
3
- "version": "9.2.5",
3
+ "version": "10.0.1",
4
4
  "description": "Parsing Library for Typescript and Javascript.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.esm.js",
@@ -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.findAncester(p => p.name === "grand-parent")
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.findAncester(p => p.name === "parent")
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._children.forEach(c => c._parent = null);
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._children.indexOf(referenceNode);
113
+ const index = this.findChildIndex(referenceNode);
94
114
 
95
115
  if (index > -1) {
96
- this._children.splice(index, 1, newNode);
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._children.indexOf(referenceNode);
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._parent = this;
125
- this._children.push(newNode);
142
+ this.append(newNode);
126
143
  }
127
144
 
128
- spliceChildren(index: number, deleteCount: number, ...items: Node[]) {
129
- const removedItems = this._children.splice(index, deleteCount, ...items);
130
-
131
- removedItems.forEach(i => i._parent = null);
132
- items.forEach(i => i._parent = this);
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
- findAncester(predicate: (node: Node) => boolean) {
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(arePatternsEqual(namePattern, expected)).toBeTruthy();
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(arePatternsEqual(namePattern, expected)).toBeTruthy();
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(arePatternsEqual(namePattern, expected)).toBeTruthy();
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(arePatternsEqual(pattern, name)).toBeTruthy();
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(arePatternsEqual(pattern, names)).toBeTruthy();
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(arePatternsEqual(pattern, fullName)).toBeTruthy();
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(arePatternsEqual(pattern, fullName)).toBeTruthy();
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
- expect(arePatternsEqual(pattern, fullName)).toBeTruthy();
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(arePatternsEqual(pattern, digits)).toBeTruthy();
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(arePatternsEqual(pattern, digits)).toBeTruthy();
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(arePatternsEqual(pattern, digits)).toBeTruthy();
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
- expect(arePatternsEqual(pattern, digits)).toBeTruthy();
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(arePatternsEqual(pattern, digits)).toBeTruthy();
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(arePatternsEqual(pattern, digits)).toBeTruthy();
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(arePatternsEqual(pattern, digits)).toBeTruthy();
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
- debugger;
252
- expect(arePatternsEqual(pattern, digits)).toBeTruthy();
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(arePatternsEqual(pattern, digits)).toBeTruthy();
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(arePatternsEqual(name, expectedName)).toBeTruthy();
307
- expect(arePatternsEqual(alias, expectedAlias)).toBeTruthy();
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(arePatternsEqual(patterns["complex-expression"], expected)).toBeTruthy();
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
  });
@@ -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.findAncester(n => n.name === "head") == null);
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
  };
@@ -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(firstIndex: number, lastIndex: number, onPattern: Pattern): void {
132
- this._history.recordErrorAt(firstIndex, lastIndex, onPattern);
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
- if (this._stackTrace.find(t => t.pattern.id === pattern.id && this.index === t.cursorIndex)) {
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