clarity-pattern-parser 5.0.0 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +328 -38
  2. package/TODO.md +55 -1
  3. package/dist/ast/Node.d.ts +8 -2
  4. package/dist/index.browser.js +470 -205
  5. package/dist/index.browser.js.map +1 -1
  6. package/dist/index.d.ts +6 -1
  7. package/dist/index.esm.js +469 -206
  8. package/dist/index.esm.js.map +1 -1
  9. package/dist/index.js +470 -205
  10. package/dist/index.js.map +1 -1
  11. package/dist/intellisense/AutoComplete.d.ts +28 -0
  12. package/dist/intellisense/Suggestion.d.ts +11 -0
  13. package/dist/intellisense/SuggestionOption.d.ts +4 -0
  14. package/dist/patterns/And.d.ts +7 -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 +7 -8
  18. package/dist/patterns/Not.d.ts +8 -5
  19. package/dist/patterns/Or.d.ts +7 -5
  20. package/dist/patterns/Pattern.d.ts +7 -4
  21. package/dist/patterns/Reference.d.ts +10 -7
  22. package/dist/patterns/Regex.d.ts +7 -8
  23. package/dist/patterns/Repeat.d.ts +7 -7
  24. package/package.json +1 -1
  25. package/src/ast/Node.test.ts +110 -0
  26. package/src/ast/Node.ts +71 -5
  27. package/src/index.ts +14 -3
  28. package/src/intellisense/AutoComplete.test.ts +90 -12
  29. package/src/intellisense/AutoComplete.ts +66 -12
  30. package/src/intellisense/Suggestion.ts +3 -4
  31. package/src/intellisense/javascript/Javascript.test.ts +56 -56
  32. package/src/intellisense/javascript/escapedCharacter.ts +0 -1
  33. package/src/intellisense/javascript/exponent.ts +0 -2
  34. package/src/intellisense/javascript/fraction.ts +0 -2
  35. package/src/patterns/And.test.ts +63 -52
  36. package/src/patterns/And.ts +58 -36
  37. package/src/patterns/Cursor.ts +17 -14
  38. package/src/patterns/CursorHistory.ts +8 -8
  39. package/src/patterns/Literal.test.ts +70 -38
  40. package/src/patterns/Literal.ts +31 -42
  41. package/src/patterns/Not.test.ts +88 -8
  42. package/src/patterns/Not.ts +54 -14
  43. package/src/patterns/Or.test.ts +117 -13
  44. package/src/patterns/Or.ts +36 -13
  45. package/src/patterns/Pattern.ts +7 -4
  46. package/src/patterns/Reference.test.ts +117 -28
  47. package/src/patterns/Reference.ts +58 -32
  48. package/src/patterns/Regex.test.ts +67 -35
  49. package/src/patterns/Regex.ts +31 -43
  50. package/src/patterns/Repeat.test.ts +63 -41
  51. package/src/patterns/Repeat.ts +51 -38
  52. package/src/patterns/getNextPattern.test.ts +0 -39
  53. 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;
92
+ }
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;
81
103
  }
