clarity-pattern-parser 5.0.0 → 6.0.2

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.
Files changed (61) hide show
  1. package/README.md +328 -38
  2. package/TODO.md +63 -7
  3. package/dist/ast/Node.d.ts +8 -2
  4. package/dist/index.browser.js +520 -205
  5. package/dist/index.browser.js.map +1 -1
  6. package/dist/index.d.ts +6 -1
  7. package/dist/index.esm.js +519 -206
  8. package/dist/index.esm.js.map +1 -1
  9. package/dist/index.js +520 -205
  10. package/dist/index.js.map +1 -1
  11. package/dist/intellisense/AutoComplete.d.ts +34 -0
  12. package/dist/intellisense/Suggestion.d.ts +10 -0
  13. package/dist/intellisense/SuggestionOption.d.ts +4 -0
  14. package/dist/patterns/And.d.ts +8 -7
  15. package/dist/patterns/Cursor.d.ts +6 -4
  16. package/dist/patterns/CursorHistory.d.ts +2 -2
  17. package/dist/patterns/Literal.d.ts +8 -8
  18. package/dist/patterns/Not.d.ts +9 -5
  19. package/dist/patterns/Or.d.ts +8 -5
  20. package/dist/patterns/Pattern.d.ts +8 -4
  21. package/dist/patterns/Reference.d.ts +11 -7
  22. package/dist/patterns/Regex.d.ts +8 -8
  23. package/dist/patterns/Repeat.d.ts +8 -7
  24. package/package.json +1 -1
  25. package/src/ast/Node.test.ts +116 -0
  26. package/src/ast/Node.ts +71 -5
  27. package/src/index.ts +14 -3
  28. package/src/intellisense/AutoComplete.test.ts +168 -23
  29. package/src/intellisense/AutoComplete.ts +102 -21
  30. package/src/intellisense/Suggestion.ts +3 -4
  31. package/src/intellisense/javascript/Javascript.test.ts +86 -62
  32. package/src/intellisense/javascript/{expressionStatement.ts → assignment.ts} +7 -8
  33. package/src/intellisense/javascript/escapedCharacter.ts +0 -1
  34. package/src/intellisense/javascript/exponent.ts +0 -2
  35. package/src/intellisense/javascript/expression.ts +44 -26
  36. package/src/intellisense/javascript/fraction.ts +0 -2
  37. package/src/intellisense/javascript/infixOperator.ts +6 -2
  38. package/src/intellisense/javascript/keywords.ts +3 -0
  39. package/src/intellisense/javascript/objectAccess.ts +9 -0
  40. package/src/intellisense/javascript/objectLiteral.ts +3 -3
  41. package/src/intellisense/javascript/propertyAccess.ts +8 -3
  42. package/src/intellisense/javascript/stringLiteral.ts +16 -8
  43. package/src/patterns/And.test.ts +74 -50
  44. package/src/patterns/And.ts +72 -36
  45. package/src/patterns/Cursor.ts +17 -14
  46. package/src/patterns/CursorHistory.ts +8 -8
  47. package/src/patterns/Literal.test.ts +79 -38
  48. package/src/patterns/Literal.ts +34 -41
  49. package/src/patterns/Not.test.ts +99 -8
  50. package/src/patterns/Not.ts +58 -14
  51. package/src/patterns/Or.test.ts +128 -13
  52. package/src/patterns/Or.ts +46 -13
  53. package/src/patterns/Pattern.ts +8 -4
  54. package/src/patterns/Reference.test.ts +127 -28
  55. package/src/patterns/Reference.ts +62 -32
  56. package/src/patterns/Regex.test.ts +76 -35
  57. package/src/patterns/Regex.ts +35 -43
  58. package/src/patterns/Repeat.test.ts +72 -41
  59. package/src/patterns/Repeat.ts +55 -38
  60. package/src/patterns/getNextPattern.test.ts +0 -39
  61. package/src/patterns/getNextPattern.ts +0 -18
