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