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
@@ -29,6 +29,9 @@
29
29
  get children() {
30
30
  return this._children;
31
31
  }
32
+ get hasChildren() {
33
+ return this._children.length > 0;
34
+ }
32
35
  get value() {
33
36
  return this.toString();
34
37
  }
@@ -78,22 +81,54 @@
78
81
  }
79
82
  spliceChildren(index, deleteCount, ...items) {
80
83
  const removedItems = this._children.splice(index, deleteCount, ...items);
81
- items.forEach(i => i._parent = this);
82
84
  removedItems.forEach(i => i._parent = null);
85
+ items.forEach(i => i._parent = this);
83
86
  return removedItems;
84
87
  }
85
- find(isMatch) {
86
- return this.findAll(isMatch)[0] || null;
88
+ nextSibling() {
89
+ if (this._parent == null) {
90
+ return null;
91
+ }
92
+ const children = this._parent._children;
93
+ const index = children.indexOf(this);
94
+ if (index > -1 && index < children.length - 1) {
95
+ return children[index + 1];
96
+ }
97
+ return null;
98
+ }
99
+ previousSibling() {
100
+ if (this._parent == null) {
101
+ return null;
102
+ }
103
+ const children = this._parent._children;
104
+ const index = children.indexOf(this);
105
+ if (index > -1 && index > 0) {
106
+ return children[index - 1];
107
+ }
108
+ return null;
87
109
  }
88
- findAll(isMatch) {
110
+ find(predicate) {
111
+ return this.findAll(predicate)[0] || null;
112
+ }
113
+ findAll(predicate) {
89
114
  const matches = [];
90
115
  this.walkUp(n => {
91
- if (isMatch(n)) {
116
+ if (predicate(n)) {
92
117
  matches.push(n);
93
118
  }
94
119
  });
95
120
  return matches;
96
121
  }
122
+ findAncester(predicate) {
123
+ let parent = this._parent;
124
+ while (parent != null) {
125
+ if (predicate(parent)) {
126
+ return parent;
127
+ }
128
+ parent = parent._parent;
129
+ }
130
+ return null;
131
+ }
97
132
  walkUp(callback) {
98
133
  this.children.forEach(c => c.walkUp(callback));
99
134
  callback(this);
@@ -102,6 +137,20 @@
102
137
  callback(this);
103
138
  this.children.forEach(c => c.walkDown(callback));
104
139
  }
140
+ flatten() {
141
+ const nodes = [];
142
+ this.walkDown((node) => {
143
+ if (!node.hasChildren) {
144
+ nodes.push(node);
145
+ }
146
+ });
147
+ return nodes;
148
+ }
149
+ reduce() {
150
+ const value = this.toString();
151
+ this.removeAllChildren();
152
+ this._value = value;
153
+ }
105
154
  clone() {
106
155
  return new Node(this._type, this._name, this._firstIndex, this._lastIndex, this._children.map((c) => c.clone()), this._value);
107
156
  }
@@ -146,15 +195,18 @@
146
195
  this._nodes = [];
147
196
  this._errors = [];
148
197
  }
198
+ get isRecording() {
199
+ return this._isRecording;
200
+ }
201
+ get rootMatch() {
202
+ return this._rootMatch;
203
+ }
149
204
  get leafMatch() {
150
205
  return this._leafMatch;
151
206
  }
152
207
  get furthestError() {
153
208
  return this._furthestError;
154
209
  }
155
- get isRecording() {
156
- return this._isRecording;
157
- }
158
210
  get errors() {
159
211
  return this._errors;
160
212
  }
@@ -167,9 +219,6 @@
167
219
  get patterns() {
168
220
  return this._patterns;
169
221
  }
170
- get rootMatch() {
171
- return this._rootMatch;
172
- }
173
222
  recordMatch(pattern, node) {
174
223
  if (this._isRecording) {
175
224
  this._patterns.push(pattern);
@@ -212,17 +261,17 @@
212
261
  return this._index === 0;
213
262
  }
214
263
  get isOnLast() {
215
- return this._index === this._getLastIndex();
264
+ return this._index === this.getLastIndex();
216
265
  }
217
266
  get isRecording() {
218
267
  return this._history.isRecording;
219
268
  }
220
- get leafMatch() {
221
- return this._history.leafMatch;
222
- }
223
269
  get rootMatch() {
224
270
  return this._history.rootMatch;
225
271
  }
272
+ get leafMatch() {
273
+ return this._history.leafMatch;
274
+ }
226
275
  get furthestError() {
227
276
  return this._history.furthestError;
228
277
  }
@@ -253,14 +302,14 @@
253
302
  hasNext() {
254
303
  return this._index + 1 < this._length;
255
304
  }
256
- hasPrevious() {
257
- return this._index - 1 >= 0;
258
- }
259
305
  next() {
260
306
  if (this.hasNext()) {
261
307
  this._index++;
262
308
  }
263
309
  }
310
+ hasPrevious() {
311
+ return this._index - 1 >= 0;
312
+ }
264
313
  previous() {
265
314
  if (this.hasPrevious()) {
266
315
  this._index--;
@@ -275,7 +324,10 @@
275
324
  this._index = 0;
276
325
  }
277
326
  moveToLastChar() {
278
- this._index = this._getLastIndex();
327
+ this._index = this.getLastIndex();
328
+ }
329
+ getLastIndex() {
330
+ return this._length - 1;
279
331
  }
280
332
  getChars(first, last) {
281
333
  return this._text.slice(first, last + 1);
@@ -295,22 +347,6 @@
295
347
  stopRecording() {
296
348
  this._history.stopRecording();
297
349
  }
298
- _getLastIndex() {
299
- return this._length - 1;
300
- }
301
- }
302
-
303
- function getNextPattern(pattern) {
304
- const parent = pattern.parent;
305
- if (parent == null) {
306
- return null;
307
- }
308
- const patternIndex = parent.children.indexOf(pattern);
309
- const nextPattern = parent.children[patternIndex + 1] || null;
310
- if (nextPattern == null) {
311
- return parent.getNextPattern();
312
- }
313
- return nextPattern;
314
350
  }
315
351
 
316
352
  class Regex {
@@ -337,8 +373,6 @@
337
373
  this._cursor = null;
338
374
  this._substring = "";
339
375
  this._tokens = [];
340
- this._hasContextualTokenAggregation = false;
341
- this._isRetrievingContextualTokens = false;
342
376
  this._type = "regex";
343
377
  this._name = name;
344
378
  this._isOptional = isOptional;
@@ -358,11 +392,16 @@
358
392
  throw new Error("Invalid Arguments: The regex string cannot end with a '$' because it is expected to be in the middle of a string.");
359
393
  }
360
394
  }
361
- parseText(text) {
395
+ test(text) {
396
+ const cursor = new Cursor(text);
397
+ const ast = this.parse(cursor);
398
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
399
+ }
400
+ exec(text) {
362
401
  const cursor = new Cursor(text);
363
402
  const ast = this.parse(cursor);
364
403
  return {
365
- ast,
404
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
366
405
  cursor
367
406
  };
368
407
  }
@@ -389,7 +428,7 @@
389
428
  processResult(cursor, result) {
390
429
  const currentIndex = cursor.index;
391
430
  const newIndex = currentIndex + result[0].length - 1;
392
- this._node = new Node("regex", this._name, currentIndex, newIndex, [], result[0]);
431
+ this._node = new Node("regex", this._name, currentIndex, newIndex, undefined, result[0]);
393
432
  cursor.moveTo(newIndex);
394
433
  cursor.recordMatch(this, this._node);
395
434
  }
@@ -402,47 +441,35 @@
402
441
  clone(name = this._name, isOptional = this._isOptional) {
403
442
  const pattern = new Regex(name, this._originalRegexString, isOptional);
404
443
  pattern._tokens = this._tokens.slice();
405
- pattern._hasContextualTokenAggregation =
406
- this._hasContextualTokenAggregation;
407
444
  return pattern;
408
445
  }
409
446
  getTokens() {
410
- const parent = this._parent;
411
- if (this._hasContextualTokenAggregation &&
412
- parent != null &&
413
- !this._isRetrievingContextualTokens) {
414
- this._isRetrievingContextualTokens = true;
415
- const tokens = this._tokens;
416
- const aggregateTokens = [];
417
- const nextTokens = parent.getNextTokens(this);
418
- for (let nextToken of nextTokens) {
419
- for (let token of tokens) {
420
- aggregateTokens.push(token + nextToken);
421
- }
422
- }
423
- this._isRetrievingContextualTokens = false;
424
- return aggregateTokens;
425
- }
426
447
  return this._tokens;
427
448
  }
428
- getNextTokens(_reference) {
449
+ getTokensAfter(_childReference) {
429
450
  return [];
430
451
  }
431
- getNextPattern() {
432
- return getNextPattern(this);
452
+ getNextTokens() {
453
+ if (this.parent == null) {
454
+ return [];
455
+ }
456
+ return this.parent.getTokensAfter(this);
457
+ }
458
+ getPatternsAfter(_childReference) {
459
+ return [];
460
+ }
461
+ getNextPatterns() {
462
+ if (this.parent == null) {
463
+ return [];
464
+ }
465
+ return this.parent.getPatternsAfter(this);
433
466
  }
434
- findPattern(_isMatch) {
467
+ findPattern(_predicate) {
435
468
  return null;
436
469
  }
437
470
  setTokens(tokens) {
438
471
  this._tokens = tokens;
439
472
  }
440
- enableContextualTokenAggregation() {
441
- this._hasContextualTokenAggregation = true;
442
- }
443
- disableContextualTokenAggregation() {
444
- this._hasContextualTokenAggregation = false;
445
- }
446
473
  }
447
474
 
448
475
  function clonePatterns(patterns, isOptional) {
@@ -512,7 +539,6 @@
512
539
  this._parent = null;
513
540
  this._children = children;
514
541
  this._firstIndex = -1;
515
- this._shouldReduceAst = false;
516
542
  this._nodes = [];
517
543
  }
518
544
  _assignChildrenToParent(children) {
@@ -520,11 +546,16 @@
520
546
  child.parent = this;
521
547
  }
522
548
  }
523
- parseText(text) {
549
+ test(text) {
550
+ const cursor = new Cursor(text);
551
+ const ast = this.parse(cursor);
552
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
553
+ }
554
+ exec(text) {
524
555
  const cursor = new Cursor(text);
525
556
  const ast = this.parse(cursor);
526
557
  return {
527
- ast,
558
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
528
559
  cursor
529
560
  };
530
561
  }
@@ -558,34 +589,43 @@
558
589
  if (hasMorePatterns) {
559
590
  if (hadMatch) {
560
591
  if (cursor.hasNext()) {
592
+ // We had a match. Increment the cursor and use the next pattern.
561
593
  cursor.next();
562
594
  continue;
563
595
  }
564
596
  else {
597
+ // We are at the end of the text, it may still be valid, if all the
598
+ // following patterns are optional.
565
599
  if (this.areRemainingPatternsOptional(i)) {
566
600
  passed = true;
567
601
  break;
568
602
  }
603
+ // We didn't finish the parsing sequence.
569
604
  cursor.recordErrorAt(cursor.index + 1, this);
570
605
  break;
571
606
  }
572
607
  }
573
608
  else {
609
+ // An optional pattern did not matched, try from the same spot on the next
610
+ // pattern.
574
611
  cursor.moveTo(runningCursorIndex);
575
612
  continue;
576
613
  }
577
614
  }
578
615
  else {
616
+ // If we don't have any results from what we parsed then record error.
579
617
  const lastNode = this.getLastValidNode();
580
618
  if (lastNode === null) {
581
619
  cursor.recordErrorAt(cursor.index, this);
582
620
  break;
583
621
  }
622
+ // The sequence was parsed fully.
584
623
  passed = true;
585
624
  break;
586
625
  }
587
626
  }
588
627
  else {
628
+ // The pattern failed.
589
629
  cursor.moveTo(this._firstIndex);
590
630
  break;
591
631
  }
@@ -613,18 +653,9 @@
613
653
  createNode(cursor) {
614
654
  const children = filterOutNull(this._nodes);
615
655
  const lastIndex = children[children.length - 1].lastIndex;
616
- const value = cursor.getChars(this._firstIndex, lastIndex);
656
+ cursor.getChars(this._firstIndex, lastIndex);
617
657
  cursor.moveTo(lastIndex);
618
- if (this._shouldReduceAst) {
619
- children.length = 0;
620
- }
621
- return new Node("and", this._name, this._firstIndex, lastIndex, children, this._shouldReduceAst ? value : undefined);
622
- }
623
- enableAstReduction() {
624
- this._shouldReduceAst = true;
625
- }
626
- disableAstReduction() {
627
- this._shouldReduceAst = false;
658
+ return new Node("and", this._name, this._firstIndex, lastIndex, children);
628
659
  }
629
660
  getTokens() {
630
661
  const tokens = [];
@@ -636,13 +667,25 @@
636
667
  }
637
668
  return tokens;
638
669
  }
639
- getNextTokens(lastMatched) {
670
+ getTokensAfter(childReference) {
671
+ const patterns = this.getPatternsAfter(childReference);
672
+ const tokens = [];
673
+ patterns.forEach(p => tokens.push(...p.getTokens()));
674
+ return tokens;
675
+ }
676
+ getNextTokens() {
677
+ if (this.parent == null) {
678
+ return [];
679
+ }
680
+ return this.parent.getTokensAfter(this);
681
+ }
682
+ getPatternsAfter(childReference) {
640
683
  let nextSibling = null;
641
684
  let nextSiblingIndex = -1;
642
685
  let index = -1;
643
- const tokens = [];
686
+ const patterns = [];
644
687
  for (let i = 0; i < this._children.length; i++) {
645
- if (this._children[i] === lastMatched) {
688
+ if (this._children[i] === childReference) {
646
689
  if (i + 1 < this._children.length) {
647
690
  nextSibling = this._children[i + 1];
648
691
  }
@@ -651,39 +694,44 @@
651
694
  break;
652
695
  }
653
696
  }
697
+ // The child reference isn't one of the child patterns.
654
698
  if (index === -1) {
655
699
  return [];
656
700
  }
701
+ // The reference pattern is the last child. So ask the parent for the next pattern.
657
702
  if (nextSiblingIndex === this._children.length && this._parent !== null) {
658
- return this._parent.getNextTokens(this);
703
+ return this._parent.getPatternsAfter(this);
659
704
  }
705
+ // Next pattern isn't optional so send it back as the next patterns.
660
706
  if (nextSibling !== null && !nextSibling.isOptional) {
661
- return nextSibling.getTokens();
707
+ return [nextSibling];
662
708
  }
709
+ // Send back as many optional patterns as possible.
663
710
  if (nextSibling !== null && nextSibling.isOptional) {
664
711
  for (let i = nextSiblingIndex; i < this._children.length; i++) {
665
712
  const child = this._children[i];
666
- tokens.push(...child.getTokens());
713
+ patterns.push(child);
667
714
  if (!child.isOptional) {
668
715
  break;
669
716
  }
670
717
  if (i === this._children.length - 1 && this._parent !== null) {
671
- tokens.push(...this._parent.getNextTokens(this));
718
+ patterns.push(...this._parent.getPatternsAfter(this));
672
719
  }
673
720
  }
674
721
  }
675
- return tokens;
722
+ return patterns;
676
723
  }
677
- getNextPattern() {
678
- return getNextPattern(this);
724
+ getNextPatterns() {
725
+ if (this.parent == null) {
726
+ return [];
727
+ }
728
+ return this.parent.getPatternsAfter(this);
679
729
  }
680
- findPattern(isMatch) {
681
- return findPattern(this, isMatch);
730
+ findPattern(predicate) {
731
+ return findPattern(this, predicate);
682
732
  }
683
733
  clone(name = this._name, isOptional = this._isOptional) {
684
- const and = new And(name, this._children, isOptional);
685
- and._shouldReduceAst = this._shouldReduceAst;
686
- return and;
734
+ return new And(name, this._children, isOptional);
687
735
  }
688
736
  }
689
737
 
@@ -718,14 +766,17 @@
718
766
  this._parent = null;
719
767
  this._firstIndex = 0;
720
768
  this._lastIndex = 0;
721
- this._hasContextualTokenAggregation = false;
722
- this._isRetrievingContextualTokens = false;
723
769
  }
724
- parseText(text) {
770
+ test(text) {
771
+ const cursor = new Cursor(text);
772
+ const ast = this.parse(cursor);
773
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
774
+ }
775
+ exec(text) {
725
776
  const cursor = new Cursor(text);
726
777
  const ast = this.parse(cursor);
727
778
  return {
728
- ast,
779
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
729
780
  cursor
730
781
  };
731
782
  }
@@ -768,45 +819,35 @@
768
819
  return passed;
769
820
  }
770
821
  _createNode() {
771
- return new Node("literal", this._name, this._firstIndex, this._lastIndex, [], this._literal);
822
+ return new Node("literal", this._name, this._firstIndex, this._lastIndex, undefined, this._literal);
772
823
  }
773
824
  clone(name = this._name, isOptional = this._isOptional) {
774
825
  const clone = new Literal(name, this._literal, isOptional);
775
- clone._hasContextualTokenAggregation = this._hasContextualTokenAggregation;
776
826
  return clone;
777
827
  }
778
828
  getTokens() {
779
- const parent = this._parent;
780
- if (this._hasContextualTokenAggregation &&
781
- parent != null &&
782
- !this._isRetrievingContextualTokens) {
783
- this._isRetrievingContextualTokens = true;
784
- const aggregateTokens = [];
785
- const nextTokens = parent.getNextTokens(this);
786
- for (const nextToken of nextTokens) {
787
- aggregateTokens.push(this._literal + nextToken);
788
- }
789
- this._isRetrievingContextualTokens = false;
790
- return aggregateTokens;
791
- }
792
- else {
793
- return [this._literal];
794
- }
829
+ return [this._literal];
795
830
  }
796
- getNextTokens(_lastMatched) {
831
+ getTokensAfter(_lastMatched) {
797
832
  return [];
798
833
  }
799
- getNextPattern() {
800
- return getNextPattern(this);
834
+ getNextTokens() {
835
+ if (this.parent == null) {
836
+ return [];
837
+ }
838
+ return this.parent.getTokensAfter(this);
801
839
  }
802
- findPattern(_isMatch) {
803
- return null;
840
+ getPatternsAfter() {
841
+ return [];
804
842
  }
805
- enableContextualTokenAggregation() {
806
- this._hasContextualTokenAggregation = true;
843
+ getNextPatterns() {
844
+ if (this.parent == null) {
845
+ return [];
846
+ }
847
+ return this.parent.getPatternsAfter(this);
807
848
  }
808
- disableContextualTokenAggregation() {
809
- this._hasContextualTokenAggregation = false;
849
+ findPattern(_predicate) {
850
+ return null;
810
851
  }
811
852
  }
812
853
 
@@ -817,9 +858,6 @@
817
858
  get name() {
818
859
  return this._name;
819
860
  }
820
- get isOptional() {
821
- return false;
822
- }
823
861
  get parent() {
824
862
  return this._parent;
825
863
  }
@@ -829,6 +867,9 @@
829
867
  get children() {
830
868
  return this._children;
831
869
  }
870
+ get isOptional() {
871
+ return false;
872
+ }
832
873
  constructor(name, pattern) {
833
874
  this._type = "not";
834
875
  this._name = name;
@@ -836,7 +877,12 @@
836
877
  this._children = [pattern.clone(pattern.name, false)];
837
878
  this._children[0].parent = this;
838
879
  }
839
- parseText(text) {
880
+ test(text) {
881
+ const cursor = new Cursor(text);
882
+ this.parse(cursor);
883
+ return !cursor.hasError;
884
+ }
885
+ exec(text) {
840
886
  const cursor = new Cursor(text);
841
887
  const ast = this.parse(cursor);
842
888
  return {
@@ -862,17 +908,41 @@
862
908
  const not = new Not(name, this._children[0]);
863
909
  return not;
864
910
  }
865
- getNextPattern() {
866
- return getNextPattern(this);
867
- }
868
911
  getTokens() {
912
+ const parent = this._parent;
913
+ if (parent != null) {
914
+ return parent.getTokensAfter(this);
915
+ }
869
916
  return [];
870
917
  }
871
- getNextTokens(_lastMatched) {
918
+ getTokensAfter(_childReference) {
919
+ const parent = this._parent;
920
+ if (parent != null) {
921
+ return parent.getTokensAfter(this);
922
+ }
872
923
  return [];
873
924
  }
874
- findPattern(isMatch) {
875
- return isMatch(this._children[0]) ? this._children[0] : null;
925
+ getNextTokens() {
926
+ if (this.parent == null) {
927
+ return [];
928
+ }
929
+ return this.parent.getTokensAfter(this);
930
+ }
931
+ getPatternsAfter(_childReference) {
932
+ const parent = this._parent;
933
+ if (parent != null) {
934
+ return parent.getPatternsAfter(this);
935
+ }
936
+ return [];
937
+ }
938
+ getNextPatterns() {
939
+ if (this.parent == null) {
940
+ return [];
941
+ }
942
+ return this.parent.getPatternsAfter(this);
943
+ }
944
+ findPattern(predicate) {
945
+ return predicate(this._children[0]) ? this._children[0] : null;
876
946
  }
877
947
  }
878
948
 
@@ -906,7 +976,6 @@
906
976
  this._parent = null;
907
977
  this._children = children;
908
978
  this._isOptional = isOptional;
909
- this._node = null;
910
979
  this._firstIndex = 0;
911
980
  }
912
981
  _assignChildrenToParent(children) {
@@ -914,17 +983,21 @@
914
983
  child.parent = this;
915
984
  }
916
985
  }
917
- parseText(text) {
986
+ test(text) {
987
+ const cursor = new Cursor(text);
988
+ const ast = this.parse(cursor);
989
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
990
+ }
991
+ exec(text) {
918
992
  const cursor = new Cursor(text);
919
993
  const ast = this.parse(cursor);
920
994
  return {
921
- ast,
995
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
922
996
  cursor
923
997
  };
924
998
  }
925
999
  parse(cursor) {
926
1000
  this._firstIndex = cursor.index;
927
- this._node = null;
928
1001
  const node = this._tryToParse(cursor);
929
1002
  if (node != null) {
930
1003
  cursor.resolveError();
@@ -956,17 +1029,32 @@
956
1029
  }
957
1030
  return tokens;
958
1031
  }
959
- getNextTokens(_lastMatched) {
1032
+ getTokensAfter(_childReference) {
960
1033
  if (this._parent === null) {
961
1034
  return [];
962
1035
  }
963
- return this._parent.getNextTokens(this);
1036
+ return this._parent.getTokensAfter(this);
964
1037
  }
965
- getNextPattern() {
966
- return getNextPattern(this);
1038
+ getNextTokens() {
1039
+ if (this._parent == null) {
1040
+ return [];
1041
+ }
1042
+ return this._parent.getTokensAfter(this);
1043
+ }
1044
+ getPatternsAfter(_childReference) {
1045
+ if (this._parent === null) {
1046
+ return [];
1047
+ }
1048
+ return this._parent.getPatternsAfter(this);
1049
+ }
1050
+ getNextPatterns() {
1051
+ if (this.parent == null) {
1052
+ return [];
1053
+ }
1054
+ return this.parent.getPatternsAfter(this);
967
1055
  }
968
- findPattern(isMatch) {
969
- return findPattern(this, isMatch);
1056
+ findPattern(predicate) {
1057
+ return findPattern(this, predicate);
970
1058
  }
971
1059
  clone(name = this._name, isOptional = this._isOptional) {
972
1060
  const or = new Or(name, this._children, isOptional);
@@ -1005,7 +1093,6 @@
1005
1093
  this._pattern = children[0];
1006
1094
  this._divider = children[1];
1007
1095
  this._firstIndex = -1;
1008
- this._shouldReduceAst = false;
1009
1096
  this._nodes = [];
1010
1097
  }
1011
1098
  _assignChildrenToParent(children) {
@@ -1013,11 +1100,16 @@
1013
1100
  child.parent = this;
1014
1101
  }
1015
1102
  }
1016
- parseText(text) {
1103
+ test(text) {
1104
+ const cursor = new Cursor(text);
1105
+ const ast = this.parse(cursor);
1106
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
1107
+ }
1108
+ exec(text) {
1017
1109
  const cursor = new Cursor(text);
1018
1110
  const ast = this.parse(cursor);
1019
1111
  return {
1020
- ast,
1112
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
1021
1113
  cursor
1022
1114
  };
1023
1115
  }
@@ -1028,7 +1120,7 @@
1028
1120
  if (passed) {
1029
1121
  cursor.resolveError();
1030
1122
  const node = this.createNode(cursor);
1031
- if (node) {
1123
+ if (node != null) {
1032
1124
  cursor.recordMatch(this, node);
1033
1125
  }
1034
1126
  return node;
@@ -1047,7 +1139,7 @@
1047
1139
  const repeatedNode = this._pattern.parse(cursor);
1048
1140
  if (cursor.hasError) {
1049
1141
  const lastValidNode = this.getLastValidNode();
1050
- if (lastValidNode) {
1142
+ if (lastValidNode != null) {
1051
1143
  passed = true;
1052
1144
  }
1053
1145
  else {
@@ -1064,13 +1156,13 @@
1064
1156
  break;
1065
1157
  }
1066
1158
  cursor.next();
1067
- if (this._divider) {
1159
+ if (this._divider != null) {
1068
1160
  const dividerNode = this._divider.parse(cursor);
1069
1161
  if (cursor.hasError) {
1070
1162
  passed = true;
1071
1163
  break;
1072
1164
  }
1073
- else if (dividerNode) {
1165
+ else if (dividerNode != null) {
1074
1166
  this._nodes.push(dividerNode);
1075
1167
  if (!cursor.hasNext()) {
1076
1168
  passed = true;
@@ -1099,12 +1191,9 @@
1099
1191
  }
1100
1192
  }
1101
1193
  const lastIndex = children[children.length - 1].lastIndex;
1102
- const value = cursor.getChars(this._firstIndex, lastIndex);
1194
+ cursor.getChars(this._firstIndex, lastIndex);
1103
1195
  cursor.moveTo(lastIndex);
1104
- if (this._shouldReduceAst) {
1105
- children = [];
1106
- }
1107
- return new Node("repeat", this._name, this._firstIndex, lastIndex, children, this._shouldReduceAst ? value : undefined);
1196
+ return new Node("repeat", this._name, this._firstIndex, lastIndex, children, undefined);
1108
1197
  }
1109
1198
  getLastValidNode() {
1110
1199
  const nodes = this._nodes.filter((node) => node !== null);
@@ -1113,51 +1202,61 @@
1113
1202
  }
1114
1203
  return nodes[nodes.length - 1];
1115
1204
  }
1116
- enableAstReduction() {
1117
- this._shouldReduceAst = true;
1118
- }
1119
- disableAstReduction() {
1120
- this._shouldReduceAst = false;
1121
- }
1122
1205
  getTokens() {
1123
1206
  return this._pattern.getTokens();
1124
1207
  }
1125
- getNextTokens(lastMatched) {
1126
- let index = -1;
1208
+ getTokensAfter(childReference) {
1209
+ const patterns = this.getPatternsAfter(childReference);
1127
1210
  const tokens = [];
1211
+ patterns.forEach(p => tokens.push(...p.getTokens()));
1212
+ return tokens;
1213
+ }
1214
+ getNextTokens() {
1215
+ if (this.parent == null) {
1216
+ return [];
1217
+ }
1218
+ return this.parent.getTokensAfter(this);
1219
+ }
1220
+ getPatternsAfter(childReference) {
1221
+ let index = -1;
1222
+ const patterns = [];
1128
1223
  for (let i = 0; i < this._children.length; i++) {
1129
- if (this._children[i] === lastMatched) {
1224
+ if (this._children[i] === childReference) {
1130
1225
  index = i;
1131
1226
  }
1132
1227
  }
1228
+ // If the last match isn't a child of this pattern.
1133
1229
  if (index === -1) {
1134
1230
  return [];
1135
1231
  }
1232
+ // If the last match was the repeated patterns, then suggest the divider.
1136
1233
  if (index === 0 && this._divider) {
1137
- tokens.push(...this._children[1].getTokens());
1234
+ patterns.push(this._children[1]);
1138
1235
  if (this._parent) {
1139
- tokens.push(...this._parent.getNextTokens(this));
1236
+ patterns.push(...this._parent.getPatternsAfter(this));
1140
1237
  }
1141
1238
  }
1239
+ // Suggest the pattern because the divider was the last match.
1142
1240
  if (index === 1) {
1143
- tokens.push(...this._children[0].getTokens());
1241
+ patterns.push(this._children[0]);
1144
1242
  }
1145
1243
  if (index === 0 && !this._divider && this._parent) {
1146
- tokens.push(...this._children[0].getTokens());
1147
- tokens.push(...this._parent.getNextTokens(this));
1244
+ patterns.push(this._children[0]);
1245
+ patterns.push(...this._parent.getPatternsAfter(this));
1148
1246
  }
1149
- return tokens;
1247
+ return patterns;
1150
1248
  }
1151
- getNextPattern() {
1152
- return getNextPattern(this);
1249
+ getNextPatterns() {
1250
+ if (this.parent == null) {
1251
+ return [];
1252
+ }
1253
+ return this.parent.getPatternsAfter(this);
1153
1254
  }
1154
- findPattern(isMatch) {
1155
- return findPattern(this, isMatch);
1255
+ findPattern(predicate) {
1256
+ return findPattern(this, predicate);
1156
1257
  }
1157
1258
  clone(name = this._name, isOptional = this._isOptional) {
1158
- const repeat = new Repeat(name, this._pattern, this._divider, isOptional);
1159
- repeat._shouldReduceAst = this._shouldReduceAst;
1160
- return repeat;
1259
+ return new Repeat(name, this._pattern, this._divider, isOptional);
1161
1260
  }
1162
1261
  }
1163
1262
 
@@ -1168,9 +1267,6 @@
1168
1267
  get name() {
1169
1268
  return this._name;
1170
1269
  }
1171
- get isOptional() {
1172
- return this._isOptional;
1173
- }
1174
1270
  get parent() {
1175
1271
  return this._parent;
1176
1272
  }
@@ -1180,6 +1276,9 @@
1180
1276
  get children() {
1181
1277
  return this._children;
1182
1278
  }
1279
+ get isOptional() {
1280
+ return this._isOptional;
1281
+ }
1183
1282
  constructor(name, isOptional = false) {
1184
1283
  this._type = "reference";
1185
1284
  this._name = name;
@@ -1188,35 +1287,22 @@
1188
1287
  this._pattern = null;
1189
1288
  this._children = [];
1190
1289
  }
1191
- parseText(text) {
1290
+ test(text) {
1291
+ const cursor = new Cursor(text);
1292
+ const ast = this.parse(cursor);
1293
+ return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
1294
+ }
1295
+ exec(text) {
1192
1296
  const cursor = new Cursor(text);
1193
1297
  const ast = this.parse(cursor);
1194
1298
  return {
1195
- ast,
1299
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
1196
1300
  cursor
1197
1301
  };
1198
1302
  }
1199
1303
  parse(cursor) {
1200
1304
  return this._getPatternSafely().parse(cursor);
1201
1305
  }
1202
- clone(name = this._name, isOptional = this._isOptional) {
1203
- return new Reference(name, isOptional);
1204
- }
1205
- getTokens() {
1206
- return this._getPatternSafely().getTokens();
1207
- }
1208
- getNextTokens(_lastMatched) {
1209
- if (this.parent == null) {
1210
- return [];
1211
- }
1212
- return this.parent.getNextTokens(this);
1213
- }
1214
- getNextPattern() {
1215
- return getNextPattern(this);
1216
- }
1217
- findPattern(_isMatch) {
1218
- return null;
1219
- }
1220
1306
  _getPatternSafely() {
1221
1307
  if (this._pattern === null) {
1222
1308
  const pattern = this._findPattern();
@@ -1249,10 +1335,189 @@
1249
1335
  }
1250
1336
  return node;
1251
1337
  }
1338
+ getTokens() {
1339
+ return this._getPatternSafely().getTokens();
1340
+ }
1341
+ getTokensAfter(_lastMatched) {
1342
+ if (this._parent == null) {
1343
+ return [];
1344
+ }
1345
+ return this._parent.getTokensAfter(this);
1346
+ }
1347
+ getNextTokens() {
1348
+ if (this.parent == null) {
1349
+ return [];
1350
+ }
1351
+ return this.parent.getTokensAfter(this);
1352
+ }
1353
+ getPatternsAfter(_childReference) {
1354
+ if (this._parent == null) {
1355
+ return [];
1356
+ }
1357
+ return this._parent.getPatternsAfter(this);
1358
+ }
1359
+ getNextPatterns() {
1360
+ if (this.parent == null) {
1361
+ return [];
1362
+ }
1363
+ return this.parent.getPatternsAfter(this);
1364
+ }
1365
+ findPattern(_predicate) {
1366
+ return null;
1367
+ }
1368
+ clone(name = this._name, isOptional = this._isOptional) {
1369
+ return new Reference(name, isOptional);
1370
+ }
1371
+ }
1372
+
1373
+ const defaultOptions = { greedyPatternNames: [], customTokens: {} };
1374
+ class AutoComplete {
1375
+ constructor(pattern, options = defaultOptions) {
1376
+ this._pattern = pattern;
1377
+ this._options = options;
1378
+ this._text = "";
1379
+ }
1380
+ suggest(text) {
1381
+ if (text.length === 0) {
1382
+ return {
1383
+ isComplete: false,
1384
+ options: this.createSuggestionsFromRoot(),
1385
+ nextPatterns: [this._pattern],
1386
+ cursor: null,
1387
+ ast: null
1388
+ };
1389
+ }
1390
+ this._text = text;
1391
+ this._cursor = new Cursor(text);
1392
+ const ast = this._pattern.parse(this._cursor);
1393
+ const leafPattern = this._cursor.leafMatch.pattern;
1394
+ const isComplete = (ast === null || ast === void 0 ? void 0 : ast.value) === text;
1395
+ const options = this.createSuggestionsFromTokens();
1396
+ let nextPatterns = [this._pattern];
1397
+ if (leafPattern != null) {
1398
+ nextPatterns = leafPattern.getNextPatterns();
1399
+ }
1400
+ return {
1401
+ isComplete: isComplete,
1402
+ options: options,
1403
+ nextPatterns,
1404
+ cursor: this._cursor,
1405
+ ast,
1406
+ };
1407
+ }
1408
+ createSuggestionsFromRoot() {
1409
+ const suggestions = [];
1410
+ const tokens = this._pattern.getTokens();
1411
+ for (const token of tokens) {
1412
+ suggestions.push(this.createSuggestion("", token));
1413
+ }
1414
+ return suggestions;
1415
+ }
1416
+ createSuggestionsFromTokens() {
1417
+ const leafMatch = this._cursor.leafMatch;
1418
+ if (!leafMatch.pattern) {
1419
+ return this.createSuggestions(-1, this._getTokensForPattern(this._pattern));
1420
+ }
1421
+ const leafPattern = leafMatch.pattern;
1422
+ leafMatch.node;
1423
+ const parent = leafMatch.pattern.parent;
1424
+ if (parent !== null && leafMatch.node != null) {
1425
+ const patterns = leafPattern.getNextPatterns();
1426
+ const tokens = patterns.reduce((acc, pattern) => {
1427
+ acc.push(...this._getTokensForPattern(pattern));
1428
+ return acc;
1429
+ }, []);
1430
+ return this.createSuggestions(leafMatch.node.lastIndex, tokens);
1431
+ }
1432
+ else {
1433
+ return [];
1434
+ }
1435
+ }
1436
+ _getTokensForPattern(pattern) {
1437
+ if (this._options.greedyPatternNames.includes(pattern.name)) {
1438
+ const greedyTokens = pattern.getTokens();
1439
+ const nextPatterns = pattern.getNextPatterns();
1440
+ const tokens = [];
1441
+ const nextPatternTokens = nextPatterns.reduce((acc, pattern) => {
1442
+ acc.push(...this._getTokensForPattern(pattern));
1443
+ return acc;
1444
+ }, []);
1445
+ for (let token of greedyTokens) {
1446
+ for (let nextPatternToken of nextPatternTokens) {
1447
+ tokens.push(token + nextPatternToken);
1448
+ }
1449
+ }
1450
+ return tokens;
1451
+ }
1452
+ else {
1453
+ const tokens = pattern.getTokens();
1454
+ const customTokens = this._options.customTokens[pattern.name] || [];
1455
+ tokens.push(...customTokens);
1456
+ return tokens;
1457
+ }
1458
+ }
1459
+ createSuggestions(lastIndex, tokens) {
1460
+ let substring = lastIndex === -1 ? "" : this._cursor.getChars(0, lastIndex);
1461
+ const suggestionStrings = [];
1462
+ const options = [];
1463
+ for (const token of tokens) {
1464
+ const suggestion = substring + token;
1465
+ const startsWith = suggestion.startsWith(substring);
1466
+ const alreadyExist = suggestionStrings.includes(suggestion);
1467
+ const isSameAsText = suggestion === this._text;
1468
+ if (startsWith && !alreadyExist && !isSameAsText) {
1469
+ suggestionStrings.push(suggestion);
1470
+ options.push(this.createSuggestion(this._cursor.text, suggestion));
1471
+ }
1472
+ }
1473
+ const reducedOptions = getFurthestOptions(options);
1474
+ reducedOptions.sort((a, b) => a.text.localeCompare(b.text));
1475
+ return reducedOptions;
1476
+ }
1477
+ createSuggestion(fullText, suggestion) {
1478
+ const furthestMatch = findMatchIndex(suggestion, fullText);
1479
+ const text = suggestion.slice(furthestMatch);
1480
+ return {
1481
+ text: text,
1482
+ startIndex: furthestMatch,
1483
+ };
1484
+ }
1485
+ }
1486
+ function findMatchIndex(str1, str2) {
1487
+ let matchCount = 0;
1488
+ let minLength = str1.length;
1489
+ if (str2.length < minLength) {
1490
+ minLength = str2.length;
1491
+ }
1492
+ for (let i = 0; i < minLength; i++) {
1493
+ if (str1[i] === str2[i]) {
1494
+ matchCount++;
1495
+ }
1496
+ else {
1497
+ break;
1498
+ }
1499
+ }
1500
+ return matchCount;
1501
+ }
1502
+ function getFurthestOptions(options) {
1503
+ let furthestOptions = [];
1504
+ let furthestIndex = -1;
1505
+ for (const option of options) {
1506
+ if (option.startIndex > furthestIndex) {
1507
+ furthestIndex = option.startIndex;
1508
+ furthestOptions = [];
1509
+ }
1510
+ if (option.startIndex === furthestIndex) {
1511
+ furthestOptions.push(option);
1512
+ }
1513
+ }
1514
+ return furthestOptions;
1252
1515
  }
1253
1516
 
1254
1517
  exports.And = And;
1518
+ exports.AutoComplete = AutoComplete;
1255
1519
  exports.Cursor = Cursor;
1520
+ exports.CursorHistory = CursorHistory;
1256
1521
  exports.Literal = Literal;
1257
1522
  exports.Node = Node;
1258
1523
  exports.Not = Not;