package/dist/index.js CHANGED
@@ -27,6 +27,9 @@ class Node {
27
27
  get children() {
28
28
  return this._children;
29
29
  }
30
+ get hasChildren() {
31
+ return this._children.length > 0;
32
+ }
30
33
  get value() {
31
34
  return this.toString();
32
35
  }
@@ -76,22 +79,54 @@ class Node {
76
79
  }
77
80
  spliceChildren(index, deleteCount, ...items) {
78
81
  const removedItems = this._children.splice(index, deleteCount, ...items);
79
- items.forEach(i => i._parent = this);
80
82
  removedItems.forEach(i => i._parent = null);
83
+ items.forEach(i => i._parent = this);
81
84
  return removedItems;
82
85
  }
83
- find(isMatch) {
84
- return this.findAll(isMatch)[0] || null;
86
+ nextSibling() {
87
+ if (this._parent == null) {
88
+ return null;
89
+ }
90
+ const children = this._parent._children;
91
+ const index = children.indexOf(this);
92
+ if (index > -1 && index < children.length - 1) {
93
+ return children[index + 1];
94
+ }
95
+ return null;
85
96
  }
86
- findAll(isMatch) {
97
+ previousSibling() {
98
+ if (this._parent == null) {
99
+ return null;
100
+ }
101
+ const children = this._parent._children;
102
+ const index = children.indexOf(this);
103
+ if (index > -1 && index > 0) {
104
+ return children[index - 1];
105
+ }
106
+ return null;
107
+ }
108
+ find(predicate) {
109
+ return this.findAll(predicate)[0] || null;
110
+ }
111
+ findAll(predicate) {
87
112
  const matches = [];
88
113
  this.walkUp(n => {
89
- if (isMatch(n)) {
114
+ if (predicate(n)) {
90
115
  matches.push(n);
91
116
  }
92
117
  });
93
118
  return matches;
94
119
  }
120
+ findAncester(predicate) {
121
+ let parent = this._parent;
122
+ while (parent != null) {
123
+ if (predicate(parent)) {
124
+ return parent;
125
+ }
126
+ parent = parent._parent;
127
+ }
128
+ return null;
129
+ }
95
130
  walkUp(callback) {
96
131
  this.children.forEach(c => c.walkUp(callback));
97
132
  callback(this);
@@ -100,6 +135,20 @@ class Node {
100
135
  callback(this);
101
136
  this.children.forEach(c => c.walkDown(callback));
102
137
  }
138
+ flatten() {
139
+ const nodes = [];
140
+ this.walkDown((node) => {
141
+ if (!node.hasChildren) {
142
+ nodes.push(node);
143
+ }
144
+ });
145
+ return nodes;
146
+ }
147
+ reduce() {
148
+ const value = this.toString();
149
+ this.removeAllChildren();
150
+ this._value = value;
151
+ }
103
152
  clone() {
104
153
  return new Node(this._type, this._name, this._firstIndex, this._lastIndex, this._children.map((c) => c.clone()), this._value);
105
154
  }
@@ -144,15 +193,18 @@ class CursorHistory {
144
193
  this._nodes = [];
145
194
  this._errors = [];
146
195
  }
196
+ get isRecording() {
197
+ return this._isRecording;
198
+ }
199
+ get rootMatch() {
200
+ return this._rootMatch;
201
+ }
147
202
  get leafMatch() {
148
203
  return this._leafMatch;
149
204
  }
150
205
  get furthestError() {
151
206
  return this._furthestError;
152
207
  }
153
- get isRecording() {
154
- return this._isRecording;
155
- }
156
208
  get errors() {
157
209
  return this._errors;
158
210
  }
@@ -165,9 +217,6 @@ class CursorHistory {
165
217
  get patterns() {
166
218
  return this._patterns;
167
219
  }
168
- get rootMatch() {
169
- return this._rootMatch;
170
- }
171
220
  recordMatch(pattern, node) {
172
221
  if (this._isRecording) {
173
222
  this._patterns.push(pattern);
@@ -210,17 +259,17 @@ class Cursor {
210
259
  return this._index === 0;
211
260
  }
212
261
  get isOnLast() {
213
- return this._index === this._getLastIndex();
262
+ return this._index === this.getLastIndex();
214
263
  }
215
264
  get isRecording() {
216
265
  return this._history.isRecording;
217
266
  }
218
- get leafMatch() {
219
- return this._history.leafMatch;
220
- }
221
267
  get rootMatch() {
222
268
  return this._history.rootMatch;
223
269
  }
270
+ get leafMatch() {
271
+ return this._history.leafMatch;
272
+ }
224
273
  get furthestError() {
225
274
  return this._history.furthestError;
226
275
  }
@@ -251,14 +300,14 @@ class Cursor {
251
300
  hasNext() {
252
301
  return this._index + 1 < this._length;
253
302
  }
254
- hasPrevious() {
255
- return this._index - 1 >= 0;
256
- }
257
303
  next() {
258
304
  if (this.hasNext()) {
259
305
  this._index++;
260
306
  }
261
307
  }
308
+ hasPrevious() {
309
+ return this._index - 1 >= 0;
310
+ }
262
311
  previous() {
263
312
  if (this.hasPrevious()) {
264
313
  this._index--;
@@ -273,7 +322,10 @@ class Cursor {
273
322
  this._index = 0;
274
323
  }
275
324
  moveToLastChar() {
276
- this._index = this._getLastIndex();
325
+ this._index = this.getLastIndex();
326
+ }
327
+ getLastIndex() {
328
+ return this._length - 1;
277
329
  }
278
330
  getChars(first, last) {
279
331
  return this._text.slice(first, last + 1);
@@ -293,22 +345,6 @@ class Cursor {
293
345
  stopRecording() {
294
346
  this._history.stopRecording();
295
347
  }
296
- _getLastIndex() {
297
- return this._length - 1;
298
- }
299
- }
300
-
301
- function getNextPattern(pattern) {
302
- const parent = pattern.parent;
303
- if (parent == null) {
304
- return null;
305
- }
306
- const patternIndex = parent.children.indexOf(pattern);
307
- const nextPattern = parent.children[patternIndex + 1] || null;
308
- if (nextPattern == null) {
309
- return parent.getNextPattern();
310
- }
311
- return nextPattern;
312
348
  }
313
349
 
314
350
  class Regex {
@@ -335,8 +371,6 @@ class Regex {
335
371
  this._cursor = null;
336
372
  this._substring = "";
337
373
  this._tokens = [];
338
- this._hasContextualTokenAggregation = false;
339
- this._isRetrievingContextualTokens = false;
340
374
  this._type = "regex";
341
375
  this._name = name;
342
376
  this._isOptional = isOptional;
@@ -356,11 +390,16 @@ class Regex {
356
390
  throw new Error("Invalid Arguments: The regex string cannot end with a '$' because it is expected to be in the middle of a string.");
357
391
  }
358
392
  }
359
- parseText(text) {
393
+ test(text) {
394
+ const cursor = new Cursor(text);
395
+ const ast = this.parse(cursor);
396
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
397
+ }
398
+ exec(text) {
360
399
  const cursor = new Cursor(text);
361
400
  const ast = this.parse(cursor);
362
401
  return {
363
- ast,
402
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
364
403
  cursor
365
404
  };
366
405
  }
@@ -387,7 +426,7 @@ class Regex {
387
426
  processResult(cursor, result) {
388
427
  const currentIndex = cursor.index;
389
428
  const newIndex = currentIndex + result[0].length - 1;
390
- this._node = new Node("regex", this._name, currentIndex, newIndex, [], result[0]);
429
+ this._node = new Node("regex", this._name, currentIndex, newIndex, undefined, result[0]);
391
430
  cursor.moveTo(newIndex);
392
431
  cursor.recordMatch(this, this._node);
393
432
  }
@@ -400,47 +439,38 @@ class Regex {
400
439
  clone(name = this._name, isOptional = this._isOptional) {
401
440
  const pattern = new Regex(name, this._originalRegexString, isOptional);
402
441
  pattern._tokens = this._tokens.slice();
403
- pattern._hasContextualTokenAggregation =
404
- this._hasContextualTokenAggregation;
405
442
  return pattern;
406
443
  }
407
444
  getTokens() {
408
- const parent = this._parent;
409
- if (this._hasContextualTokenAggregation &&
410
- parent != null &&
411
- !this._isRetrievingContextualTokens) {
412
- this._isRetrievingContextualTokens = true;
413
- const tokens = this._tokens;
414
- const aggregateTokens = [];
415
- const nextTokens = parent.getNextTokens(this);
416
- for (let nextToken of nextTokens) {
417
- for (let token of tokens) {
418
- aggregateTokens.push(token + nextToken);
419
- }
420
- }
421
- this._isRetrievingContextualTokens = false;
422
- return aggregateTokens;
423
- }
424
445
  return this._tokens;
425
446
  }
426
- getNextTokens(_reference) {
447
+ getTokensAfter(_childReference) {
427
448
  return [];
428
449
  }
429
- getNextPattern() {
430
- return getNextPattern(this);
450
+ getNextTokens() {
451
+ if (this.parent == null) {
452
+ return [];
453
+ }
454
+ return this.parent.getTokensAfter(this);
455
+ }
456
+ getPatterns() {
457
+ return [this];
431
458
  }
432
- findPattern(_isMatch) {
459
+ getPatternsAfter(_childReference) {
460
+ return [];
461
+ }
462
+ getNextPatterns() {
463
+ if (this.parent == null) {
464
+ return [];
465
+ }
466
+ return this.parent.getPatternsAfter(this);
467
+ }
468
+ findPattern(_predicate) {
433
469
  return null;
434
470
  }
435
471
  setTokens(tokens) {
436
472
  this._tokens = tokens;
437
473
  }
438
- enableContextualTokenAggregation() {
439
- this._hasContextualTokenAggregation = true;
440
- }
441
- disableContextualTokenAggregation() {
442
- this._hasContextualTokenAggregation = false;
443
- }
444
474
  }
445
475
 
446
476
  function clonePatterns(patterns, isOptional) {
@@ -510,7 +540,6 @@ class And {
510
540
  this._parent = null;
511
541
  this._children = children;
512
542
  this._firstIndex = -1;
513
- this._shouldReduceAst = false;
514
543
  this._nodes = [];
515
544
  }
516
545
  _assignChildrenToParent(children) {
@@ -518,11 +547,16 @@ class And {
518
547
  child.parent = this;
519
548
  }
520
549
  }
521
- parseText(text) {
550
+ test(text) {
551
+ const cursor = new Cursor(text);
552
+ const ast = this.parse(cursor);
553
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
554
+ }
555
+ exec(text) {
522
556
  const cursor = new Cursor(text);
523
557
  const ast = this.parse(cursor);
524
558
  return {
525
- ast,
559
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
526
560
  cursor
527
561
  };
528
562
  }
@@ -556,34 +590,43 @@ class And {
556
590
  if (hasMorePatterns) {
557
591
  if (hadMatch) {
558
592
  if (cursor.hasNext()) {
593
+ // We had a match. Increment the cursor and use the next pattern.
559
594
  cursor.next();
560
595
  continue;
561
596
  }
562
597
  else {
598
+ // We are at the end of the text, it may still be valid, if all the
599
+ // following patterns are optional.
563
600
  if (this.areRemainingPatternsOptional(i)) {
564
601
  passed = true;
565
602
  break;
566
603
  }
604
+ // We didn't finish the parsing sequence.
567
605
  cursor.recordErrorAt(cursor.index + 1, this);
568
606
  break;
569
607
  }
570
608
  }
571
609
  else {
610
+ // An optional pattern did not matched, try from the same spot on the next
611
+ // pattern.
572
612
  cursor.moveTo(runningCursorIndex);
573
613
  continue;
574
614
  }
575
615
  }
576
616
  else {
617
+ // If we don't have any results from what we parsed then record error.
577
618
  const lastNode = this.getLastValidNode();
578
619
  if (lastNode === null) {
579
620
  cursor.recordErrorAt(cursor.index, this);
580
621
  break;
581
622
  }
623
+ // The sequence was parsed fully.
582
624
  passed = true;
583
625
  break;
584
626
  }
585
627
  }
586
628
  else {
629
+ // The pattern failed.
587
630
  cursor.moveTo(this._firstIndex);
588
631
  break;
589
632
  }
@@ -611,18 +654,9 @@ class And {
611
654
  createNode(cursor) {
612
655
  const children = filterOutNull(this._nodes);
613
656
  const lastIndex = children[children.length - 1].lastIndex;
614
- const value = cursor.getChars(this._firstIndex, lastIndex);
657
+ cursor.getChars(this._firstIndex, lastIndex);
615
658
  cursor.moveTo(lastIndex);
616
- if (this._shouldReduceAst) {
617
- children.length = 0;
618
- }
619
- return new Node("and", this._name, this._firstIndex, lastIndex, children, this._shouldReduceAst ? value : undefined);
620
- }
621
- enableAstReduction() {
622
- this._shouldReduceAst = true;
623
- }
624
- disableAstReduction() {
625
- this._shouldReduceAst = false;
659
+ return new Node("and", this._name, this._firstIndex, lastIndex, children);
626
660
  }
627
661
  getTokens() {
628
662
  const tokens = [];
@@ -634,13 +668,35 @@ class And {
634
668
  }
635
669
  return tokens;
636
670
  }
637
- getNextTokens(lastMatched) {
671
+ getTokensAfter(childReference) {
672
+ const patterns = this.getPatternsAfter(childReference);
673
+ const tokens = [];
674
+ patterns.forEach(p => tokens.push(...p.getTokens()));
675
+ return tokens;
676
+ }
677
+ getNextTokens() {
678
+ if (this.parent == null) {
679
+ return [];
680
+ }
681
+ return this.parent.getTokensAfter(this);
682
+ }
683
+ getPatterns() {
684
+ const patterns = [];
685
+ for (const pattern of this._children) {
686
+ patterns.push(...pattern.getPatterns());
687
+ if (!pattern.isOptional) {
688
+ break;
689
+ }
690
+ }
691
+ return patterns;
692
+ }
693
+ getPatternsAfter(childReference) {
638
694
  let nextSibling = null;
639
695
  let nextSiblingIndex = -1;
640
696
  let index = -1;
641
- const tokens = [];
697
+ const patterns = [];
642
698
  for (let i = 0; i < this._children.length; i++) {
643
- if (this._children[i] === lastMatched) {
699
+ if (this._children[i] === childReference) {
644
700
  if (i + 1 < this._children.length) {
645
701
  nextSibling = this._children[i + 1];
646
702
  }
@@ -649,39 +705,44 @@ class And {
649
705
  break;
650
706
  }
651
707
  }
708
+ // The child reference isn't one of the child patterns.
652
709
  if (index === -1) {
653
710
  return [];
654
711
  }
712
+ // The reference pattern is the last child. So ask the parent for the next pattern.
655
713
  if (nextSiblingIndex === this._children.length && this._parent !== null) {
656
- return this._parent.getNextTokens(this);
714
+ return this._parent.getPatternsAfter(this);
657
715
  }
716
+ // Next pattern isn't optional so send it back as the next patterns.
658
717
  if (nextSibling !== null && !nextSibling.isOptional) {
659
- return nextSibling.getTokens();
718
+ return [nextSibling];
660
719
  }
720
+ // Send back as many optional patterns as possible.
661
721
  if (nextSibling !== null && nextSibling.isOptional) {
662
722
  for (let i = nextSiblingIndex; i < this._children.length; i++) {
663
723
  const child = this._children[i];
664
- tokens.push(...child.getTokens());
724
+ patterns.push(child);
665
725
  if (!child.isOptional) {
666
726
  break;
667
727
  }
668
728
  if (i === this._children.length - 1 && this._parent !== null) {
669
- tokens.push(...this._parent.getNextTokens(this));
729
+ patterns.push(...this._parent.getPatternsAfter(this));
670
730
  }
671
731
  }
672
732
  }
673
- return tokens;
733
+ return patterns;
674
734
  }
675
- getNextPattern() {
676
- return getNextPattern(this);
735
+ getNextPatterns() {
736
+ if (this.parent == null) {
737
+ return [];
738
+ }
739
+ return this.parent.getPatternsAfter(this);
677
740
  }
678
- findPattern(isMatch) {
679
- return findPattern(this, isMatch);
741
+ findPattern(predicate) {
742
+ return findPattern(this, predicate);
680
743
  }
681
744
  clone(name = this._name, isOptional = this._isOptional) {
682
- const and = new And(name, this._children, isOptional);
683
- and._shouldReduceAst = this._shouldReduceAst;
684
- return and;
745
+ return new And(name, this._children, isOptional);
685
746
  }
686
747
  }
687
748
 
@@ -716,14 +777,17 @@ class Literal {
716
777
  this._parent = null;
717
778
  this._firstIndex = 0;
718
779
  this._lastIndex = 0;
719
- this._hasContextualTokenAggregation = false;
720
- this._isRetrievingContextualTokens = false;
721
780
  }
722
- parseText(text) {
781
+ test(text) {
782
+ const cursor = new Cursor(text);
783
+ const ast = this.parse(cursor);
784
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
785
+ }
786
+ exec(text) {
723
787
  const cursor = new Cursor(text);
724
788
  const ast = this.parse(cursor);
725
789
  return {
726
- ast,
790
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
727
791
  cursor
728
792
  };
729
793
  }
@@ -766,45 +830,38 @@ class Literal {
766
830
  return passed;
767
831
  }
768
832
  _createNode() {
769
- return new Node("literal", this._name, this._firstIndex, this._lastIndex, [], this._literal);
833
+ return new Node("literal", this._name, this._firstIndex, this._lastIndex, undefined, this._literal);
770
834
  }
771
835
  clone(name = this._name, isOptional = this._isOptional) {
772
836
  const clone = new Literal(name, this._literal, isOptional);
773
- clone._hasContextualTokenAggregation = this._hasContextualTokenAggregation;
774
837
  return clone;
775
838
  }
776
839
  getTokens() {
777
- const parent = this._parent;
778
- if (this._hasContextualTokenAggregation &&
779
- parent != null &&
780
- !this._isRetrievingContextualTokens) {
781
- this._isRetrievingContextualTokens = true;
782
- const aggregateTokens = [];
783
- const nextTokens = parent.getNextTokens(this);
784
- for (const nextToken of nextTokens) {
785
- aggregateTokens.push(this._literal + nextToken);
786
- }
787
- this._isRetrievingContextualTokens = false;
788
- return aggregateTokens;
789
- }
790
- else {
791
- return [this._literal];
792
- }
840
+ return [this._literal];
793
841
  }
794
- getNextTokens(_lastMatched) {
842
+ getTokensAfter(_lastMatched) {
795
843
  return [];
796
844
  }
797
- getNextPattern() {
798
- return getNextPattern(this);
845
+ getNextTokens() {
846
+ if (this.parent == null) {
847
+ return [];
848
+ }
849
+ return this.parent.getTokensAfter(this);
799
850
  }
800
- findPattern(_isMatch) {
801
- return null;
851
+ getPatterns() {
852
+ return [this];
853
+ }
854
+ getPatternsAfter() {
855
+ return [];
802
856
  }
803
- enableContextualTokenAggregation() {
804
- this._hasContextualTokenAggregation = true;
857
+ getNextPatterns() {
858
+ if (this.parent == null) {
859
+ return [];
860
+ }
861
+ return this.parent.getPatternsAfter(this);
805
862
  }
806
- disableContextualTokenAggregation() {
807
- this._hasContextualTokenAggregation = false;
863
+ findPattern(_predicate) {
864
+ return null;
808
865
  }
809
866
  }
810
867
 
@@ -815,9 +872,6 @@ class Not {
815
872
  get name() {
816
873
  return this._name;
817
874
  }
818
- get isOptional() {
819
- return false;
820
- }
821
875
  get parent() {
822
876
  return this._parent;
823
877
  }
@@ -827,6 +881,9 @@ class Not {
827
881
  get children() {
828
882
  return this._children;
829
883
  }
884
+ get isOptional() {
885
+ return false;
886
+ }
830
887
  constructor(name, pattern) {
831
888
  this._type = "not";
832
889
  this._name = name;
@@ -834,7 +891,12 @@ class Not {
834
891
  this._children = [pattern.clone(pattern.name, false)];
835
892
  this._children[0].parent = this;
836
893
  }
837
- parseText(text) {
894
+ test(text) {
895
+ const cursor = new Cursor(text);
896
+ this.parse(cursor);
897
+ return !cursor.hasError;
898
+ }
899
+ exec(text) {
838
900
  const cursor = new Cursor(text);
839
901
  const ast = this.parse(cursor);
840
902
  return {
@@ -860,17 +922,44 @@ class Not {
860
922
  const not = new Not(name, this._children[0]);
861
923
  return not;
862
924
  }
863
- getNextPattern() {
864
- return getNextPattern(this);
865
- }
866
925
  getTokens() {
926
+ const parent = this._parent;
927
+ if (parent != null) {
928
+ return parent.getTokensAfter(this);
929
+ }
930
+ return [];
931
+ }
932
+ getTokensAfter(_childReference) {
933
+ const parent = this._parent;
934
+ if (parent != null) {
935
+ return parent.getTokensAfter(this);
936
+ }
867
937
  return [];
868
938
  }
869
- getNextTokens(_lastMatched) {
939
+ getNextTokens() {
940
+ if (this.parent == null) {
941
+ return [];
942
+ }
943
+ return this.parent.getTokensAfter(this);
944
+ }
945
+ getPatterns() {
946
+ return [...this.getNextPatterns().map(p => p.getPatterns()).flat()];
947
+ }
948
+ getPatternsAfter(_childReference) {
949
+ const parent = this._parent;
950
+ if (parent != null) {
951
+ return parent.getPatternsAfter(this);
952
+ }
870
953
  return [];
871
954
  }
872
- findPattern(isMatch) {
873
- return isMatch(this._children[0]) ? this._children[0] : null;
955
+ getNextPatterns() {
956
+ if (this.parent == null) {
957
+ return [];
958
+ }
959
+ return this.parent.getPatternsAfter(this);
960
+ }
961
+ findPattern(predicate) {
962
+ return predicate(this._children[0]) ? this._children[0] : null;
874
963
  }
875
964
  }
876
965
 
@@ -904,7 +993,6 @@ class Or {
904
993
  this._parent = null;
905
994
  this._children = children;
906
995
  this._isOptional = isOptional;
907
- this._node = null;
908
996
  this._firstIndex = 0;
909
997
  }
910
998
  _assignChildrenToParent(children) {
@@ -912,17 +1000,21 @@ class Or {
912
1000
  child.parent = this;
913
1001
  }
914
1002
  }
915
- parseText(text) {
1003
+ test(text) {
1004
+ const cursor = new Cursor(text);
1005
+ const ast = this.parse(cursor);
1006
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
1007
+ }
1008
+ exec(text) {
916
1009
  const cursor = new Cursor(text);
917
1010
  const ast = this.parse(cursor);
918
1011
  return {
919
- ast,
1012
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
920
1013
  cursor
921
1014
  };
922
1015
  }
923
1016
  parse(cursor) {
924
1017
  this._firstIndex = cursor.index;
925
- this._node = null;
926
1018
  const node = this._tryToParse(cursor);
927
1019
  if (node != null) {
928
1020
  cursor.resolveError();
@@ -954,17 +1046,39 @@ class Or {
954
1046
  }
955
1047
  return tokens;
956
1048
  }
957
- getNextTokens(_lastMatched) {
1049
+ getTokensAfter(_childReference) {
1050
+ if (this._parent === null) {
1051
+ return [];
1052
+ }
1053
+ return this._parent.getTokensAfter(this);
1054
+ }
1055
+ getNextTokens() {
1056
+ if (this._parent == null) {
1057
+ return [];
1058
+ }
1059
+ return this._parent.getTokensAfter(this);
1060
+ }
1061
+ getPatterns() {
1062
+ const patterns = [];
1063
+ for (const pattern of this._children) {
1064
+ patterns.push(...pattern.getPatterns());
1065
+ }
1066
+ return patterns;
1067
+ }
1068
+ getPatternsAfter(_childReference) {
958
1069
  if (this._parent === null) {
959
1070
  return [];
960
1071
  }
961
- return this._parent.getNextTokens(this);
1072
+ return this._parent.getPatternsAfter(this);
962
1073
  }
963
- getNextPattern() {
964
- return getNextPattern(this);
1074
+ getNextPatterns() {
1075
+ if (this.parent == null) {
1076
+ return [];
1077
+ }
1078
+ return this.parent.getPatternsAfter(this);
965
1079
  }
966
- findPattern(isMatch) {
967
- return findPattern(this, isMatch);
1080
+ findPattern(predicate) {
1081
+ return findPattern(this, predicate);
968
1082
  }
969
1083
  clone(name = this._name, isOptional = this._isOptional) {
970
1084
  const or = new Or(name, this._children, isOptional);
@@ -1003,7 +1117,6 @@ class Repeat {
1003
1117
  this._pattern = children[0];
1004
1118
  this._divider = children[1];
1005
1119
  this._firstIndex = -1;
1006
- this._shouldReduceAst = false;
1007
1120
  this._nodes = [];
1008
1121
  }
1009
1122
  _assignChildrenToParent(children) {
@@ -1011,11 +1124,16 @@ class Repeat {
1011
1124
  child.parent = this;
1012
1125
  }
1013
1126
  }
1014
- parseText(text) {
1127
+ test(text) {
1128
+ const cursor = new Cursor(text);
1129
+ const ast = this.parse(cursor);
1130
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
1131
+ }
1132
+ exec(text) {
1015
1133
  const cursor = new Cursor(text);
1016
1134
  const ast = this.parse(cursor);
1017
1135
  return {
1018
- ast,
1136
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
1019
1137
  cursor
1020
1138
  };
1021
1139
  }
@@ -1026,7 +1144,7 @@ class Repeat {
1026
1144
  if (passed) {
1027
1145
  cursor.resolveError();
1028
1146
  const node = this.createNode(cursor);
1029
- if (node) {
1147
+ if (node != null) {
1030
1148
  cursor.recordMatch(this, node);
1031
1149
  }
1032
1150
  return node;
@@ -1045,7 +1163,7 @@ class Repeat {
1045
1163
  const repeatedNode = this._pattern.parse(cursor);
1046
1164
  if (cursor.hasError) {
1047
1165
  const lastValidNode = this.getLastValidNode();
1048
- if (lastValidNode) {
1166
+ if (lastValidNode != null) {
1049
1167
  passed = true;
1050
1168
  }
1051
1169
  else {
@@ -1062,13 +1180,13 @@ class Repeat {
1062
1180
  break;
1063
1181
  }
1064
1182
  cursor.next();
1065
- if (this._divider) {
1183
+ if (this._divider != null) {
1066
1184
  const dividerNode = this._divider.parse(cursor);
1067
1185
  if (cursor.hasError) {
1068
1186
  passed = true;
1069
1187
  break;
1070
1188
  }
1071
- else if (dividerNode) {
1189
+ else if (dividerNode != null) {
1072
1190
  this._nodes.push(dividerNode);
1073
1191
  if (!cursor.hasNext()) {
1074
1192
  passed = true;
@@ -1097,12 +1215,9 @@ class Repeat {
1097
1215
  }
1098
1216
  }
1099
1217
  const lastIndex = children[children.length - 1].lastIndex;
1100
- const value = cursor.getChars(this._firstIndex, lastIndex);
1218
+ cursor.getChars(this._firstIndex, lastIndex);
1101
1219
  cursor.moveTo(lastIndex);
1102
- if (this._shouldReduceAst) {
1103
- children = [];
1104
- }
1105
- return new Node("repeat", this._name, this._firstIndex, lastIndex, children, this._shouldReduceAst ? value : undefined);
1220
+ return new Node("repeat", this._name, this._firstIndex, lastIndex, children, undefined);
1106
1221
  }
1107
1222
  getLastValidNode() {
1108
1223
  const nodes = this._nodes.filter((node) => node !== null);
@@ -1111,51 +1226,64 @@ class Repeat {
1111
1226
  }
1112
1227
  return nodes[nodes.length - 1];
1113
1228
  }
1114
- enableAstReduction() {
1115
- this._shouldReduceAst = true;
1116
- }
1117
- disableAstReduction() {
1118
- this._shouldReduceAst = false;
1119
- }
1120
1229
  getTokens() {
1121
1230
  return this._pattern.getTokens();
1122
1231
  }
1123
- getNextTokens(lastMatched) {
1124
- let index = -1;
1232
+ getTokensAfter(childReference) {
1233
+ const patterns = this.getPatternsAfter(childReference);
1125
1234
  const tokens = [];
1235
+ patterns.forEach(p => tokens.push(...p.getTokens()));
1236
+ return tokens;
1237
+ }
1238
+ getNextTokens() {
1239
+ if (this.parent == null) {
1240
+ return [];
1241
+ }
1242
+ return this.parent.getTokensAfter(this);
1243
+ }
1244
+ getPatterns() {
1245
+ return this._pattern.getPatterns();
1246
+ }
1247
+ getPatternsAfter(childReference) {
1248
+ let index = -1;
1249
+ const patterns = [];
1126
1250
  for (let i = 0; i < this._children.length; i++) {
1127
- if (this._children[i] === lastMatched) {
1251
+ if (this._children[i] === childReference) {
1128
1252
  index = i;
1129
1253
  }
1130
1254
  }
1255
+ // If the last match isn't a child of this pattern.
1131
1256
  if (index === -1) {
1132
1257
  return [];
1133
1258
  }
1259
+ // If the last match was the repeated patterns, then suggest the divider.
1134
1260
  if (index === 0 && this._divider) {
1135
- tokens.push(...this._children[1].getTokens());
1261
+ patterns.push(this._children[1]);
1136
1262
  if (this._parent) {
1137
- tokens.push(...this._parent.getNextTokens(this));
1263
+ patterns.push(...this._parent.getPatternsAfter(this));
1138
1264
  }
1139
1265
  }
1266
+ // Suggest the pattern because the divider was the last match.
1140
1267
  if (index === 1) {
1141
- tokens.push(...this._children[0].getTokens());
1268
+ patterns.push(this._children[0]);
1142
1269
  }
1143
1270
  if (index === 0 && !this._divider && this._parent) {
1144
- tokens.push(...this._children[0].getTokens());
1145
- tokens.push(...this._parent.getNextTokens(this));
1271
+ patterns.push(this._children[0]);
1272
+ patterns.push(...this._parent.getPatternsAfter(this));
1146
1273
  }
1147
- return tokens;
1274
+ return patterns;
1148
1275
  }
1149
- getNextPattern() {
1150
- return getNextPattern(this);
1276
+ getNextPatterns() {
1277
+ if (this.parent == null) {
1278
+ return [];
1279
+ }
1280
+ return this.parent.getPatternsAfter(this);
1151
1281
  }
1152
- findPattern(isMatch) {
1153
- return findPattern(this, isMatch);
1282
+ findPattern(predicate) {
1283
+ return findPattern(this, predicate);
1154
1284
  }
1155
1285
  clone(name = this._name, isOptional = this._isOptional) {
1156
- const repeat = new Repeat(name, this._pattern, this._divider, isOptional);
1157
- repeat._shouldReduceAst = this._shouldReduceAst;
1158
- return repeat;
1286
+ return new Repeat(name, this._pattern, this._divider, isOptional);
1159
1287
  }
1160
1288
  }
1161
1289
 
@@ -1166,9 +1294,6 @@ class Reference {
1166
1294
  get name() {
1167
1295
  return this._name;
1168
1296
  }
1169
- get isOptional() {
1170
- return this._isOptional;
1171
- }
1172
1297
  get parent() {
1173
1298
  return this._parent;
1174
1299
  }
@@ -1178,6 +1303,9 @@ class Reference {
1178
1303
  get children() {
1179
1304
  return this._children;
1180
1305
  }
1306
+ get isOptional() {
1307
+ return this._isOptional;
1308
+ }
1181
1309
  constructor(name, isOptional = false) {
1182
1310
  this._type = "reference";
1183
1311
  this._name = name;
@@ -1186,35 +1314,22 @@ class Reference {
1186
1314
  this._pattern = null;
1187
1315
  this._children = [];
1188
1316
  }
1189
- parseText(text) {
1317
+ test(text) {
1318
+ const cursor = new Cursor(text);
1319
+ const ast = this.parse(cursor);
1320
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
1321
+ }
1322
+ exec(text) {
1190
1323
  const cursor = new Cursor(text);
1191
1324
  const ast = this.parse(cursor);
1192
1325
  return {
1193
- ast,
1326
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
1194
1327
  cursor
1195
1328
  };
1196
1329
  }
1197
1330
  parse(cursor) {
1198
1331
  return this._getPatternSafely().parse(cursor);
1199
1332
  }
1200
- clone(name = this._name, isOptional = this._isOptional) {
1201
- return new Reference(name, isOptional);
1202
- }
1203
- getTokens() {
1204
- return this._getPatternSafely().getTokens();
1205
- }
1206
- getNextTokens(_lastMatched) {
1207
- if (this.parent == null) {
1208
- return [];
1209
- }
1210
- return this.parent.getNextTokens(this);
1211
- }
1212
- getNextPattern() {
1213
- return getNextPattern(this);
1214
- }
1215
- findPattern(_isMatch) {
1216
- return null;
1217
- }
1218
1333
  _getPatternSafely() {
1219
1334
  if (this._pattern === null) {
1220
1335
  const pattern = this._findPattern();
@@ -1247,10 +1362,210 @@ class Reference {
1247
1362
  }
1248
1363
  return node;
1249
1364
  }
1365
+ getTokens() {
1366
+ return this._getPatternSafely().getTokens();
1367
+ }
1368
+ getTokensAfter(_lastMatched) {
1369
+ if (this._parent == null) {
1370
+ return [];
1371
+ }
1372
+ return this._parent.getTokensAfter(this);
1373
+ }
1374
+ getNextTokens() {
1375
+ if (this.parent == null) {
1376
+ return [];
1377
+ }
1378
+ return this.parent.getTokensAfter(this);
1379
+ }
1380
+ getPatterns() {
1381
+ return this._getPatternSafely().getPatterns();
1382
+ }
1383
+ getPatternsAfter(_childReference) {
1384
+ if (this._parent == null) {
1385
+ return [];
1386
+ }
1387
+ return this._parent.getPatternsAfter(this);
1388
+ }
1389
+ getNextPatterns() {
1390
+ if (this.parent == null) {
1391
+ return [];
1392
+ }
1393
+ return this.parent.getPatternsAfter(this);
1394
+ }
1395
+ findPattern(_predicate) {
1396
+ return null;
1397
+ }
1398
+ clone(name = this._name, isOptional = this._isOptional) {
1399
+ return new Reference(name, isOptional);
1400
+ }
1401
+ }
1402
+
1403
+ const defaultOptions = { greedyPatternNames: [], customTokens: {} };
1404
+ class AutoComplete {
1405
+ constructor(pattern, options = defaultOptions) {
1406
+ this._pattern = pattern;
1407
+ this._options = options;
1408
+ this._text = "";
1409
+ }
1410
+ /**
1411
+ * @deprecated Use suggestFor instead.
1412
+ * @param text The text to suggest for.
1413
+ */
1414
+ suggest(text) {
1415
+ return this.suggestFor(text);
1416
+ }
1417
+ suggestFor(text) {
1418
+ if (text.length === 0) {
1419
+ return {
1420
+ isComplete: false,
1421
+ options: this._createSuggestionsFromRoot(),
1422
+ errorAtIndex: 0,
1423
+ cursor: null,
1424
+ ast: null
1425
+ };
1426
+ }
1427
+ this._text = text;
1428
+ this._cursor = new Cursor(text);
1429
+ const ast = this._pattern.parse(this._cursor);
1430
+ const leafPattern = this._cursor.leafMatch.pattern;
1431
+ const isComplete = (ast === null || ast === void 0 ? void 0 : ast.value) === text;
1432
+ const options = this._createSuggestionsFromTokens();
1433
+ [this._pattern];
1434
+ let errorAtIndex = null;
1435
+ if (leafPattern != null) {
1436
+ leafPattern.getNextPatterns();
1437
+ }
1438
+ if (this._cursor.hasError && this._cursor.furthestError != null) {
1439
+ errorAtIndex = this._cursor.furthestError.index;
1440
+ errorAtIndex = options.reduce((errorAtIndex, option) => Math.max(errorAtIndex, option.startIndex), errorAtIndex);
1441
+ }
1442
+ return {
1443
+ isComplete: isComplete,
1444
+ options: options,
1445
+ errorAtIndex,
1446
+ cursor: this._cursor,
1447
+ ast,
1448
+ };
1449
+ }
1450
+ _createSuggestionsFromRoot() {
1451
+ const suggestions = [];
1452
+ const tokens = this._pattern.getTokens();
1453
+ for (const token of tokens) {
1454
+ suggestions.push(this._createSuggestion("", token));
1455
+ }
1456
+ return suggestions;
1457
+ }
1458
+ _createSuggestionsFromTokens() {
1459
+ const leafMatch = this._cursor.leafMatch;
1460
+ if (!leafMatch.pattern) {
1461
+ return this._createSuggestions(-1, this._getTokensForPattern(this._pattern));
1462
+ }
1463
+ const leafPattern = leafMatch.pattern;
1464
+ const parent = leafMatch.pattern.parent;
1465
+ if (parent !== null && leafMatch.node != null) {
1466
+ const patterns = leafPattern.getNextPatterns();
1467
+ const tokens = patterns.reduce((acc, pattern) => {
1468
+ acc.push(...this._getTokensForPattern(pattern));
1469
+ return acc;
1470
+ }, []);
1471
+ return this._createSuggestions(leafMatch.node.lastIndex, tokens);
1472
+ }
1473
+ else {
1474
+ return [];
1475
+ }
1476
+ }
1477
+ _getTokensForPattern(pattern) {
1478
+ const augmentedTokens = this._getAugmentedTokens(pattern);
1479
+ if (this._options.greedyPatternNames != null && this._options.greedyPatternNames.includes(pattern.name)) {
1480
+ const nextPatterns = pattern.getNextPatterns();
1481
+ const tokens = [];
1482
+ const nextPatternTokens = nextPatterns.reduce((acc, pattern) => {
1483
+ acc.push(...this._getTokensForPattern(pattern));
1484
+ return acc;
1485
+ }, []);
1486
+ for (let token of augmentedTokens) {
1487
+ for (let nextPatternToken of nextPatternTokens) {
1488
+ tokens.push(token + nextPatternToken);
1489
+ }
1490
+ }
1491
+ return tokens;
1492
+ }
1493
+ else {
1494
+ return augmentedTokens;
1495
+ }
1496
+ }
1497
+ _getAugmentedTokens(pattern) {
1498
+ const customTokensMap = this._options.customTokens || {};
1499
+ const leafPatterns = pattern.getPatterns();
1500
+ const tokens = customTokensMap[pattern.name] || [];
1501
+ leafPatterns.forEach(p => {
1502
+ const augmentedTokens = customTokensMap[p.name] || [];
1503
+ tokens.push(...p.getTokens(), ...augmentedTokens);
1504
+ });
1505
+ return tokens;
1506
+ }
1507
+ _createSuggestions(lastIndex, tokens) {
1508
+ let substring = lastIndex === -1 ? "" : this._cursor.getChars(0, lastIndex);
1509
+ const suggestionStrings = [];
1510
+ const options = [];
1511
+ for (const token of tokens) {
1512
+ const suggestion = substring + token;
1513
+ const startsWith = suggestion.startsWith(substring);
1514
+ const alreadyExist = suggestionStrings.includes(suggestion);
1515
+ const isSameAsText = suggestion === this._text;
1516
+ if (startsWith && !alreadyExist && !isSameAsText) {
1517
+ suggestionStrings.push(suggestion);
1518
+ options.push(this._createSuggestion(this._cursor.text, suggestion));
1519
+ }
1520
+ }
1521
+ const reducedOptions = getFurthestOptions(options);
1522
+ reducedOptions.sort((a, b) => a.text.localeCompare(b.text));
1523
+ return reducedOptions;
1524
+ }
1525
+ _createSuggestion(fullText, suggestion) {
1526
+ const furthestMatch = findMatchIndex(suggestion, fullText);
1527
+ const text = suggestion.slice(furthestMatch);
1528
+ return {
1529
+ text: text,
1530
+ startIndex: furthestMatch,
1531
+ };
1532
+ }
1533
+ }
1534
+ function findMatchIndex(str1, str2) {
1535
+ let matchCount = 0;
1536
+ let minLength = str1.length;
1537
+ if (str2.length < minLength) {
1538
+ minLength = str2.length;
1539
+ }
1540
+ for (let i = 0; i < minLength; i++) {
1541
+ if (str1[i] === str2[i]) {
1542
+ matchCount++;
1543
+ }
1544
+ else {
1545
+ break;
1546
+ }
1547
+ }
1548
+ return matchCount;
1549
+ }
1550
+ function getFurthestOptions(options) {
1551
+ let furthestOptions = [];
1552
+ let furthestIndex = -1;
1553
+ for (const option of options) {
1554
+ if (option.startIndex > furthestIndex) {
1555
+ furthestIndex = option.startIndex;
1556
+ furthestOptions = [];
1557
+ }
1558
+ if (option.startIndex === furthestIndex) {
1559
+ furthestOptions.push(option);
1560
+ }
1561
+ }
1562
+ return furthestOptions;
1250
1563
  }
1251
1564
 
1252
1565
  exports.And = And;
1566
+ exports.AutoComplete = AutoComplete;
1253
1567
  exports.Cursor = Cursor;
1568
+ exports.CursorHistory = CursorHistory;
1254
1569
  exports.Literal = Literal;
1255
1570
  exports.Node = Node;
1256
1571
  exports.Not = Not;