82
- findAll(isMatch) {
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,35 @@ 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
+ getPatternsAfter(_childReference) {
453
+ return [];
454
+ }
455
+ getNextPatterns() {
456
+ if (this.parent == null) {
457
+ return [];
458
+ }
459
+ return this.parent.getPatternsAfter(this);
427
460
  }
428
- findPattern(_isMatch) {
461
+ findPattern(_predicate) {
429
462
  return null;
430
463
  }
431
464
  setTokens(tokens) {
432
465
  this._tokens = tokens;
433
466
  }
434
- enableContextualTokenAggregation() {
435
- this._hasContextualTokenAggregation = true;
436
- }
437
- disableContextualTokenAggregation() {
438
- this._hasContextualTokenAggregation = false;
439
- }
440
467
  }
441
468
 
442
469
  function clonePatterns(patterns, isOptional) {
@@ -506,7 +533,6 @@ class And {
506
533
  this._parent = null;
507
534
  this._children = children;
508
535
  this._firstIndex = -1;
509
- this._shouldReduceAst = false;
510
536
  this._nodes = [];
511
537
  }
512
538
  _assignChildrenToParent(children) {
@@ -514,11 +540,16 @@ class And {
514
540
  child.parent = this;
515
541
  }
516
542
  }
517
- parseText(text) {
543
+ test(text) {
544
+ const cursor = new Cursor(text);
545
+ const ast = this.parse(cursor);
546
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
547
+ }
548
+ exec(text) {
518
549
  const cursor = new Cursor(text);
519
550
  const ast = this.parse(cursor);
520
551
  return {
521
- ast,
552
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
522
553
  cursor
523
554
  };
524
555
  }
@@ -552,34 +583,43 @@ class And {
552
583
  if (hasMorePatterns) {
553
584
  if (hadMatch) {
554
585
  if (cursor.hasNext()) {
586
+ // We had a match. Increment the cursor and use the next pattern.
555
587
  cursor.next();
556
588
  continue;
557
589
  }
558
590
  else {
591
+ // We are at the end of the text, it may still be valid, if all the
592
+ // following patterns are optional.
559
593
  if (this.areRemainingPatternsOptional(i)) {
560
594
  passed = true;
561
595
  break;
562
596
  }
597
+ // We didn't finish the parsing sequence.
563
598
  cursor.recordErrorAt(cursor.index + 1, this);
564
599
  break;
565
600
  }
566
601
  }
567
602
  else {
603
+ // An optional pattern did not matched, try from the same spot on the next
604
+ // pattern.
568
605
  cursor.moveTo(runningCursorIndex);
569
606
  continue;
570
607
  }
571
608
  }
572
609
  else {
610
+ // If we don't have any results from what we parsed then record error.
573
611
  const lastNode = this.getLastValidNode();
574
612
  if (lastNode === null) {
575
613
  cursor.recordErrorAt(cursor.index, this);
576
614
  break;
577
615
  }
616
+ // The sequence was parsed fully.
578
617
  passed = true;
579
618
  break;
580
619
  }
581
620
  }
582
621
  else {
622
+ // The pattern failed.
583
623
  cursor.moveTo(this._firstIndex);
584
624
  break;
585
625
  }
@@ -607,18 +647,9 @@ class And {
607
647
  createNode(cursor) {
608
648
  const children = filterOutNull(this._nodes);
609
649
  const lastIndex = children[children.length - 1].lastIndex;
610
- const value = cursor.getChars(this._firstIndex, lastIndex);
650
+ cursor.getChars(this._firstIndex, lastIndex);
611
651
  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;
652
+ return new Node("and", this._name, this._firstIndex, lastIndex, children);
622
653
  }
623
654
  getTokens() {
624
655
  const tokens = [];
@@ -630,13 +661,25 @@ class And {
630
661
  }
631
662
  return tokens;
632
663
  }
633
- getNextTokens(lastMatched) {
664
+ getTokensAfter(childReference) {
665
+ const patterns = this.getPatternsAfter(childReference);
666
+ const tokens = [];
667
+ patterns.forEach(p => tokens.push(...p.getTokens()));
668
+ return tokens;
669
+ }
670
+ getNextTokens() {
671
+ if (this.parent == null) {
672
+ return [];
673
+ }
674
+ return this.parent.getTokensAfter(this);
675
+ }
676
+ getPatternsAfter(childReference) {
634
677
  let nextSibling = null;
635
678
  let nextSiblingIndex = -1;
636
679
  let index = -1;
637
- const tokens = [];
680
+ const patterns = [];
638
681
  for (let i = 0; i < this._children.length; i++) {
639
- if (this._children[i] === lastMatched) {
682
+ if (this._children[i] === childReference) {
640
683
  if (i + 1 < this._children.length) {
641
684
  nextSibling = this._children[i + 1];
642
685
  }
@@ -645,39 +688,44 @@ class And {
645
688
  break;
646
689
  }
647
690
  }
691
+ // The child reference isn't one of the child patterns.
648
692
  if (index === -1) {
649
693
  return [];
650
694
  }
695
+ // The reference pattern is the last child. So ask the parent for the next pattern.
651
696
  if (nextSiblingIndex === this._children.length && this._parent !== null) {
652
- return this._parent.getNextTokens(this);
697
+ return this._parent.getPatternsAfter(this);
653
698
  }
699
+ // Next pattern isn't optional so send it back as the next patterns.
654
700
  if (nextSibling !== null && !nextSibling.isOptional) {
655
- return nextSibling.getTokens();
701
+ return [nextSibling];
656
702
  }
703
+ // Send back as many optional patterns as possible.
657
704
  if (nextSibling !== null && nextSibling.isOptional) {
658
705
  for (let i = nextSiblingIndex; i < this._children.length; i++) {
659
706
  const child = this._children[i];
660
- tokens.push(...child.getTokens());
707
+ patterns.push(child);
661
708
  if (!child.isOptional) {
662
709
  break;
663
710
  }
664
711
  if (i === this._children.length - 1 && this._parent !== null) {
665
- tokens.push(...this._parent.getNextTokens(this));
712
+ patterns.push(...this._parent.getPatternsAfter(this));
666
713
  }
667
714
  }
668
715
  }
669
- return tokens;
716
+ return patterns;
670
717
  }
671
- getNextPattern() {
672
- return getNextPattern(this);
718
+ getNextPatterns() {
719
+ if (this.parent == null) {
720
+ return [];
721
+ }
722
+ return this.parent.getPatternsAfter(this);
673
723
  }
674
- findPattern(isMatch) {
675
- return findPattern(this, isMatch);
724
+ findPattern(predicate) {
725
+ return findPattern(this, predicate);
676
726
  }
677
727
  clone(name = this._name, isOptional = this._isOptional) {
678
- const and = new And(name, this._children, isOptional);
679
- and._shouldReduceAst = this._shouldReduceAst;
680
- return and;
728
+ return new And(name, this._children, isOptional);
681
729
  }
682
730
  }
683
731
 
@@ -712,14 +760,17 @@ class Literal {
712
760
  this._parent = null;
713
761
  this._firstIndex = 0;
714
762
  this._lastIndex = 0;
715
- this._hasContextualTokenAggregation = false;
716
- this._isRetrievingContextualTokens = false;
717
763
  }
718
- parseText(text) {
764
+ test(text) {
765
+ const cursor = new Cursor(text);
766
+ const ast = this.parse(cursor);
767
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
768
+ }
769
+ exec(text) {
719
770
  const cursor = new Cursor(text);
720
771
  const ast = this.parse(cursor);
721
772
  return {
722
- ast,
773
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
723
774
  cursor
724
775
  };
725
776
  }
@@ -762,45 +813,35 @@ class Literal {
762
813
  return passed;
763
814
  }
764
815
  _createNode() {
765
- return new Node("literal", this._name, this._firstIndex, this._lastIndex, [], this._literal);
816
+ return new Node("literal", this._name, this._firstIndex, this._lastIndex, undefined, this._literal);
766
817
  }
767
818
  clone(name = this._name, isOptional = this._isOptional) {
768
819
  const clone = new Literal(name, this._literal, isOptional);
769
- clone._hasContextualTokenAggregation = this._hasContextualTokenAggregation;
770
820
  return clone;
771
821
  }
772
822
  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
- }
823
+ return [this._literal];
789
824
  }
790
- getNextTokens(_lastMatched) {
825
+ getTokensAfter(_lastMatched) {
791
826
  return [];
792
827
  }
793
- getNextPattern() {
794
- return getNextPattern(this);
828
+ getNextTokens() {
829
+ if (this.parent == null) {
830
+ return [];
831
+ }
832
+ return this.parent.getTokensAfter(this);
795
833
  }
796
- findPattern(_isMatch) {
797
- return null;
834
+ getPatternsAfter() {
835
+ return [];
798
836
  }
799
- enableContextualTokenAggregation() {
800
- this._hasContextualTokenAggregation = true;
837
+ getNextPatterns() {
838
+ if (this.parent == null) {
839
+ return [];
840
+ }
841
+ return this.parent.getPatternsAfter(this);
801
842
  }
802
- disableContextualTokenAggregation() {
803
- this._hasContextualTokenAggregation = false;
843
+ findPattern(_predicate) {
844
+ return null;
804
845
  }
805
846
  }
806
847
 
@@ -811,9 +852,6 @@ class Not {
811
852
  get name() {
812
853
  return this._name;
813
854
  }
814
- get isOptional() {
815
- return false;
816
- }
817
855
  get parent() {
818
856
  return this._parent;
819
857
  }
@@ -823,6 +861,9 @@ class Not {
823
861
  get children() {
824
862
  return this._children;
825
863
  }
864
+ get isOptional() {
865
+ return false;
866
+ }
826
867
  constructor(name, pattern) {
827
868
  this._type = "not";
828
869
  this._name = name;
@@ -830,7 +871,12 @@ class Not {
830
871
  this._children = [pattern.clone(pattern.name, false)];
831
872
  this._children[0].parent = this;
832
873
  }
833
- parseText(text) {
874
+ test(text) {
875
+ const cursor = new Cursor(text);
876
+ this.parse(cursor);
877
+ return !cursor.hasError;
878
+ }
879
+ exec(text) {
834
880
  const cursor = new Cursor(text);
835
881
  const ast = this.parse(cursor);
836
882
  return {
@@ -856,17 +902,41 @@ class Not {
856
902
  const not = new Not(name, this._children[0]);
857
903
  return not;
858
904
  }
859
- getNextPattern() {
860
- return getNextPattern(this);
861
- }
862
905
  getTokens() {
906
+ const parent = this._parent;
907
+ if (parent != null) {
908
+ return parent.getTokensAfter(this);
909
+ }
863
910
  return [];
864
911
  }
865
- getNextTokens(_lastMatched) {
912
+ getTokensAfter(_childReference) {
913
+ const parent = this._parent;
914
+ if (parent != null) {
915
+ return parent.getTokensAfter(this);
916
+ }
866
917
  return [];
867
918
  }
868
- findPattern(isMatch) {
869
- return isMatch(this._children[0]) ? this._children[0] : null;
919
+ getNextTokens() {
920
+ if (this.parent == null) {
921
+ return [];
922
+ }
923
+ return this.parent.getTokensAfter(this);
924
+ }
925
+ getPatternsAfter(_childReference) {
926
+ const parent = this._parent;
927
+ if (parent != null) {
928
+ return parent.getPatternsAfter(this);
929
+ }
930
+ return [];
931
+ }
932
+ getNextPatterns() {
933
+ if (this.parent == null) {
934
+ return [];
935
+ }
936
+ return this.parent.getPatternsAfter(this);
937
+ }
938
+ findPattern(predicate) {
939
+ return predicate(this._children[0]) ? this._children[0] : null;
870
940
  }
871
941
  }
872
942
 
@@ -900,7 +970,6 @@ class Or {
900
970
  this._parent = null;
901
971
  this._children = children;
902
972
  this._isOptional = isOptional;
903
- this._node = null;
904
973
  this._firstIndex = 0;
905
974
  }
906
975
  _assignChildrenToParent(children) {
@@ -908,17 +977,21 @@ class Or {
908
977
  child.parent = this;
909
978
  }
910
979
  }
911
- parseText(text) {
980
+ test(text) {
981
+ const cursor = new Cursor(text);
982
+ const ast = this.parse(cursor);
983
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
984
+ }
985
+ exec(text) {
912
986
  const cursor = new Cursor(text);
913
987
  const ast = this.parse(cursor);
914
988
  return {
915
- ast,
989
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
916
990
  cursor
917
991
  };
918
992
  }
919
993
  parse(cursor) {
920
994
  this._firstIndex = cursor.index;
921
- this._node = null;
922
995
  const node = this._tryToParse(cursor);
923
996
  if (node != null) {
924
997
  cursor.resolveError();
@@ -950,17 +1023,32 @@ class Or {
950
1023
  }
951
1024
  return tokens;
952
1025
  }
953
- getNextTokens(_lastMatched) {
1026
+ getTokensAfter(_childReference) {
954
1027
  if (this._parent === null) {
955
1028
  return [];
956
1029
  }
957
- return this._parent.getNextTokens(this);
1030
+ return this._parent.getTokensAfter(this);
958
1031
  }
959
- getNextPattern() {
960
- return getNextPattern(this);
1032
+ getNextTokens() {
1033
+ if (this._parent == null) {
1034
+ return [];
1035
+ }
1036
+ return this._parent.getTokensAfter(this);
1037
+ }
1038
+ getPatternsAfter(_childReference) {
1039
+ if (this._parent === null) {
1040
+ return [];
1041
+ }
1042
+ return this._parent.getPatternsAfter(this);
1043
+ }
1044
+ getNextPatterns() {
1045
+ if (this.parent == null) {
1046
+ return [];
1047
+ }
1048
+ return this.parent.getPatternsAfter(this);
961
1049
  }
962
- findPattern(isMatch) {
963
- return findPattern(this, isMatch);
1050
+ findPattern(predicate) {
1051
+ return findPattern(this, predicate);
964
1052
  }
965
1053
  clone(name = this._name, isOptional = this._isOptional) {
966
1054
  const or = new Or(name, this._children, isOptional);
@@ -999,7 +1087,6 @@ class Repeat {
999
1087
  this._pattern = children[0];
1000
1088
  this._divider = children[1];
1001
1089
  this._firstIndex = -1;
1002
- this._shouldReduceAst = false;
1003
1090
  this._nodes = [];
1004
1091
  }
1005
1092
  _assignChildrenToParent(children) {
@@ -1007,11 +1094,16 @@ class Repeat {
1007
1094
  child.parent = this;
1008
1095
  }
1009
1096
  }
1010
- parseText(text) {
1097
+ test(text) {
1098
+ const cursor = new Cursor(text);
1099
+ const ast = this.parse(cursor);
1100
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
1101
+ }
1102
+ exec(text) {
1011
1103
  const cursor = new Cursor(text);
1012
1104
  const ast = this.parse(cursor);
1013
1105
  return {
1014
- ast,
1106
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
1015
1107
  cursor
1016
1108
  };
1017
1109
  }
@@ -1022,7 +1114,7 @@ class Repeat {
1022
1114
  if (passed) {
1023
1115
  cursor.resolveError();
1024
1116
  const node = this.createNode(cursor);
1025
- if (node) {
1117
+ if (node != null) {
1026
1118
  cursor.recordMatch(this, node);
1027
1119
  }
1028
1120
  return node;
@@ -1041,7 +1133,7 @@ class Repeat {
1041
1133
  const repeatedNode = this._pattern.parse(cursor);
1042
1134
  if (cursor.hasError) {
1043
1135
  const lastValidNode = this.getLastValidNode();
1044
- if (lastValidNode) {
1136
+ if (lastValidNode != null) {
1045
1137
  passed = true;
1046
1138
  }
1047
1139
  else {
@@ -1058,13 +1150,13 @@ class Repeat {
1058
1150
  break;
1059
1151
  }
1060
1152
  cursor.next();
1061
- if (this._divider) {
1153
+ if (this._divider != null) {
1062
1154
  const dividerNode = this._divider.parse(cursor);
1063
1155
  if (cursor.hasError) {
1064
1156
  passed = true;
1065
1157
  break;
1066
1158
  }
1067
- else if (dividerNode) {
1159
+ else if (dividerNode != null) {
1068
1160
  this._nodes.push(dividerNode);
1069
1161
  if (!cursor.hasNext()) {
1070
1162
  passed = true;
@@ -1093,12 +1185,9 @@ class Repeat {
1093
1185
  }
1094
1186
  }
1095
1187
  const lastIndex = children[children.length - 1].lastIndex;
1096
- const value = cursor.getChars(this._firstIndex, lastIndex);
1188
+ cursor.getChars(this._firstIndex, lastIndex);
1097
1189
  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);
1190
+ return new Node("repeat", this._name, this._firstIndex, lastIndex, children, undefined);
1102
1191
  }
1103
1192
  getLastValidNode() {
1104
1193
  const nodes = this._nodes.filter((node) => node !== null);
@@ -1107,51 +1196,61 @@ class Repeat {
1107
1196
  }
1108
1197
  return nodes[nodes.length - 1];
1109
1198
  }
1110
- enableAstReduction() {
1111
- this._shouldReduceAst = true;
1112
- }
1113
- disableAstReduction() {
1114
- this._shouldReduceAst = false;
1115
- }
1116
1199
  getTokens() {
1117
1200
  return this._pattern.getTokens();
1118
1201
  }
1119
- getNextTokens(lastMatched) {
1120
- let index = -1;
1202
+ getTokensAfter(childReference) {
1203
+ const patterns = this.getPatternsAfter(childReference);
1121
1204
  const tokens = [];
1205
+ patterns.forEach(p => tokens.push(...p.getTokens()));
1206
+ return tokens;
1207
+ }
1208
+ getNextTokens() {
1209
+ if (this.parent == null) {
1210
+ return [];
1211
+ }
1212
+ return this.parent.getTokensAfter(this);
1213
+ }
1214
+ getPatternsAfter(childReference) {
1215
+ let index = -1;
1216
+ const patterns = [];
1122
1217
  for (let i = 0; i < this._children.length; i++) {
1123
- if (this._children[i] === lastMatched) {
1218
+ if (this._children[i] === childReference) {
1124
1219
  index = i;
1125
1220
  }
1126
1221
  }
1222
+ // If the last match isn't a child of this pattern.
1127
1223
  if (index === -1) {
1128
1224
  return [];
1129
1225
  }
1226
+ // If the last match was the repeated patterns, then suggest the divider.
1130
1227
  if (index === 0 && this._divider) {
1131
- tokens.push(...this._children[1].getTokens());
1228
+ patterns.push(this._children[1]);
1132
1229
  if (this._parent) {
1133
- tokens.push(...this._parent.getNextTokens(this));
1230
+ patterns.push(...this._parent.getPatternsAfter(this));
1134
1231
  }
1135
1232
  }
1233
+ // Suggest the pattern because the divider was the last match.
1136
1234
  if (index === 1) {
1137
- tokens.push(...this._children[0].getTokens());
1235
+ patterns.push(this._children[0]);
1138
1236
  }
1139
1237
  if (index === 0 && !this._divider && this._parent) {
1140
- tokens.push(...this._children[0].getTokens());
1141
- tokens.push(...this._parent.getNextTokens(this));
1238
+ patterns.push(this._children[0]);
1239
+ patterns.push(...this._parent.getPatternsAfter(this));
1142
1240
  }
1143
- return tokens;
1241
+ return patterns;
1144
1242
  }
1145
- getNextPattern() {
1146
- return getNextPattern(this);
1243
+ getNextPatterns() {
1244
+ if (this.parent == null) {
1245
+ return [];
1246
+ }
1247
+ return this.parent.getPatternsAfter(this);
1147
1248
  }
1148
- findPattern(isMatch) {
1149
- return findPattern(this, isMatch);
1249
+ findPattern(predicate) {
1250
+ return findPattern(this, predicate);
1150
1251
  }
1151
1252
  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;
1253
+ return new Repeat(name, this._pattern, this._divider, isOptional);
1155
1254
  }
1156
1255
  }
1157
1256
 
@@ -1162,9 +1261,6 @@ class Reference {
1162
1261
  get name() {
1163
1262
  return this._name;
1164
1263
  }
1165
- get isOptional() {
1166
- return this._isOptional;
1167
- }
1168
1264
  get parent() {
1169
1265
  return this._parent;
1170
1266
  }
@@ -1174,6 +1270,9 @@ class Reference {
1174
1270
  get children() {
1175
1271
  return this._children;
1176
1272
  }
1273
+ get isOptional() {
1274
+ return this._isOptional;
1275
+ }
1177
1276
  constructor(name, isOptional = false) {
1178
1277
  this._type = "reference";
1179
1278
  this._name = name;
@@ -1182,35 +1281,22 @@ class Reference {
1182
1281
  this._pattern = null;
1183
1282
  this._children = [];
1184
1283
  }
1185
- parseText(text) {
1284
+ test(text) {
1285
+ const cursor = new Cursor(text);
1286
+ const ast = this.parse(cursor);
1287
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
1288
+ }
1289
+ exec(text) {
1186
1290
  const cursor = new Cursor(text);
1187
1291
  const ast = this.parse(cursor);
1188
1292
  return {
1189
- ast,
1293
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
1190
1294
  cursor
1191
1295
  };
1192
1296
  }
1193
1297
  parse(cursor) {
1194
1298
  return this._getPatternSafely().parse(cursor);
1195
1299
  }
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
1300
  _getPatternSafely() {
1215
1301
  if (this._pattern === null) {
1216
1302
  const pattern = this._findPattern();
@@ -1243,7 +1329,184 @@ class Reference {
1243
1329
  }
1244
1330
  return node;
1245
1331
  }
1332
+ getTokens() {
1333
+ return this._getPatternSafely().getTokens();
1334
+ }
1335
+ getTokensAfter(_lastMatched) {
1336
+ if (this._parent == null) {
1337
+ return [];
1338
+ }
1339
+ return this._parent.getTokensAfter(this);
1340
+ }
1341
+ getNextTokens() {
1342
+ if (this.parent == null) {
1343
+ return [];
1344
+ }
1345
+ return this.parent.getTokensAfter(this);
1346
+ }
1347
+ getPatternsAfter(_childReference) {
1348
+ if (this._parent == null) {
1349
+ return [];
1350
+ }
1351
+ return this._parent.getPatternsAfter(this);
1352
+ }
1353
+ getNextPatterns() {
1354
+ if (this.parent == null) {
1355
+ return [];
1356
+ }
1357
+ return this.parent.getPatternsAfter(this);
1358
+ }
1359
+ findPattern(_predicate) {
1360
+ return null;
1361
+ }
1362
+ clone(name = this._name, isOptional = this._isOptional) {
1363
+ return new Reference(name, isOptional);
1364
+ }
1365
+ }
1366
+
1367
+ const defaultOptions = { greedyPatternNames: [], customTokens: {} };
1368
+ class AutoComplete {
1369
+ constructor(pattern, options = defaultOptions) {
1370
+ this._pattern = pattern;
1371
+ this._options = options;
1372
+ this._text = "";
1373
+ }
1374
+ suggest(text) {
1375
+ if (text.length === 0) {
1376
+ return {
1377
+ isComplete: false,
1378
+ options: this.createSuggestionsFromRoot(),
1379
+ nextPatterns: [this._pattern],
1380
+ cursor: null,
1381
+ ast: null
1382
+ };
1383
+ }
1384
+ this._text = text;
1385
+ this._cursor = new Cursor(text);
1386
+ const ast = this._pattern.parse(this._cursor);
1387
+ const leafPattern = this._cursor.leafMatch.pattern;
1388
+ const isComplete = (ast === null || ast === void 0 ? void 0 : ast.value) === text;
1389
+ const options = this.createSuggestionsFromTokens();
1390
+ let nextPatterns = [this._pattern];
1391
+ if (leafPattern != null) {
1392
+ nextPatterns = leafPattern.getNextPatterns();
1393
+ }
1394
+ return {
1395
+ isComplete: isComplete,
1396
+ options: options,
1397
+ nextPatterns,
1398
+ cursor: this._cursor,
1399
+ ast,
1400
+ };
1401
+ }
1402
+ createSuggestionsFromRoot() {
1403
+ const suggestions = [];
1404
+ const tokens = this._pattern.getTokens();
1405
+ for (const token of tokens) {
1406
+ suggestions.push(this.createSuggestion("", token));
1407
+ }
1408
+ return suggestions;
1409
+ }
1410
+ createSuggestionsFromTokens() {
1411
+ const leafMatch = this._cursor.leafMatch;
1412
+ if (!leafMatch.pattern) {
1413
+ return this.createSuggestions(-1, this._getTokensForPattern(this._pattern));
1414
+ }
1415
+ const leafPattern = leafMatch.pattern;
1416
+ leafMatch.node;
1417
+ const parent = leafMatch.pattern.parent;
1418
+ if (parent !== null && leafMatch.node != null) {
1419
+ const patterns = leafPattern.getNextPatterns();
1420
+ const tokens = patterns.reduce((acc, pattern) => {
1421
+ acc.push(...this._getTokensForPattern(pattern));
1422
+ return acc;
1423
+ }, []);
1424
+ return this.createSuggestions(leafMatch.node.lastIndex, tokens);
1425
+ }
1426
+ else {
1427
+ return [];
1428
+ }
1429
+ }
1430
+ _getTokensForPattern(pattern) {
1431
+ if (this._options.greedyPatternNames.includes(pattern.name)) {
1432
+ const greedyTokens = pattern.getTokens();
1433
+ const nextPatterns = pattern.getNextPatterns();
1434
+ const tokens = [];
1435
+ const nextPatternTokens = nextPatterns.reduce((acc, pattern) => {
1436
+ acc.push(...this._getTokensForPattern(pattern));
1437
+ return acc;
1438
+ }, []);
1439
+ for (let token of greedyTokens) {
1440
+ for (let nextPatternToken of nextPatternTokens) {
1441
+ tokens.push(token + nextPatternToken);
1442
+ }
1443
+ }
1444
+ return tokens;
1445
+ }
1446
+ else {
1447
+ const tokens = pattern.getTokens();
1448
+ const customTokens = this._options.customTokens[pattern.name] || [];
1449
+ tokens.push(...customTokens);
1450
+ return tokens;
1451
+ }
1452
+ }
1453
+ createSuggestions(lastIndex, tokens) {
1454
+ let substring = lastIndex === -1 ? "" : this._cursor.getChars(0, lastIndex);
1455
+ const suggestionStrings = [];
1456
+ const options = [];
1457
+ for (const token of tokens) {
1458
+ const suggestion = substring + token;
1459
+ const startsWith = suggestion.startsWith(substring);
1460
+ const alreadyExist = suggestionStrings.includes(suggestion);
1461
+ const isSameAsText = suggestion === this._text;
1462
+ if (startsWith && !alreadyExist && !isSameAsText) {
1463
+ suggestionStrings.push(suggestion);
1464
+ options.push(this.createSuggestion(this._cursor.text, suggestion));
1465
+ }
1466
+ }
1467
+ const reducedOptions = getFurthestOptions(options);
1468
+ reducedOptions.sort((a, b) => a.text.localeCompare(b.text));
1469
+ return reducedOptions;
1470
+ }
1471
+ createSuggestion(fullText, suggestion) {
1472
+ const furthestMatch = findMatchIndex(suggestion, fullText);
1473
+ const text = suggestion.slice(furthestMatch);
1474
+ return {
1475
+ text: text,
1476
+ startIndex: furthestMatch,
1477
+ };
1478
+ }
1479
+ }
1480
+ function findMatchIndex(str1, str2) {
1481
+ let matchCount = 0;
1482
+ let minLength = str1.length;
1483
+ if (str2.length < minLength) {
1484
+ minLength = str2.length;
1485
+ }
1486
+ for (let i = 0; i < minLength; i++) {
1487
+ if (str1[i] === str2[i]) {
1488
+ matchCount++;
1489
+ }
1490
+ else {
1491
+ break;
1492
+ }
1493
+ }
1494
+ return matchCount;
1495
+ }
1496
+ function getFurthestOptions(options) {
1497
+ let furthestOptions = [];
1498
+ let furthestIndex = -1;
1499
+ for (const option of options) {
1500
+ if (option.startIndex > furthestIndex) {
1501
+ furthestIndex = option.startIndex;
1502
+ furthestOptions = [];
1503
+ }
1504
+ if (option.startIndex === furthestIndex) {
1505
+ furthestOptions.push(option);
1506
+ }
1507
+ }
1508
+ return furthestOptions;
1246
1509
  }
1247
1510
 
1248
- export { And, Cursor, Literal, Node, Not, Or, ParseError, Reference, Regex, Repeat };
1511
+ export { And, AutoComplete, Cursor, CursorHistory, Literal, Node, Not, Or, ParseError, Reference, Regex, Repeat };
1249
1512
  //# sourceMappingURL=index.esm.js.map