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.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;
96
+ }
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;
85
107
  }
86
- findAll(isMatch) {
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,35 @@ 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
+ getPatternsAfter(_childReference) {
457
+ return [];
458
+ }
459
+ getNextPatterns() {
460
+ if (this.parent == null) {
461
+ return [];
462
+ }
463
+ return this.parent.getPatternsAfter(this);
431
464
  }
432
- findPattern(_isMatch) {
465
+ findPattern(_predicate) {
433
466
  return null;
434
467
  }
435
468
  setTokens(tokens) {
436
469
  this._tokens = tokens;
437
470
  }
438
- enableContextualTokenAggregation() {
439
- this._hasContextualTokenAggregation = true;
440
- }
441
- disableContextualTokenAggregation() {
442
- this._hasContextualTokenAggregation = false;
443
- }
444
471
  }
445
472
 
446
473
  function clonePatterns(patterns, isOptional) {
@@ -510,7 +537,6 @@ class And {
510
537
  this._parent = null;
511
538
  this._children = children;
512
539
  this._firstIndex = -1;
513
- this._shouldReduceAst = false;
514
540
  this._nodes = [];
515
541
  }
516
542
  _assignChildrenToParent(children) {
@@ -518,11 +544,16 @@ class And {
518
544
  child.parent = this;
519
545
  }
520
546
  }
521
- parseText(text) {
547
+ test(text) {
548
+ const cursor = new Cursor(text);
549
+ const ast = this.parse(cursor);
550
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
551
+ }
552
+ exec(text) {
522
553
  const cursor = new Cursor(text);
523
554
  const ast = this.parse(cursor);
524
555
  return {
525
- ast,
556
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
526
557
  cursor
527
558
  };
528
559
  }
@@ -556,34 +587,43 @@ class And {
556
587
  if (hasMorePatterns) {
557
588
  if (hadMatch) {
558
589
  if (cursor.hasNext()) {
590
+ // We had a match. Increment the cursor and use the next pattern.
559
591
  cursor.next();
560
592
  continue;
561
593
  }
562
594
  else {
595
+ // We are at the end of the text, it may still be valid, if all the
596
+ // following patterns are optional.
563
597
  if (this.areRemainingPatternsOptional(i)) {
564
598
  passed = true;
565
599
  break;
566
600
  }
601
+ // We didn't finish the parsing sequence.
567
602
  cursor.recordErrorAt(cursor.index + 1, this);
568
603
  break;
569
604
  }
570
605
  }
571
606
  else {
607
+ // An optional pattern did not matched, try from the same spot on the next
608
+ // pattern.
572
609
  cursor.moveTo(runningCursorIndex);
573
610
  continue;
574
611
  }
575
612
  }
576
613
  else {
614
+ // If we don't have any results from what we parsed then record error.
577
615
  const lastNode = this.getLastValidNode();
578
616
  if (lastNode === null) {
579
617
  cursor.recordErrorAt(cursor.index, this);
580
618
  break;
581
619
  }
620
+ // The sequence was parsed fully.
582
621
  passed = true;
583
622
  break;
584
623
  }
585
624
  }
586
625
  else {
626
+ // The pattern failed.
587
627
  cursor.moveTo(this._firstIndex);
588
628
  break;
589
629
  }
@@ -611,18 +651,9 @@ class And {
611
651
  createNode(cursor) {
612
652
  const children = filterOutNull(this._nodes);
613
653
  const lastIndex = children[children.length - 1].lastIndex;
614
- const value = cursor.getChars(this._firstIndex, lastIndex);
654
+ cursor.getChars(this._firstIndex, lastIndex);
615
655
  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;
656
+ return new Node("and", this._name, this._firstIndex, lastIndex, children);
626
657
  }
627
658
  getTokens() {
628
659
  const tokens = [];
@@ -634,13 +665,25 @@ class And {
634
665
  }
635
666
  return tokens;
636
667
  }
637
- getNextTokens(lastMatched) {
668
+ getTokensAfter(childReference) {
669
+ const patterns = this.getPatternsAfter(childReference);
670
+ const tokens = [];
671
+ patterns.forEach(p => tokens.push(...p.getTokens()));
672
+ return tokens;
673
+ }
674
+ getNextTokens() {
675
+ if (this.parent == null) {
676
+ return [];
677
+ }
678
+ return this.parent.getTokensAfter(this);
679
+ }
680
+ getPatternsAfter(childReference) {
638
681
  let nextSibling = null;
639
682
  let nextSiblingIndex = -1;
640
683
  let index = -1;
641
- const tokens = [];
684
+ const patterns = [];
642
685
  for (let i = 0; i < this._children.length; i++) {
643
- if (this._children[i] === lastMatched) {
686
+ if (this._children[i] === childReference) {
644
687
  if (i + 1 < this._children.length) {
645
688
  nextSibling = this._children[i + 1];
646
689
  }
@@ -649,39 +692,44 @@ class And {
649
692
  break;
650
693
  }
651
694
  }
695
+ // The child reference isn't one of the child patterns.
652
696
  if (index === -1) {
653
697
  return [];
654
698
  }
699
+ // The reference pattern is the last child. So ask the parent for the next pattern.
655
700
  if (nextSiblingIndex === this._children.length && this._parent !== null) {
656
- return this._parent.getNextTokens(this);
701
+ return this._parent.getPatternsAfter(this);
657
702
  }
703
+ // Next pattern isn't optional so send it back as the next patterns.
658
704
  if (nextSibling !== null && !nextSibling.isOptional) {
659
- return nextSibling.getTokens();
705
+ return [nextSibling];
660
706
  }
707
+ // Send back as many optional patterns as possible.
661
708
  if (nextSibling !== null && nextSibling.isOptional) {
662
709
  for (let i = nextSiblingIndex; i < this._children.length; i++) {
663
710
  const child = this._children[i];
664
- tokens.push(...child.getTokens());
711
+ patterns.push(child);
665
712
  if (!child.isOptional) {
666
713
  break;
667
714
  }
668
715
  if (i === this._children.length - 1 && this._parent !== null) {
669
- tokens.push(...this._parent.getNextTokens(this));
716
+ patterns.push(...this._parent.getPatternsAfter(this));
670
717
  }
671
718
  }
672
719
  }
673
- return tokens;
720
+ return patterns;
674
721
  }
675
- getNextPattern() {
676
- return getNextPattern(this);
722
+ getNextPatterns() {
723
+ if (this.parent == null) {
724
+ return [];
725
+ }
726
+ return this.parent.getPatternsAfter(this);
677
727
  }
678
- findPattern(isMatch) {
679
- return findPattern(this, isMatch);
728
+ findPattern(predicate) {
729
+ return findPattern(this, predicate);
680
730
  }
681
731
  clone(name = this._name, isOptional = this._isOptional) {
682
- const and = new And(name, this._children, isOptional);
683
- and._shouldReduceAst = this._shouldReduceAst;
684
- return and;
732
+ return new And(name, this._children, isOptional);
685
733
  }
686
734
  }
687
735
 
@@ -716,14 +764,17 @@ class Literal {
716
764
  this._parent = null;
717
765
  this._firstIndex = 0;
718
766
  this._lastIndex = 0;
719
- this._hasContextualTokenAggregation = false;
720
- this._isRetrievingContextualTokens = false;
721
767
  }
722
- parseText(text) {
768
+ test(text) {
769
+ const cursor = new Cursor(text);
770
+ const ast = this.parse(cursor);
771
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
772
+ }
773
+ exec(text) {
723
774
  const cursor = new Cursor(text);
724
775
  const ast = this.parse(cursor);
725
776
  return {
726
- ast,
777
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
727
778
  cursor
728
779
  };
729
780
  }
@@ -766,45 +817,35 @@ class Literal {
766
817
  return passed;
767
818
  }
768
819
  _createNode() {
769
- return new Node("literal", this._name, this._firstIndex, this._lastIndex, [], this._literal);
820
+ return new Node("literal", this._name, this._firstIndex, this._lastIndex, undefined, this._literal);
770
821
  }
771
822
  clone(name = this._name, isOptional = this._isOptional) {
772
823
  const clone = new Literal(name, this._literal, isOptional);
773
- clone._hasContextualTokenAggregation = this._hasContextualTokenAggregation;
774
824
  return clone;
775
825
  }
776
826
  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
- }
827
+ return [this._literal];
793
828
  }
794
- getNextTokens(_lastMatched) {
829
+ getTokensAfter(_lastMatched) {
795
830
  return [];
796
831
  }
797
- getNextPattern() {
798
- return getNextPattern(this);
832
+ getNextTokens() {
833
+ if (this.parent == null) {
834
+ return [];
835
+ }
836
+ return this.parent.getTokensAfter(this);
799
837
  }
800
- findPattern(_isMatch) {
801
- return null;
838
+ getPatternsAfter() {
839
+ return [];
802
840
  }
803
- enableContextualTokenAggregation() {
804
- this._hasContextualTokenAggregation = true;
841
+ getNextPatterns() {
842
+ if (this.parent == null) {
843
+ return [];
844
+ }
845
+ return this.parent.getPatternsAfter(this);
805
846
  }
806
- disableContextualTokenAggregation() {
807
- this._hasContextualTokenAggregation = false;
847
+ findPattern(_predicate) {
848
+ return null;
808
849
  }
809
850
  }
810
851
 
@@ -815,9 +856,6 @@ class Not {
815
856
  get name() {
816
857
  return this._name;
817
858
  }
818
- get isOptional() {
819
- return false;
820
- }
821
859
  get parent() {
822
860
  return this._parent;
823
861
  }
@@ -827,6 +865,9 @@ class Not {
827
865
  get children() {
828
866
  return this._children;
829
867
  }
868
+ get isOptional() {
869
+ return false;
870
+ }
830
871
  constructor(name, pattern) {
831
872
  this._type = "not";
832
873
  this._name = name;
@@ -834,7 +875,12 @@ class Not {
834
875
  this._children = [pattern.clone(pattern.name, false)];
835
876
  this._children[0].parent = this;
836
877
  }
837
- parseText(text) {
878
+ test(text) {
879
+ const cursor = new Cursor(text);
880
+ this.parse(cursor);
881
+ return !cursor.hasError;
882
+ }
883
+ exec(text) {
838
884
  const cursor = new Cursor(text);
839
885
  const ast = this.parse(cursor);
840
886
  return {
@@ -860,17 +906,41 @@ class Not {
860
906
  const not = new Not(name, this._children[0]);
861
907
  return not;
862
908
  }
863
- getNextPattern() {
864
- return getNextPattern(this);
865
- }
866
909
  getTokens() {
910
+ const parent = this._parent;
911
+ if (parent != null) {
912
+ return parent.getTokensAfter(this);
913
+ }
867
914
  return [];
868
915
  }
869
- getNextTokens(_lastMatched) {
916
+ getTokensAfter(_childReference) {
917
+ const parent = this._parent;
918
+ if (parent != null) {
919
+ return parent.getTokensAfter(this);
920
+ }
870
921
  return [];
871
922
  }
872
- findPattern(isMatch) {
873
- return isMatch(this._children[0]) ? this._children[0] : null;
923
+ getNextTokens() {
924
+ if (this.parent == null) {
925
+ return [];
926
+ }
927
+ return this.parent.getTokensAfter(this);
928
+ }
929
+ getPatternsAfter(_childReference) {
930
+ const parent = this._parent;
931
+ if (parent != null) {
932
+ return parent.getPatternsAfter(this);
933
+ }
934
+ return [];
935
+ }
936
+ getNextPatterns() {
937
+ if (this.parent == null) {
938
+ return [];
939
+ }
940
+ return this.parent.getPatternsAfter(this);
941
+ }
942
+ findPattern(predicate) {
943
+ return predicate(this._children[0]) ? this._children[0] : null;
874
944
  }
875
945
  }
876
946
 
@@ -904,7 +974,6 @@ class Or {
904
974
  this._parent = null;
905
975
  this._children = children;
906
976
  this._isOptional = isOptional;
907
- this._node = null;
908
977
  this._firstIndex = 0;
909
978
  }
910
979
  _assignChildrenToParent(children) {
@@ -912,17 +981,21 @@ class Or {
912
981
  child.parent = this;
913
982
  }
914
983
  }
915
- parseText(text) {
984
+ test(text) {
985
+ const cursor = new Cursor(text);
986
+ const ast = this.parse(cursor);
987
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
988
+ }
989
+ exec(text) {
916
990
  const cursor = new Cursor(text);
917
991
  const ast = this.parse(cursor);
918
992
  return {
919
- ast,
993
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
920
994
  cursor
921
995
  };
922
996
  }
923
997
  parse(cursor) {
924
998
  this._firstIndex = cursor.index;
925
- this._node = null;
926
999
  const node = this._tryToParse(cursor);
927
1000
  if (node != null) {
928
1001
  cursor.resolveError();
@@ -954,17 +1027,32 @@ class Or {
954
1027
  }
955
1028
  return tokens;
956
1029
  }
957
- getNextTokens(_lastMatched) {
1030
+ getTokensAfter(_childReference) {
958
1031
  if (this._parent === null) {
959
1032
  return [];
960
1033
  }
961
- return this._parent.getNextTokens(this);
1034
+ return this._parent.getTokensAfter(this);
962
1035
  }
963
- getNextPattern() {
964
- return getNextPattern(this);
1036
+ getNextTokens() {
1037
+ if (this._parent == null) {
1038
+ return [];
1039
+ }
1040
+ return this._parent.getTokensAfter(this);
1041
+ }
1042
+ getPatternsAfter(_childReference) {
1043
+ if (this._parent === null) {
1044
+ return [];
1045
+ }
1046
+ return this._parent.getPatternsAfter(this);
1047
+ }
1048
+ getNextPatterns() {
1049
+ if (this.parent == null) {
1050
+ return [];
1051
+ }
1052
+ return this.parent.getPatternsAfter(this);
965
1053
  }
966
- findPattern(isMatch) {
967
- return findPattern(this, isMatch);
1054
+ findPattern(predicate) {
1055
+ return findPattern(this, predicate);
968
1056
  }
969
1057
  clone(name = this._name, isOptional = this._isOptional) {
970
1058
  const or = new Or(name, this._children, isOptional);
@@ -1003,7 +1091,6 @@ class Repeat {
1003
1091
  this._pattern = children[0];
1004
1092
  this._divider = children[1];
1005
1093
  this._firstIndex = -1;
1006
- this._shouldReduceAst = false;
1007
1094
  this._nodes = [];
1008
1095
  }
1009
1096
  _assignChildrenToParent(children) {
@@ -1011,11 +1098,16 @@ class Repeat {
1011
1098
  child.parent = this;
1012
1099
  }
1013
1100
  }
1014
- parseText(text) {
1101
+ test(text) {
1102
+ const cursor = new Cursor(text);
1103
+ const ast = this.parse(cursor);
1104
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
1105
+ }
1106
+ exec(text) {
1015
1107
  const cursor = new Cursor(text);
1016
1108
  const ast = this.parse(cursor);
1017
1109
  return {
1018
- ast,
1110
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
1019
1111
  cursor
1020
1112
  };
1021
1113
  }
@@ -1026,7 +1118,7 @@ class Repeat {
1026
1118
  if (passed) {
1027
1119
  cursor.resolveError();
1028
1120
  const node = this.createNode(cursor);
1029
- if (node) {
1121
+ if (node != null) {
1030
1122
  cursor.recordMatch(this, node);
1031
1123
  }
1032
1124
  return node;
@@ -1045,7 +1137,7 @@ class Repeat {
1045
1137
  const repeatedNode = this._pattern.parse(cursor);
1046
1138
  if (cursor.hasError) {
1047
1139
  const lastValidNode = this.getLastValidNode();
1048
- if (lastValidNode) {
1140
+ if (lastValidNode != null) {
1049
1141
  passed = true;
1050
1142
  }
1051
1143
  else {
@@ -1062,13 +1154,13 @@ class Repeat {
1062
1154
  break;
1063
1155
  }
1064
1156
  cursor.next();
1065
- if (this._divider) {
1157
+ if (this._divider != null) {
1066
1158
  const dividerNode = this._divider.parse(cursor);
1067
1159
  if (cursor.hasError) {
1068
1160
  passed = true;
1069
1161
  break;
1070
1162
  }
1071
- else if (dividerNode) {
1163
+ else if (dividerNode != null) {
1072
1164
  this._nodes.push(dividerNode);
1073
1165
  if (!cursor.hasNext()) {
1074
1166
  passed = true;
@@ -1097,12 +1189,9 @@ class Repeat {
1097
1189
  }
1098
1190
  }
1099
1191
  const lastIndex = children[children.length - 1].lastIndex;
1100
- const value = cursor.getChars(this._firstIndex, lastIndex);
1192
+ cursor.getChars(this._firstIndex, lastIndex);
1101
1193
  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);
1194
+ return new Node("repeat", this._name, this._firstIndex, lastIndex, children, undefined);
1106
1195
  }
1107
1196
  getLastValidNode() {
1108
1197
  const nodes = this._nodes.filter((node) => node !== null);
@@ -1111,51 +1200,61 @@ class Repeat {
1111
1200
  }
1112
1201
  return nodes[nodes.length - 1];
1113
1202
  }
1114
- enableAstReduction() {
1115
- this._shouldReduceAst = true;
1116
- }
1117
- disableAstReduction() {
1118
- this._shouldReduceAst = false;
1119
- }
1120
1203
  getTokens() {
1121
1204
  return this._pattern.getTokens();
1122
1205
  }
1123
- getNextTokens(lastMatched) {
1124
- let index = -1;
1206
+ getTokensAfter(childReference) {
1207
+ const patterns = this.getPatternsAfter(childReference);
1125
1208
  const tokens = [];
1209
+ patterns.forEach(p => tokens.push(...p.getTokens()));
1210
+ return tokens;
1211
+ }
1212
+ getNextTokens() {
1213
+ if (this.parent == null) {
1214
+ return [];
1215
+ }
1216
+ return this.parent.getTokensAfter(this);
1217
+ }
1218
+ getPatternsAfter(childReference) {
1219
+ let index = -1;
1220
+ const patterns = [];
1126
1221
  for (let i = 0; i < this._children.length; i++) {
1127
- if (this._children[i] === lastMatched) {
1222
+ if (this._children[i] === childReference) {
1128
1223
  index = i;
1129
1224
  }
1130
1225
  }
1226
+ // If the last match isn't a child of this pattern.
1131
1227
  if (index === -1) {
1132
1228
  return [];
1133
1229
  }
1230
+ // If the last match was the repeated patterns, then suggest the divider.
1134
1231
  if (index === 0 && this._divider) {
1135
- tokens.push(...this._children[1].getTokens());
1232
+ patterns.push(this._children[1]);
1136
1233
  if (this._parent) {
1137
- tokens.push(...this._parent.getNextTokens(this));
1234
+ patterns.push(...this._parent.getPatternsAfter(this));
1138
1235
  }
1139
1236
  }
1237
+ // Suggest the pattern because the divider was the last match.
1140
1238
  if (index === 1) {
1141
- tokens.push(...this._children[0].getTokens());
1239
+ patterns.push(this._children[0]);
1142
1240
  }
1143
1241
  if (index === 0 && !this._divider && this._parent) {
1144
- tokens.push(...this._children[0].getTokens());
1145
- tokens.push(...this._parent.getNextTokens(this));
1242
+ patterns.push(this._children[0]);
1243
+ patterns.push(...this._parent.getPatternsAfter(this));
1146
1244
  }
1147
- return tokens;
1245
+ return patterns;
1148
1246
  }
1149
- getNextPattern() {
1150
- return getNextPattern(this);
1247
+ getNextPatterns() {
1248
+ if (this.parent == null) {
1249
+ return [];
1250
+ }
1251
+ return this.parent.getPatternsAfter(this);
1151
1252
  }
1152
- findPattern(isMatch) {
1153
- return findPattern(this, isMatch);
1253
+ findPattern(predicate) {
1254
+ return findPattern(this, predicate);
1154
1255
  }
1155
1256
  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;
1257
+ return new Repeat(name, this._pattern, this._divider, isOptional);
1159
1258
  }
1160
1259
  }
1161
1260
 
@@ -1166,9 +1265,6 @@ class Reference {
1166
1265
  get name() {
1167
1266
  return this._name;
1168
1267
  }
1169
- get isOptional() {
1170
- return this._isOptional;
1171
- }
1172
1268
  get parent() {
1173
1269
  return this._parent;
1174
1270
  }
@@ -1178,6 +1274,9 @@ class Reference {
1178
1274
  get children() {
1179
1275
  return this._children;
1180
1276
  }
1277
+ get isOptional() {
1278
+ return this._isOptional;
1279
+ }
1181
1280
  constructor(name, isOptional = false) {
1182
1281
  this._type = "reference";
1183
1282
  this._name = name;
@@ -1186,35 +1285,22 @@ class Reference {
1186
1285
  this._pattern = null;
1187
1286
  this._children = [];
1188
1287
  }
1189
- parseText(text) {
1288
+ test(text) {
1289
+ const cursor = new Cursor(text);
1290
+ const ast = this.parse(cursor);
1291
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
1292
+ }
1293
+ exec(text) {
1190
1294
  const cursor = new Cursor(text);
1191
1295
  const ast = this.parse(cursor);
1192
1296
  return {
1193
- ast,
1297
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
1194
1298
  cursor
1195
1299
  };
1196
1300
  }
1197
1301
  parse(cursor) {
1198
1302
  return this._getPatternSafely().parse(cursor);
1199
1303
  }
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
1304
  _getPatternSafely() {
1219
1305
  if (this._pattern === null) {
1220
1306
  const pattern = this._findPattern();
@@ -1247,10 +1333,189 @@ class Reference {
1247
1333
  }
1248
1334
  return node;
1249
1335
  }
1336
+ getTokens() {
1337
+ return this._getPatternSafely().getTokens();
1338
+ }
1339
+ getTokensAfter(_lastMatched) {
1340
+ if (this._parent == null) {
1341
+ return [];
1342
+ }
1343
+ return this._parent.getTokensAfter(this);
1344
+ }
1345
+ getNextTokens() {
1346
+ if (this.parent == null) {
1347
+ return [];
1348
+ }
1349
+ return this.parent.getTokensAfter(this);
1350
+ }
1351
+ getPatternsAfter(_childReference) {
1352
+ if (this._parent == null) {
1353
+ return [];
1354
+ }
1355
+ return this._parent.getPatternsAfter(this);
1356
+ }
1357
+ getNextPatterns() {
1358
+ if (this.parent == null) {
1359
+ return [];
1360
+ }
1361
+ return this.parent.getPatternsAfter(this);
1362
+ }
1363
+ findPattern(_predicate) {
1364
+ return null;
1365
+ }
1366
+ clone(name = this._name, isOptional = this._isOptional) {
1367
+ return new Reference(name, isOptional);
1368
+ }
1369
+ }
1370
+
1371
+ const defaultOptions = { greedyPatternNames: [], customTokens: {} };
1372
+ class AutoComplete {
1373
+ constructor(pattern, options = defaultOptions) {
1374
+ this._pattern = pattern;
1375
+ this._options = options;
1376
+ this._text = "";
1377
+ }
1378
+ suggest(text) {
1379
+ if (text.length === 0) {
1380
+ return {
1381
+ isComplete: false,
1382
+ options: this.createSuggestionsFromRoot(),
1383
+ nextPatterns: [this._pattern],
1384
+ cursor: null,
1385
+ ast: null
1386
+ };
1387
+ }
1388
+ this._text = text;
1389
+ this._cursor = new Cursor(text);
1390
+ const ast = this._pattern.parse(this._cursor);
1391
+ const leafPattern = this._cursor.leafMatch.pattern;
1392
+ const isComplete = (ast === null || ast === void 0 ? void 0 : ast.value) === text;
1393
+ const options = this.createSuggestionsFromTokens();
1394
+ let nextPatterns = [this._pattern];
1395
+ if (leafPattern != null) {
1396
+ nextPatterns = leafPattern.getNextPatterns();
1397
+ }
1398
+ return {
1399
+ isComplete: isComplete,
1400
+ options: options,
1401
+ nextPatterns,
1402
+ cursor: this._cursor,
1403
+ ast,
1404
+ };
1405
+ }
1406
+ createSuggestionsFromRoot() {
1407
+ const suggestions = [];
1408
+ const tokens = this._pattern.getTokens();
1409
+ for (const token of tokens) {
1410
+ suggestions.push(this.createSuggestion("", token));
1411
+ }
1412
+ return suggestions;
1413
+ }
1414
+ createSuggestionsFromTokens() {
1415
+ const leafMatch = this._cursor.leafMatch;
1416
+ if (!leafMatch.pattern) {
1417
+ return this.createSuggestions(-1, this._getTokensForPattern(this._pattern));
1418
+ }
1419
+ const leafPattern = leafMatch.pattern;
1420
+ leafMatch.node;
1421
+ const parent = leafMatch.pattern.parent;
1422
+ if (parent !== null && leafMatch.node != null) {
1423
+ const patterns = leafPattern.getNextPatterns();
1424
+ const tokens = patterns.reduce((acc, pattern) => {
1425
+ acc.push(...this._getTokensForPattern(pattern));
1426
+ return acc;
1427
+ }, []);
1428
+ return this.createSuggestions(leafMatch.node.lastIndex, tokens);
1429
+ }
1430
+ else {
1431
+ return [];
1432
+ }
1433
+ }
1434
+ _getTokensForPattern(pattern) {
1435
+ if (this._options.greedyPatternNames.includes(pattern.name)) {
1436
+ const greedyTokens = pattern.getTokens();
1437
+ const nextPatterns = pattern.getNextPatterns();
1438
+ const tokens = [];
1439
+ const nextPatternTokens = nextPatterns.reduce((acc, pattern) => {
1440
+ acc.push(...this._getTokensForPattern(pattern));
1441
+ return acc;
1442
+ }, []);
1443
+ for (let token of greedyTokens) {
1444
+ for (let nextPatternToken of nextPatternTokens) {
1445
+ tokens.push(token + nextPatternToken);
1446
+ }
1447
+ }
1448
+ return tokens;
1449
+ }
1450
+ else {
1451
+ const tokens = pattern.getTokens();
1452
+ const customTokens = this._options.customTokens[pattern.name] || [];
1453
+ tokens.push(...customTokens);
1454
+ return tokens;
1455
+ }
1456
+ }
1457
+ createSuggestions(lastIndex, tokens) {
1458
+ let substring = lastIndex === -1 ? "" : this._cursor.getChars(0, lastIndex);
1459
+ const suggestionStrings = [];
1460
+ const options = [];
1461
+ for (const token of tokens) {
1462
+ const suggestion = substring + token;
1463
+ const startsWith = suggestion.startsWith(substring);
1464
+ const alreadyExist = suggestionStrings.includes(suggestion);
1465
+ const isSameAsText = suggestion === this._text;
1466
+ if (startsWith && !alreadyExist && !isSameAsText) {
1467
+ suggestionStrings.push(suggestion);
1468
+ options.push(this.createSuggestion(this._cursor.text, suggestion));
1469
+ }
1470
+ }
1471
+ const reducedOptions = getFurthestOptions(options);
1472
+ reducedOptions.sort((a, b) => a.text.localeCompare(b.text));
1473
+ return reducedOptions;
1474
+ }
1475
+ createSuggestion(fullText, suggestion) {
1476
+ const furthestMatch = findMatchIndex(suggestion, fullText);
1477
+ const text = suggestion.slice(furthestMatch);
1478
+ return {
1479
+ text: text,
1480
+ startIndex: furthestMatch,
1481
+ };
1482
+ }
1483
+ }
1484
+ function findMatchIndex(str1, str2) {
1485
+ let matchCount = 0;
1486
+ let minLength = str1.length;
1487
+ if (str2.length < minLength) {
1488
+ minLength = str2.length;
1489
+ }
1490
+ for (let i = 0; i < minLength; i++) {
1491
+ if (str1[i] === str2[i]) {
1492
+ matchCount++;
1493
+ }
1494
+ else {
1495
+ break;
1496
+ }
1497
+ }
1498
+ return matchCount;
1499
+ }
1500
+ function getFurthestOptions(options) {
1501
+ let furthestOptions = [];
1502
+ let furthestIndex = -1;
1503
+ for (const option of options) {
1504
+ if (option.startIndex > furthestIndex) {
1505
+ furthestIndex = option.startIndex;
1506
+ furthestOptions = [];
1507
+ }
1508
+ if (option.startIndex === furthestIndex) {
1509
+ furthestOptions.push(option);
1510
+ }
1511
+ }
1512
+ return furthestOptions;
1250
1513
  }
1251
1514
 
1252
1515
  exports.And = And;
1516
+ exports.AutoComplete = AutoComplete;
1253
1517
  exports.Cursor = Cursor;
1518
+ exports.CursorHistory = CursorHistory;
1254
1519
  exports.Literal = Literal;
1255
1520
  exports.Node = Node;
1256
1521
  exports.Not = Not;