clarity-pattern-parser 8.4.15 → 9.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 (100) hide show
  1. package/TODO.md +4 -1
  2. package/dist/grammar/Grammar.d.ts +18 -10
  3. package/dist/grammar/patterns/andLiteral.d.ts +2 -0
  4. package/dist/grammar/patterns/anonymousPattern.d.ts +2 -0
  5. package/dist/grammar/patterns/inlinePattern.d.ts +1 -0
  6. package/dist/grammar/patterns/literals.d.ts +3 -0
  7. package/dist/grammar/patterns/pattern.d.ts +2 -2
  8. package/dist/grammar/patterns.d.ts +2 -0
  9. package/dist/index.browser.js +471 -184
  10. package/dist/index.browser.js.map +1 -1
  11. package/dist/index.d.ts +3 -1
  12. package/dist/index.esm.js +470 -185
  13. package/dist/index.esm.js.map +1 -1
  14. package/dist/index.js +471 -184
  15. package/dist/index.js.map +1 -1
  16. package/dist/patterns/And.d.ts +4 -1
  17. package/dist/patterns/Cursor.d.ts +5 -0
  18. package/dist/patterns/CursorHistory.d.ts +7 -0
  19. package/dist/patterns/FiniteRepeat.d.ts +4 -1
  20. package/dist/patterns/InfiniteRepeat.d.ts +5 -4
  21. package/dist/patterns/Literal.d.ts +6 -5
  22. package/dist/patterns/Not.d.ts +5 -4
  23. package/dist/patterns/Or.d.ts +5 -4
  24. package/dist/patterns/Pattern.d.ts +4 -2
  25. package/dist/patterns/Reference.d.ts +5 -4
  26. package/dist/patterns/Regex.d.ts +5 -4
  27. package/dist/patterns/Repeat.d.ts +3 -0
  28. package/dist/patterns/arePatternsEqual.d.ts +2 -0
  29. package/package.json +1 -1
  30. package/src/grammar/Grammar.test.ts +117 -74
  31. package/src/grammar/Grammar.ts +241 -158
  32. package/src/grammar/patterns/anonymousPattern.ts +23 -0
  33. package/src/grammar/patterns/body.ts +9 -6
  34. package/src/grammar/patterns/comment.ts +3 -2
  35. package/src/grammar/patterns/grammar.ts +15 -12
  36. package/src/grammar/patterns/import.ts +18 -12
  37. package/src/grammar/patterns/literal.ts +2 -1
  38. package/src/grammar/patterns/literals.ts +20 -0
  39. package/src/grammar/patterns/optionsLiteral.ts +19 -0
  40. package/src/grammar/patterns/pattern.ts +23 -9
  41. package/src/grammar/patterns/regexLiteral.ts +1 -0
  42. package/src/grammar/patterns/repeatLiteral.ts +30 -25
  43. package/src/grammar/patterns/sequenceLiteral.ts +24 -0
  44. package/src/grammar/patterns/spaces.ts +8 -6
  45. package/src/grammar/patterns/statement.ts +8 -20
  46. package/src/grammar/patterns.test.ts +38 -0
  47. package/src/grammar/patterns.ts +24 -0
  48. package/src/grammar/spec.md +4 -12
  49. package/src/index.ts +11 -5
  50. package/src/intellisense/AutoComplete.test.ts +41 -40
  51. package/src/intellisense/css/method.ts +2 -2
  52. package/src/intellisense/css/unit.ts +2 -2
  53. package/src/intellisense/css/value.ts +1 -1
  54. package/src/intellisense/javascript/Javascript.test.ts +31 -32
  55. package/src/intellisense/javascript/arrayLiteral.ts +7 -6
  56. package/src/intellisense/javascript/assignment.ts +6 -6
  57. package/src/intellisense/javascript/deleteStatement.ts +2 -2
  58. package/src/intellisense/javascript/escapedCharacter.ts +6 -6
  59. package/src/intellisense/javascript/exponent.ts +6 -6
  60. package/src/intellisense/javascript/expression.ts +18 -17
  61. package/src/intellisense/javascript/fraction.ts +3 -3
  62. package/src/intellisense/javascript/infixOperator.ts +10 -10
  63. package/src/intellisense/javascript/integer.ts +1 -1
  64. package/src/intellisense/javascript/invocation.ts +8 -7
  65. package/src/intellisense/javascript/literal.ts +3 -3
  66. package/src/intellisense/javascript/numberLiteral.ts +5 -4
  67. package/src/intellisense/javascript/objectAccess.ts +2 -3
  68. package/src/intellisense/javascript/objectLiteral.ts +8 -7
  69. package/src/intellisense/javascript/optionalSpaces.ts +2 -1
  70. package/src/intellisense/javascript/parameters.ts +5 -5
  71. package/src/intellisense/javascript/prefixOperator.ts +3 -4
  72. package/src/intellisense/javascript/propertyAccess.ts +9 -8
  73. package/src/intellisense/javascript/stringLiteral.ts +14 -15
  74. package/src/patterns/Cursor.ts +42 -4
  75. package/src/patterns/CursorHistory.ts +20 -4
  76. package/src/patterns/FiniteRepeat.test.ts +52 -51
  77. package/src/patterns/FiniteRepeat.ts +60 -38
  78. package/src/patterns/InfiniteRepeat.test.ts +36 -49
  79. package/src/patterns/InfiniteRepeat.ts +70 -37
  80. package/src/patterns/Literal.test.ts +16 -27
  81. package/src/patterns/Literal.ts +34 -27
  82. package/src/patterns/Not.test.ts +7 -7
  83. package/src/patterns/Not.ts +24 -6
  84. package/src/patterns/Optional.test.ts +164 -0
  85. package/src/patterns/Optional.ts +143 -0
  86. package/src/patterns/{Or.test.ts → Options.test.ts} +51 -49
  87. package/src/patterns/{Or.ts → Options.ts} +32 -23
  88. package/src/patterns/Pattern.ts +6 -5
  89. package/src/patterns/Reference.test.ts +21 -22
  90. package/src/patterns/Reference.ts +26 -15
  91. package/src/patterns/Regex.test.ts +15 -15
  92. package/src/patterns/Regex.ts +29 -19
  93. package/src/patterns/Repeat.test.ts +12 -22
  94. package/src/patterns/Repeat.ts +22 -21
  95. package/src/patterns/{And.test.ts → Sequence.test.ts} +78 -78
  96. package/src/patterns/{And.ts → Sequence.ts} +40 -29
  97. package/src/patterns/arePatternsEqual.ts +12 -0
  98. package/src/patterns/clonePatterns.ts +2 -2
  99. package/src/grammar/patterns/andLiteral.ts +0 -8
  100. package/src/grammar/patterns/orLiteral.ts +0 -8
@@ -249,6 +249,7 @@
249
249
  this._patterns = [];
250
250
  this._nodes = [];
251
251
  this._errors = [];
252
+ this._trace = [];
252
253
  }
253
254
  get isRecording() {
254
255
  return this._isRecording;
@@ -277,6 +278,9 @@
277
278
  get patterns() {
278
279
  return this._patterns;
279
280
  }
281
+ get trace() {
282
+ return this._trace;
283
+ }
280
284
  recordMatch(pattern, node) {
281
285
  if (this._isRecording) {
282
286
  this._patterns.push(pattern);
@@ -331,6 +335,11 @@
331
335
  resolveError() {
332
336
  this._currentError = null;
333
337
  }
338
+ pushStackTrace(trace) {
339
+ if (this._isRecording) {
340
+ this._trace.push(trace);
341
+ }
342
+ }
334
343
  }
335
344
 
336
345
  class Cursor {
@@ -387,6 +396,7 @@
387
396
  this._index = 0;
388
397
  this._length = text.length;
389
398
  this._history = new CursorHistory();
399
+ this._stackTrace = [];
390
400
  }
391
401
  hasNext() {
392
402
  return this._index + 1 < this._length;
@@ -436,9 +446,42 @@
436
446
  stopRecording() {
437
447
  this._history.stopRecording();
438
448
  }
449
+ startParseWith(pattern) {
450
+ const patternName = pattern.name;
451
+ const trace = {
452
+ pattern,
453
+ cursorIndex: this.index
454
+ };
455
+ if (this._stackTrace.find(t => t.pattern.id === pattern.id && this.index === t.cursorIndex)) {
456
+ throw new Error(`Cyclical Pattern: ${this._stackTrace.map(t => `${t.pattern.name}#${t.pattern.id}{${t.cursorIndex}}`).join(" -> ")} -> ${patternName}#${pattern.id}{${this.index}}.`);
457
+ }
458
+ this._history.pushStackTrace(trace);
459
+ this._stackTrace.push(trace);
460
+ }
461
+ endParse() {
462
+ this._stackTrace.pop();
463
+ }
464
+ audit() {
465
+ return this._history.trace.map(t => {
466
+ const onChar = this.getChars(t.cursorIndex, t.cursorIndex);
467
+ const restChars = this.getChars(t.cursorIndex + 1, t.cursorIndex + 5);
468
+ const context = `{${t.cursorIndex}}[${onChar}]${restChars}`;
469
+ return `${this._buildPatternContext(t.pattern)}-->${context}`;
470
+ });
471
+ }
472
+ _buildPatternContext(pattern) {
473
+ if (pattern.parent != null) {
474
+ return `${pattern.parent.name}.${pattern.name}`;
475
+ }
476
+ return pattern.name;
477
+ }
439
478
  }
440
479
 
480
+ let idIndex$8 = 0;
441
481
  class Literal {
482
+ get id() {
483
+ return this._id;
484
+ }
442
485
  get type() {
443
486
  return this._type;
444
487
  }
@@ -461,9 +504,10 @@
461
504
  if (value.length === 0) {
462
505
  throw new Error("Value Cannot be empty.");
463
506
  }
507
+ this._id = `literal-${idIndex$8++}`;
464
508
  this._type = "literal";
465
509
  this._name = name;
466
- this._literal = value;
510
+ this._text = value;
467
511
  this._runes = Array.from(value);
468
512
  this._isOptional = isOptional;
469
513
  this._parent = null;
@@ -476,8 +520,9 @@
476
520
  const ast = this.parse(cursor);
477
521
  return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
478
522
  }
479
- exec(text) {
523
+ exec(text, record = false) {
480
524
  const cursor = new Cursor(text);
525
+ record && cursor.startRecording();
481
526
  const ast = this.parse(cursor);
482
527
  return {
483
528
  ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
@@ -485,20 +530,24 @@
485
530
  };
486
531
  }
487
532
  parse(cursor) {
533
+ cursor.startParseWith(this);
488
534
  this._firstIndex = cursor.index;
489
535
  const passed = this._tryToParse(cursor);
490
536
  if (passed) {
491
537
  cursor.resolveError();
492
538
  const node = this._createNode();
493
539
  cursor.recordMatch(this, node);
540
+ cursor.endParse();
494
541
  return node;
495
542
  }
496
543
  if (!this._isOptional) {
497
544
  cursor.recordErrorAt(this._firstIndex, this._endIndex, this);
545
+ cursor.endParse();
498
546
  return null;
499
547
  }
500
548
  cursor.resolveError();
501
549
  cursor.moveTo(this._firstIndex);
550
+ cursor.endParse();
502
551
  return null;
503
552
  }
504
553
  _tryToParse(cursor) {
@@ -512,7 +561,7 @@
512
561
  break;
513
562
  }
514
563
  if (i + 1 === literalRuneLength) {
515
- this._lastIndex = this._firstIndex + this._literal.length - 1;
564
+ this._lastIndex = this._firstIndex + this._text.length - 1;
516
565
  passed = true;
517
566
  break;
518
567
  }
@@ -525,14 +574,15 @@
525
574
  return passed;
526
575
  }
527
576
  _createNode() {
528
- return new Node("literal", this._name, this._firstIndex, this._lastIndex, undefined, this._literal);
577
+ return new Node("literal", this._name, this._firstIndex, this._lastIndex, undefined, this._text);
529
578
  }
530
579
  clone(name = this._name, isOptional = this._isOptional) {
531
- const clone = new Literal(name, this._literal, isOptional);
580
+ const clone = new Literal(name, this._text, isOptional);
581
+ clone._id = this._id;
532
582
  return clone;
533
583
  }
534
584
  getTokens() {
535
- return [this._literal];
585
+ return [this._text];
536
586
  }
537
587
  getTokensAfter(_lastMatched) {
538
588
  return [];
@@ -558,9 +608,16 @@
558
608
  find(_predicate) {
559
609
  return null;
560
610
  }
611
+ isEqual(pattern) {
612
+ return pattern.type === this.type && pattern._text === this._text;
613
+ }
561
614
  }
562
615
 
616
+ let idIndex$7 = 0;
563
617
  class Regex {
618
+ get id() {
619
+ return this._id;
620
+ }
564
621
  get type() {
565
622
  return this._type;
566
623
  }
@@ -585,6 +642,7 @@
585
642
  this._firstIndex = -1;
586
643
  this._substring = "";
587
644
  this._tokens = [];
645
+ this._id = `regex-${idIndex$7++}`;
588
646
  this._type = "regex";
589
647
  this._name = name;
590
648
  this._isOptional = isOptional;
@@ -609,8 +667,9 @@
609
667
  const ast = this.parse(cursor);
610
668
  return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
611
669
  }
612
- exec(text) {
670
+ exec(text, record = false) {
613
671
  const cursor = new Cursor(text);
672
+ record && cursor.startRecording();
614
673
  const ast = this.parse(cursor);
615
674
  return {
616
675
  ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
@@ -618,9 +677,11 @@
618
677
  };
619
678
  }
620
679
  parse(cursor) {
680
+ cursor.startParseWith(this);
621
681
  this._firstIndex = cursor.index;
622
682
  this.resetState(cursor);
623
683
  this.tryToParse(cursor);
684
+ cursor.endParse();
624
685
  return this._node;
625
686
  }
626
687
  resetState(cursor) {
@@ -652,9 +713,10 @@
652
713
  this._node = null;
653
714
  }
654
715
  clone(name = this._name, isOptional = this._isOptional) {
655
- const pattern = new Regex(name, this._originalRegexString, isOptional);
656
- pattern._tokens = this._tokens.slice();
657
- return pattern;
716
+ const clone = new Regex(name, this._originalRegexString, isOptional);
717
+ clone._tokens = this._tokens.slice();
718
+ clone._id = this._id;
719
+ return clone;
658
720
  }
659
721
  getTokens() {
660
722
  return this._tokens;
@@ -686,6 +748,9 @@
686
748
  setTokens(tokens) {
687
749
  this._tokens = tokens;
688
750
  }
751
+ isEqual(pattern) {
752
+ return pattern.type === this.type && pattern._originalRegexString === this._originalRegexString;
753
+ }
689
754
  }
690
755
 
691
756
  function findPattern(pattern, predicate) {
@@ -710,7 +775,11 @@
710
775
  }
711
776
  }
712
777
 
778
+ let idIndex$6 = 0;
713
779
  class Reference {
780
+ get id() {
781
+ return this._id;
782
+ }
714
783
  get type() {
715
784
  return this._type;
716
785
  }
@@ -730,6 +799,7 @@
730
799
  return this._isOptional;
731
800
  }
732
801
  constructor(name, isOptional = false) {
802
+ this._id = `reference-${idIndex$6++}`;
733
803
  this._type = "reference";
734
804
  this._name = name;
735
805
  this._parent = null;
@@ -742,8 +812,9 @@
742
812
  const ast = this.parse(cursor);
743
813
  return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
744
814
  }
745
- exec(text) {
815
+ exec(text, record = false) {
746
816
  const cursor = new Cursor(text);
817
+ record && cursor.startRecording();
747
818
  const ast = this.parse(cursor);
748
819
  return {
749
820
  ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
@@ -819,7 +890,12 @@
819
890
  return null;
820
891
  }
821
892
  clone(name = this._name, isOptional = this._isOptional) {
822
- return new Reference(name, isOptional);
893
+ const clone = new Reference(name, isOptional);
894
+ clone._id = this._id;
895
+ return clone;
896
+ }
897
+ isEqual(pattern) {
898
+ return pattern.type === this.type && pattern.name === this.name;
823
899
  }
824
900
  }
825
901
 
@@ -827,7 +903,11 @@
827
903
  return patterns.map(p => p.clone(p.name, isOptional));
828
904
  }
829
905
 
906
+ let idIndex$5 = 0;
830
907
  class Or {
908
+ get id() {
909
+ return this._id;
910
+ }
831
911
  get type() {
832
912
  return this._type;
833
913
  }
@@ -852,6 +932,7 @@
852
932
  }
853
933
  const children = clonePatterns(options, false);
854
934
  this._assignChildrenToParent(children);
935
+ this._id = `or-${idIndex$5++}`;
855
936
  this._type = "or";
856
937
  this._name = name;
857
938
  this._parent = null;
@@ -870,8 +951,9 @@
870
951
  const ast = this.parse(cursor);
871
952
  return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
872
953
  }
873
- exec(text) {
954
+ exec(text, record = false) {
874
955
  const cursor = new Cursor(text);
956
+ record && cursor.startRecording();
875
957
  const ast = this.parse(cursor);
876
958
  return {
877
959
  ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
@@ -879,19 +961,23 @@
879
961
  };
880
962
  }
881
963
  parse(cursor) {
964
+ cursor.startParseWith(this);
882
965
  this._firstIndex = cursor.index;
883
966
  const node = this._tryToParse(cursor);
884
967
  if (node != null) {
885
968
  cursor.moveTo(node.lastIndex);
886
969
  cursor.resolveError();
970
+ cursor.endParse();
887
971
  return node;
888
972
  }
889
973
  if (!this._isOptional) {
890
974
  cursor.recordErrorAt(this._firstIndex, this._firstIndex, this);
975
+ cursor.endParse();
891
976
  return null;
892
977
  }
893
978
  cursor.resolveError();
894
979
  cursor.moveTo(this._firstIndex);
980
+ cursor.endParse();
895
981
  return null;
896
982
  }
897
983
  _tryToParse(cursor) {
@@ -954,11 +1040,19 @@
954
1040
  }
955
1041
  clone(name = this._name, isOptional = this._isOptional) {
956
1042
  const or = new Or(name, this._children, isOptional, this._isGreedy);
1043
+ or._id = this._id;
957
1044
  return or;
958
1045
  }
1046
+ isEqual(pattern) {
1047
+ return pattern.type === this.type && this.children.every((c, index) => c.isEqual(pattern.children[index]));
1048
+ }
959
1049
  }
960
1050
 
1051
+ let idIndex$4 = 0;
961
1052
  class FiniteRepeat {
1053
+ get id() {
1054
+ return this._id;
1055
+ }
962
1056
  get type() {
963
1057
  return this._type;
964
1058
  }
@@ -984,6 +1078,7 @@
984
1078
  return this._max;
985
1079
  }
986
1080
  constructor(name, pattern, repeatAmount, options = {}) {
1081
+ this._id = `finite-repeat-${idIndex$4++}`;
987
1082
  this._type = "finite-repeat";
988
1083
  this._name = name;
989
1084
  this._parent = null;
@@ -1000,6 +1095,7 @@
1000
1095
  }
1001
1096
  }
1002
1097
  parse(cursor) {
1098
+ cursor.startParseWith(this);
1003
1099
  const startIndex = cursor.index;
1004
1100
  const nodes = [];
1005
1101
  const modulo = this._hasDivider ? 2 : 1;
@@ -1034,16 +1130,19 @@
1034
1130
  const lastIndex = cursor.index;
1035
1131
  cursor.moveTo(startIndex);
1036
1132
  cursor.recordErrorAt(startIndex, lastIndex, this);
1133
+ cursor.endParse();
1037
1134
  return null;
1038
1135
  }
1039
1136
  else if (nodes.length === 0) {
1040
1137
  cursor.resolveError();
1041
1138
  cursor.moveTo(startIndex);
1139
+ cursor.endParse();
1042
1140
  return null;
1043
1141
  }
1044
1142
  const firstIndex = nodes[0].firstIndex;
1045
1143
  const lastIndex = nodes[nodes.length - 1].lastIndex;
1046
1144
  cursor.moveTo(lastIndex);
1145
+ cursor.endParse();
1047
1146
  return new Node(this._type, this.name, firstIndex, lastIndex, nodes);
1048
1147
  }
1049
1148
  test(text) {
@@ -1051,8 +1150,9 @@
1051
1150
  const ast = this.parse(cursor);
1052
1151
  return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
1053
1152
  }
1054
- exec(text) {
1153
+ exec(text, record = false) {
1055
1154
  const cursor = new Cursor(text);
1155
+ record && cursor.startRecording();
1056
1156
  const ast = this.parse(cursor);
1057
1157
  return {
1058
1158
  ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
@@ -1069,11 +1169,13 @@
1069
1169
  min = Math.max(this._min, 1);
1070
1170
  }
1071
1171
  }
1072
- return new FiniteRepeat(name, this._children[0], this._max, {
1172
+ const clone = new FiniteRepeat(name, this._children[0], this._max, {
1073
1173
  divider: this._hasDivider ? this._children[1] : undefined,
1074
1174
  min,
1075
1175
  trimDivider: this._trimDivider
1076
1176
  });
1177
+ clone._id = this._id;
1178
+ return clone;
1077
1179
  }
1078
1180
  getTokens() {
1079
1181
  return this._children[0].getTokens();
@@ -1121,9 +1223,16 @@
1121
1223
  find(predicate) {
1122
1224
  return findPattern(this, predicate);
1123
1225
  }
1226
+ isEqual(pattern) {
1227
+ return pattern.type === this.type && this.children.every((c, index) => c.isEqual(pattern.children[index]));
1228
+ }
1124
1229
  }
1125
1230
 
1231
+ let idIndex$3 = 0;
1126
1232
  class InfiniteRepeat {
1233
+ get id() {
1234
+ return this._id;
1235
+ }
1127
1236
  get type() {
1128
1237
  return this._type;
1129
1238
  }
@@ -1156,6 +1265,7 @@
1156
1265
  children = [pattern.clone(pattern.name, false)];
1157
1266
  }
1158
1267
  this._assignChildrenToParent(children);
1268
+ this._id = `infinite-repeat-${idIndex$3++}`;
1159
1269
  this._type = "infinite-repeat";
1160
1270
  this._name = name;
1161
1271
  this._min = min;
@@ -1177,8 +1287,9 @@
1177
1287
  const ast = this.parse(cursor);
1178
1288
  return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
1179
1289
  }
1180
- exec(text) {
1290
+ exec(text, record = false) {
1181
1291
  const cursor = new Cursor(text);
1292
+ record && cursor.startRecording();
1182
1293
  const ast = this.parse(cursor);
1183
1294
  return {
1184
1295
  ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
@@ -1186,6 +1297,7 @@
1186
1297
  };
1187
1298
  }
1188
1299
  parse(cursor) {
1300
+ cursor.startParseWith(this);
1189
1301
  this._firstIndex = cursor.index;
1190
1302
  this._nodes = [];
1191
1303
  const passed = this._tryToParse(cursor);
@@ -1196,12 +1308,15 @@
1196
1308
  cursor.moveTo(node.lastIndex);
1197
1309
  cursor.recordMatch(this, node);
1198
1310
  }
1311
+ cursor.endParse();
1199
1312
  return node;
1200
1313
  }
1201
1314
  if (this._min > 0) {
1315
+ cursor.endParse();
1202
1316
  return null;
1203
1317
  }
1204
1318
  cursor.resolveError();
1319
+ cursor.endParse();
1205
1320
  return null;
1206
1321
  }
1207
1322
  _meetsMin() {
@@ -1355,15 +1470,24 @@
1355
1470
  min = Math.max(this._min, 1);
1356
1471
  }
1357
1472
  }
1358
- return new InfiniteRepeat(name, this._pattern, {
1473
+ const clone = new InfiniteRepeat(name, this._pattern, {
1359
1474
  divider: this._divider == null ? undefined : this._divider,
1360
1475
  min: min,
1361
1476
  trimDivider: this._trimDivider
1362
1477
  });
1478
+ clone._id = this._id;
1479
+ return clone;
1480
+ }
1481
+ isEqual(pattern) {
1482
+ return pattern.type === this.type && this.children.every((c, index) => c.isEqual(pattern.children[index]));
1363
1483
  }
1364
1484
  }
1365
1485
 
1486
+ let idIndex$2 = 0;
1366
1487
  class Repeat {
1488
+ get id() {
1489
+ return this._id;
1490
+ }
1367
1491
  get type() {
1368
1492
  return this._repeatPattern.type;
1369
1493
  }
@@ -1383,6 +1507,7 @@
1383
1507
  return this._repeatPattern.isOptional;
1384
1508
  }
1385
1509
  constructor(name, pattern, options = {}) {
1510
+ this._id = `repeat-${idIndex$2++}`;
1386
1511
  this._pattern = pattern;
1387
1512
  this._parent = null;
1388
1513
  this._options = Object.assign(Object.assign({}, options), { min: options.min == null ? 1 : options.min, max: options.max == null ? Infinity : options.max });
@@ -1414,7 +1539,9 @@
1414
1539
  min = Math.max(this._options.min, 1);
1415
1540
  }
1416
1541
  }
1417
- return new Repeat(name, this._pattern, Object.assign(Object.assign({}, this._options), { min }));
1542
+ const clone = new Repeat(name, this._pattern, Object.assign(Object.assign({}, this._options), { min }));
1543
+ clone._id = this._id;
1544
+ return clone;
1418
1545
  }
1419
1546
  getTokens() {
1420
1547
  return this._repeatPattern.getTokens();
@@ -1449,6 +1576,9 @@
1449
1576
  find(predicate) {
1450
1577
  return this._repeatPattern.find(predicate);
1451
1578
  }
1579
+ isEqual(pattern) {
1580
+ return pattern.type === this.type && this.children.every((c, index) => c.isEqual(pattern.children[index]));
1581
+ }
1452
1582
  }
1453
1583
 
1454
1584
  const comment = new Regex("comment", "#[^\r\n]+");
@@ -1463,7 +1593,11 @@
1463
1593
  return filteredNodes;
1464
1594
  }
1465
1595
 
1596
+ let idIndex$1 = 0;
1466
1597
  class And {
1598
+ get id() {
1599
+ return this._id;
1600
+ }
1467
1601
  get type() {
1468
1602
  return this._type;
1469
1603
  }
@@ -1488,6 +1622,7 @@
1488
1622
  }
1489
1623
  const children = clonePatterns(sequence);
1490
1624
  this._assignChildrenToParent(children);
1625
+ this._id = `and-${idIndex$1++}`;
1491
1626
  this._type = "and";
1492
1627
  this._name = name;
1493
1628
  this._isOptional = isOptional;
@@ -1506,8 +1641,9 @@
1506
1641
  const ast = this.parse(cursor);
1507
1642
  return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
1508
1643
  }
1509
- exec(text) {
1644
+ exec(text, record = false) {
1510
1645
  const cursor = new Cursor(text);
1646
+ record && cursor.startRecording();
1511
1647
  const ast = this.parse(cursor);
1512
1648
  return {
1513
1649
  ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
@@ -1515,6 +1651,7 @@
1515
1651
  };
1516
1652
  }
1517
1653
  parse(cursor) {
1654
+ cursor.startParseWith(this);
1518
1655
  this._firstIndex = cursor.index;
1519
1656
  this._nodes = [];
1520
1657
  const passed = this.tryToParse(cursor);
@@ -1523,11 +1660,13 @@
1523
1660
  if (node !== null) {
1524
1661
  cursor.recordMatch(this, node);
1525
1662
  }
1663
+ cursor.endParse();
1526
1664
  return node;
1527
1665
  }
1528
1666
  if (this._isOptional) {
1529
1667
  cursor.resolveError();
1530
1668
  }
1669
+ cursor.endParse();
1531
1670
  return null;
1532
1671
  }
1533
1672
  tryToParse(cursor) {
@@ -1686,7 +1825,12 @@
1686
1825
  return findPattern(this, predicate);
1687
1826
  }
1688
1827
  clone(name = this._name, isOptional = this._isOptional) {
1689
- return new And(name, this._children, isOptional);
1828
+ const clone = new And(name, this._children, isOptional);
1829
+ clone._id = this._id;
1830
+ return clone;
1831
+ }
1832
+ isEqual(pattern) {
1833
+ return pattern.type === this.type && this.children.every((c, index) => c.isEqual(pattern.children[index]));
1690
1834
  }
1691
1835
  }
1692
1836
 
@@ -1703,34 +1847,45 @@
1703
1847
 
1704
1848
  const name$1 = new Regex("name", "[a-zA-Z_-]+[a-zA-Z0-9_-]*");
1705
1849
 
1706
- const optionalNot = new Literal("not", "!", true);
1707
- const optionalIsOptional = new Literal("is-optional", "?", true);
1708
- const patternName$1 = name$1.clone("pattern-name");
1709
- const pattern = new And("pattern", [
1710
- optionalNot,
1711
- patternName$1,
1712
- optionalIsOptional,
1713
- ]);
1714
-
1715
- const divider$1 = new Regex("and-divider", "\\s*[&]\\s*");
1716
- divider$1.setTokens([" & "]);
1717
- const andLiteral = new Repeat("and-literal", pattern, { divider: divider$1, min: 2, trimDivider: true });
1850
+ const regexLiteral = new Regex("regex-literal", "/(\\\\/|[^/\\n\\r])*/");
1718
1851
 
1719
- const divider = new Regex("or-divider", "\\s*[|]\\s*");
1720
- divider.setTokens([" | "]);
1721
- const orLiteral = new Repeat("or-literal", name$1.clone("pattern-name"), { divider, min: 2, trimDivider: true });
1852
+ const patternName$3 = name$1.clone("pattern-name");
1853
+ const anonymousLiterals = new Or("anonymous-literals", [
1854
+ literal,
1855
+ regexLiteral,
1856
+ patternName$3,
1857
+ new Reference("repeat-literal"),
1858
+ ]);
1859
+ const anonymousWrappedLiterals = new Or("anonymous-wrapped-literals", [
1860
+ new Reference("or-literal"),
1861
+ new Reference("and-literal"),
1862
+ new Reference("complex-anonymous-pattern")
1863
+ ]);
1722
1864
 
1723
- const regexLiteral = new Regex("regex-literal", "/(\\\\/|[^/\\n\\r])*/");
1865
+ const inlinePatternOpenParen = new Literal("anonymous-pattern-open-paren", "(");
1866
+ const inlinePatternCloseParen = new Literal("anonymous-pattern-close-paren", ")");
1867
+ const optionalLineSpaces$1 = lineSpaces$1.clone(undefined, true);
1868
+ const complexAnonymousPattern = new And("complex-anonymous-pattern", [
1869
+ inlinePatternOpenParen,
1870
+ optionalLineSpaces$1,
1871
+ anonymousWrappedLiterals,
1872
+ optionalLineSpaces$1,
1873
+ inlinePatternCloseParen,
1874
+ ]);
1875
+ const anonymousPattern = new Or("anonymous-pattern", [
1876
+ anonymousLiterals,
1877
+ complexAnonymousPattern
1878
+ ]);
1724
1879
 
1725
- const patternName = name$1.clone("pattern-name");
1726
1880
  const optionalSpaces$2 = spaces$1.clone("optional-spaces", true);
1727
- const dividerPattern = name$1.clone("divider-pattern");
1728
1881
  const openBracket$1 = new Literal("open-bracket", "{");
1729
1882
  const closeBracket$1 = new Literal("close-bracket", "}");
1730
1883
  const comma = new Literal("comma", ",");
1731
1884
  const integer = new Regex("integer", "([1-9][0-9]*)|0");
1732
1885
  integer.setTokens(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]);
1733
1886
  const optionalInteger = integer.clone("integer", true);
1887
+ const trimKeyword = new Literal("trim-keyword", "trim", true);
1888
+ const trimFlag = new And("trim-flag", [lineSpaces$1, trimKeyword], true);
1734
1889
  const bounds = new And("bounds", [
1735
1890
  openBracket$1,
1736
1891
  optionalSpaces$2,
@@ -1739,7 +1894,6 @@
1739
1894
  comma,
1740
1895
  optionalSpaces$2,
1741
1896
  optionalInteger.clone("max"),
1742
- optionalSpaces$2,
1743
1897
  closeBracket$1
1744
1898
  ]);
1745
1899
  const exactCount = new And("exact-count", [
@@ -1756,41 +1910,67 @@
1756
1910
  exactCount,
1757
1911
  bounds
1758
1912
  ]);
1759
- const optional = new Literal("is-optional", "?", true);
1760
- const trimDivider = new Literal("trim-divider", "-t");
1761
- const openParen = new Literal("open-paren", "(");
1762
- const closeParen = new Literal("close-paren", ")");
1913
+ const openParen = new Literal("repeat-open-paren", "(");
1914
+ const closeParen = new Literal("repeat-close-paren", ")");
1763
1915
  const dividerComma = new Regex("divider-comma", "\\s*,\\s*");
1764
1916
  dividerComma.setTokens([", "]);
1917
+ const patternName$2 = name$1.clone("pattern-name");
1918
+ const patterns$3 = new Or("or-patterns", [patternName$2, anonymousPattern]);
1919
+ const dividerPattern = patterns$3.clone("divider-pattern");
1765
1920
  const repeatLiteral = new And("repeat-literal", [
1766
1921
  openParen,
1767
1922
  optionalSpaces$2,
1768
- patternName,
1769
- optional,
1770
- new And("optional-divider-section", [dividerComma, dividerPattern], true),
1923
+ patterns$3,
1924
+ new And("optional-divider-section", [dividerComma, dividerPattern, trimFlag], true),
1771
1925
  optionalSpaces$2,
1772
1926
  closeParen,
1773
- new And("quantifier-section", [optionalSpaces$2, quantifier]),
1774
- new And("optional-trim-divider-section", [spaces$1, trimDivider], true)
1927
+ new And("quantifier-section", [quantifier]),
1775
1928
  ]);
1776
1929
 
1777
- const optionalSpaces$1 = spaces$1.clone("optional-spaces", true);
1778
- const assignOperator = new Literal("assign-operator", "=");
1779
- const statements = new Or("statements", [
1930
+ const optionalNot = new Literal("not", "!", true);
1931
+ const optionalIsOptional$1 = new Literal("is-optional", "?", true);
1932
+ const patternName$1 = name$1.clone("pattern-name");
1933
+ const patterns$2 = new Or("and-patterns", [patternName$1, anonymousPattern]);
1934
+ const pattern$1 = new And("and-child-pattern", [
1935
+ optionalNot,
1936
+ patterns$2,
1937
+ optionalIsOptional$1,
1938
+ ]);
1939
+ const divider$1 = new Regex("and-divider", "\\s*[+]\\s*");
1940
+ divider$1.setTokens([" + "]);
1941
+ const andLiteral = new Repeat("and-literal", pattern$1, { divider: divider$1, min: 2, trimDivider: true });
1942
+
1943
+ const patternName = name$1.clone("pattern-name");
1944
+ const patterns$1 = new Or("or-patterns", [patternName, anonymousPattern]);
1945
+ const defaultDivider = new Regex("default-divider", "\\s*[|]\\s*");
1946
+ const greedyDivider = new Regex("greedy-divider", "\\s*[<][|][>]\\s*");
1947
+ const divider = new Or("or-divider", [defaultDivider, greedyDivider]);
1948
+ defaultDivider.setTokens([" | "]);
1949
+ greedyDivider.setTokens([" <|> "]);
1950
+ const orLiteral = new Repeat("or-literal", patterns$1, { divider, min: 2, trimDivider: true });
1951
+
1952
+ const aliasLiteral = name$1.clone("alias-literal");
1953
+ const optionalIsOptional = new Literal("is-optional", "?", true);
1954
+ const configurableAnonymousPattern = new And("configurable-anonymous-pattern", [anonymousPattern, optionalIsOptional]);
1955
+ const pattern = new Or("pattern", [
1780
1956
  literal,
1781
1957
  regexLiteral,
1958
+ repeatLiteral,
1959
+ aliasLiteral,
1782
1960
  orLiteral,
1783
1961
  andLiteral,
1784
- repeatLiteral,
1785
- name$1.clone("alias-literal"),
1786
- ]);
1962
+ configurableAnonymousPattern,
1963
+ ], false, true);
1964
+
1965
+ const optionalSpaces$1 = spaces$1.clone("optional-spaces", true);
1966
+ const assignOperator = new Literal("assign-operator", "=");
1787
1967
  const assignStatement = new And("assign-statement", [
1788
1968
  optionalSpaces$1,
1789
1969
  name$1,
1790
1970
  optionalSpaces$1,
1791
1971
  assignOperator,
1792
1972
  optionalSpaces$1,
1793
- statements
1973
+ pattern
1794
1974
  ]);
1795
1975
  const statement = new Or("statement", [assignStatement, name$1.clone("export-name")]);
1796
1976
 
@@ -1885,7 +2065,11 @@
1885
2065
  allSpaces
1886
2066
  ]);
1887
2067
 
2068
+ let idIndex = 0;
1888
2069
  class Not {
2070
+ get id() {
2071
+ return this._id;
2072
+ }
1889
2073
  get type() {
1890
2074
  return this._type;
1891
2075
  }
@@ -1905,6 +2089,7 @@
1905
2089
  return false;
1906
2090
  }
1907
2091
  constructor(name, pattern) {
2092
+ this._id = `not-${idIndex++}`;
1908
2093
  this._type = "not";
1909
2094
  this._name = name;
1910
2095
  this._parent = null;
@@ -1916,15 +2101,17 @@
1916
2101
  this.parse(cursor);
1917
2102
  return !cursor.hasError;
1918
2103
  }
1919
- exec(text) {
2104
+ exec(text, record = false) {
1920
2105
  const cursor = new Cursor(text);
2106
+ record && cursor.startRecording();
1921
2107
  const ast = this.parse(cursor);
1922
2108
  return {
1923
- ast,
2109
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
1924
2110
  cursor
1925
2111
  };
1926
2112
  }
1927
2113
  parse(cursor) {
2114
+ cursor.startParseWith(this);
1928
2115
  const firstIndex = cursor.index;
1929
2116
  this._children[0].parse(cursor);
1930
2117
  if (cursor.hasError) {
@@ -1936,10 +2123,12 @@
1936
2123
  cursor.resolveError();
1937
2124
  cursor.recordErrorAt(firstIndex, firstIndex, this);
1938
2125
  }
2126
+ cursor.endParse();
1939
2127
  return null;
1940
2128
  }
1941
2129
  clone(name = this._name) {
1942
2130
  const not = new Not(name, this._children[0]);
2131
+ not._id = this._id;
1943
2132
  return not;
1944
2133
  }
1945
2134
  getTokens() {
@@ -1981,6 +2170,9 @@
1981
2170
  find(predicate) {
1982
2171
  return predicate(this._children[0]) ? this._children[0] : null;
1983
2172
  }
2173
+ isEqual(pattern) {
2174
+ return pattern.type === this.type && this.children.every((c, index) => c.isEqual(pattern.children[index]));
2175
+ }
1984
2176
  }
1985
2177
 
1986
2178
  const defaultOptions = { greedyPatternNames: [], customTokens: {} };
@@ -2185,6 +2377,16 @@
2185
2377
  return furthestOptions;
2186
2378
  }
2187
2379
 
2380
+ let anonymousIndexId = 0;
2381
+ const patternNodes = {
2382
+ "literal": true,
2383
+ "regex-literal": true,
2384
+ "or-literal": true,
2385
+ "and-literal": true,
2386
+ "repeat-literal": true,
2387
+ "alias-literal": true,
2388
+ "configurable-anonymous-pattern": true
2389
+ };
2188
2390
  class ParseContext {
2189
2391
  constructor(params) {
2190
2392
  this.patternsByName = new Map();
@@ -2229,7 +2431,7 @@
2229
2431
  const ast = this._tryToParse(expression);
2230
2432
  yield this._resolveImports(ast);
2231
2433
  this._buildPatterns(ast);
2232
- return this._parseContext.patternsByName;
2434
+ return Object.fromEntries(this._parseContext.patternsByName);
2233
2435
  });
2234
2436
  }
2235
2437
  parseString(expression) {
@@ -2239,7 +2441,7 @@
2239
2441
  throw new Error("Cannot use imports on parseString, use parse instead.");
2240
2442
  }
2241
2443
  this._buildPatterns(ast);
2242
- return this._parseContext.patternsByName;
2444
+ return Object.fromEntries(this._parseContext.patternsByName);
2243
2445
  }
2244
2446
  _tryToParse(expression) {
2245
2447
  const { ast, cursor, options, isComplete } = this._autoComplete.suggestFor(expression);
@@ -2269,41 +2471,207 @@
2269
2471
  if (body == null) {
2270
2472
  return;
2271
2473
  }
2272
- body.findAll(n => n.name === "assign-statement" || n.name === "export-name").forEach((n) => {
2273
- const typeNode = n.find(n => n.name.includes("literal"));
2274
- const type = n.name === "export-name" ? "export-name" : (typeNode === null || typeNode === void 0 ? void 0 : typeNode.name) || "unknown";
2275
- switch (type) {
2474
+ body.findAll(n => n.name === "assign-statement").forEach((n) => {
2475
+ const patternNode = n.children.find(n => patternNodes[n.name] != null);
2476
+ if (patternNode == null) {
2477
+ return;
2478
+ }
2479
+ switch (patternNode.name) {
2276
2480
  case "literal": {
2277
- this._buildLiteral(n);
2481
+ this._saveLiteral(n);
2278
2482
  break;
2279
2483
  }
2280
2484
  case "regex-literal": {
2281
- this._buildRegex(n);
2485
+ this._saveRegex(n);
2282
2486
  break;
2283
2487
  }
2284
2488
  case "or-literal": {
2285
- this._buildOr(n);
2489
+ this._saveOr(n);
2286
2490
  break;
2287
2491
  }
2288
2492
  case "and-literal": {
2289
- this._buildAnd(n);
2493
+ this._saveAnd(n);
2290
2494
  break;
2291
2495
  }
2292
2496
  case "repeat-literal": {
2293
- this._buildRepeat(n);
2497
+ this._saveRepeat(n);
2294
2498
  break;
2295
2499
  }
2296
2500
  case "alias-literal": {
2297
- this._buildAlias(n);
2501
+ this._saveAlias(n);
2298
2502
  break;
2299
2503
  }
2300
- case "export-name": {
2301
- const pattern = this._getPattern(n.value);
2302
- this._parseContext.patternsByName.set(n.value, pattern);
2504
+ case "configurable-anonymous-pattern": {
2505
+ this._saveConfigurableAnonymous(n);
2303
2506
  break;
2304
2507
  }
2305
2508
  }
2306
2509
  });
2510
+ body.findAll(n => n.name === "export-name").forEach((n) => {
2511
+ const pattern = this._getPattern(n.value).clone();
2512
+ this._parseContext.patternsByName.set(n.value, pattern);
2513
+ });
2514
+ }
2515
+ _saveLiteral(statementNode) {
2516
+ const nameNode = statementNode.find(n => n.name === "name");
2517
+ const literalNode = statementNode.find(n => n.name === "literal");
2518
+ const name = nameNode.value;
2519
+ const literal = this._buildLiteral(name, literalNode);
2520
+ this._parseContext.patternsByName.set(name, literal);
2521
+ }
2522
+ _buildLiteral(name, node) {
2523
+ return new Literal(name, this._resolveStringValue(node.value));
2524
+ }
2525
+ _resolveStringValue(value) {
2526
+ return value.replace(/\\n/g, '\n')
2527
+ .replace(/\\r/g, '\r')
2528
+ .replace(/\\t/g, '\t')
2529
+ .replace(/\\b/g, '\b')
2530
+ .replace(/\\f/g, '\f')
2531
+ .replace(/\\v/g, '\v')
2532
+ .replace(/\\0/g, '\0')
2533
+ .replace(/\\x([0-9A-Fa-f]{2})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
2534
+ .replace(/\\u([0-9A-Fa-f]{4})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
2535
+ .replace(/\\(.)/g, '$1').slice(1, -1);
2536
+ }
2537
+ _saveRegex(statementNode) {
2538
+ const nameNode = statementNode.find(n => n.name === "name");
2539
+ const regexNode = statementNode.find(n => n.name === "regex-literal");
2540
+ const name = nameNode.value;
2541
+ const regex = this._buildRegex(name, regexNode);
2542
+ this._parseContext.patternsByName.set(name, regex);
2543
+ }
2544
+ _buildRegex(name, node) {
2545
+ const value = node.value.slice(1, node.value.length - 1);
2546
+ return new Regex(name, value);
2547
+ }
2548
+ _saveOr(statementNode) {
2549
+ const nameNode = statementNode.find(n => n.name === "name");
2550
+ const name = nameNode.value;
2551
+ const orNode = statementNode.find(n => n.name === "or-literal");
2552
+ const or = this._buildOr(name, orNode);
2553
+ this._parseContext.patternsByName.set(name, or);
2554
+ }
2555
+ _buildOr(name, node) {
2556
+ const patternNodes = node.children.filter(n => n.name !== "default-divider" && n.name !== "greedy-divider");
2557
+ const isGreedy = node.find(n => n.name === "greedy-divider") != null;
2558
+ const patterns = patternNodes.map(n => this._buildPattern(n));
2559
+ const or = new Or(name, patterns, false, isGreedy);
2560
+ return or;
2561
+ }
2562
+ _buildPattern(node) {
2563
+ const type = node.name;
2564
+ const name = `anonymous-pattern-${anonymousIndexId++}`;
2565
+ switch (type) {
2566
+ case "pattern-name": {
2567
+ return this._getPattern(node.value).clone();
2568
+ }
2569
+ case "literal": {
2570
+ return this._buildLiteral(node.value.slice(1, -1), node);
2571
+ }
2572
+ case "regex-literal": {
2573
+ return this._buildRegex(node.value.slice(1, -1), node);
2574
+ }
2575
+ case "repeat-literal": {
2576
+ return this._buildRepeat(name, node);
2577
+ }
2578
+ case "or-literal": {
2579
+ return this._buildOr(name, node);
2580
+ }
2581
+ case "and-literal": {
2582
+ return this._buildAnd(name, node);
2583
+ }
2584
+ case "complex-anonymous-pattern": {
2585
+ return this._buildComplexAnonymousPattern(node);
2586
+ }
2587
+ }
2588
+ throw new Error(`Couldn't build node: ${node.name}.`);
2589
+ }
2590
+ _saveAnd(statementNode) {
2591
+ const nameNode = statementNode.find(n => n.name === "name");
2592
+ const name = nameNode.value;
2593
+ const andNode = statementNode.find(n => n.name === "and-literal");
2594
+ const and = this._buildAnd(name, andNode);
2595
+ this._parseContext.patternsByName.set(name, and);
2596
+ }
2597
+ _buildAnd(name, node) {
2598
+ const patternNodes = node.children.filter(n => n.name !== "and-divider");
2599
+ const patterns = patternNodes.map(n => {
2600
+ const patternNode = n.children[0].name === "not" ? n.children[1] : n.children[0];
2601
+ const isNot = n.find(n => n.name === "not") != null;
2602
+ const isOptional = n.find(n => n.name === "is-optional");
2603
+ const pattern = this._buildPattern(patternNode).clone(undefined, isOptional == null ? undefined : true);
2604
+ if (isNot) {
2605
+ return new Not(`not-${pattern.name}`, pattern);
2606
+ }
2607
+ return pattern;
2608
+ });
2609
+ return new And(name, patterns);
2610
+ }
2611
+ _saveRepeat(statementNode) {
2612
+ const nameNode = statementNode.find(n => n.name === "name");
2613
+ const name = nameNode.value;
2614
+ const repeatNode = statementNode.find(n => n.name === "repeat-literal");
2615
+ const repeat = this._buildRepeat(name, repeatNode);
2616
+ this._parseContext.patternsByName.set(name, repeat);
2617
+ }
2618
+ _buildRepeat(name, repeatNode) {
2619
+ const bounds = repeatNode.find(n => n.name === "bounds");
2620
+ const exactCount = repeatNode.find(n => n.name === "exact-count");
2621
+ const quantifier = repeatNode.find(n => n.name === "quantifier-shorthand");
2622
+ const trimDivider = repeatNode.find(n => n.name === "trim-flag") != null;
2623
+ const patterNode = repeatNode.children[1].type === "optional-spaces" ? repeatNode.children[2] : repeatNode.children[1];
2624
+ const pattern = this._buildPattern(patterNode);
2625
+ const dividerSectionNode = repeatNode.find(n => n.name === "optional-divider-section");
2626
+ const options = {
2627
+ min: 1,
2628
+ max: Infinity
2629
+ };
2630
+ if (trimDivider) {
2631
+ options.trimDivider = trimDivider;
2632
+ }
2633
+ if (dividerSectionNode != null) {
2634
+ const dividerNode = dividerSectionNode.children[1];
2635
+ options.divider = this._buildPattern(dividerNode);
2636
+ }
2637
+ if (bounds != null) {
2638
+ const minNode = bounds.find(p => p.name === "min");
2639
+ const maxNode = bounds.find(p => p.name === "max");
2640
+ const min = minNode == null ? 0 : Number(minNode.value);
2641
+ const max = maxNode == null ? Infinity : Number(maxNode.value);
2642
+ options.min = min;
2643
+ options.max = max;
2644
+ }
2645
+ else if (exactCount != null) {
2646
+ const integerNode = exactCount.find(p => p.name === "integer");
2647
+ const integer = Number(integerNode.value);
2648
+ options.min = integer;
2649
+ options.max = integer;
2650
+ }
2651
+ else if (quantifier != null) {
2652
+ const type = quantifier.value;
2653
+ if (type === "+") {
2654
+ options.min = 1;
2655
+ options.max = Infinity;
2656
+ }
2657
+ else {
2658
+ options.min = 0;
2659
+ options.max = Infinity;
2660
+ }
2661
+ }
2662
+ return new Repeat(name, pattern.clone(pattern.name), options);
2663
+ }
2664
+ _saveConfigurableAnonymous(node) {
2665
+ const nameNode = node.find(n => n.name === "name");
2666
+ const name = nameNode.value;
2667
+ const anonymousNode = node.find(n => n.name === "complex-anonymous-pattern");
2668
+ const isOptional = node.children[1] != null;
2669
+ const anonymous = this._buildPattern(anonymousNode).clone(name, isOptional);
2670
+ this._parseContext.patternsByName.set(name, anonymous);
2671
+ }
2672
+ _buildComplexAnonymousPattern(node) {
2673
+ const wrappedNode = node.children[1].name === "line-spaces" ? node.children[2] : node.children[1];
2674
+ return this._buildPattern(wrappedNode);
2307
2675
  }
2308
2676
  _resolveImports(ast) {
2309
2677
  return __awaiter(this, void 0, void 0, function* () {
@@ -2332,7 +2700,7 @@
2332
2700
  if (parseContext.importedPatternsByName.has(importName)) {
2333
2701
  throw new Error(`'${importName}' was already used within another import.`);
2334
2702
  }
2335
- const pattern = patterns.get(importName);
2703
+ const pattern = patterns[importName];
2336
2704
  if (pattern == null) {
2337
2705
  throw new Error(`Couldn't find pattern with name: ${importName}, from import: ${resource}.`);
2338
2706
  }
@@ -2346,7 +2714,7 @@
2346
2714
  if (parseContext.importedPatternsByName.has(alias)) {
2347
2715
  throw new Error(`'${alias}' was already used within another import.`);
2348
2716
  }
2349
- const pattern = patterns.get(importName);
2717
+ const pattern = patterns[importName];
2350
2718
  if (pattern == null) {
2351
2719
  throw new Error(`Couldn't find pattern with name: ${importName}, from import: ${resource}.`);
2352
2720
  }
@@ -2377,48 +2745,11 @@
2377
2745
  resolveImport: this._resolveImport
2378
2746
  });
2379
2747
  const patterns = grammar.parseString(expression);
2380
- params = Array.from(patterns.values());
2748
+ params = Array.from(Object.values(patterns));
2381
2749
  }
2382
2750
  }
2383
2751
  return params;
2384
2752
  }
2385
- _buildLiteral(statementNode) {
2386
- const nameNode = statementNode.find(n => n.name === "name");
2387
- const literalNode = statementNode.find(n => n.name === "literal");
2388
- const name = nameNode.value;
2389
- const value = this._resolveStringValue(literalNode.value.slice(1, -1));
2390
- const literal = new Literal(name, value);
2391
- this._parseContext.patternsByName.set(name, literal);
2392
- }
2393
- _resolveStringValue(value) {
2394
- return value.replace(/\\n/g, '\n')
2395
- .replace(/\\r/g, '\r')
2396
- .replace(/\\t/g, '\t')
2397
- .replace(/\\b/g, '\b')
2398
- .replace(/\\f/g, '\f')
2399
- .replace(/\\v/g, '\v')
2400
- .replace(/\\0/g, '\0')
2401
- .replace(/\\x([0-9A-Fa-f]{2})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
2402
- .replace(/\\u([0-9A-Fa-f]{4})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
2403
- .replace(/\\(.)/g, '$1');
2404
- }
2405
- _buildRegex(statementNode) {
2406
- const nameNode = statementNode.find(n => n.name === "name");
2407
- const regexNode = statementNode.find(n => n.name === "regex-literal");
2408
- const value = regexNode.value.slice(1, regexNode.value.length - 1);
2409
- const name = nameNode.value;
2410
- const regex = new Regex(name, value);
2411
- this._parseContext.patternsByName.set(name, regex);
2412
- }
2413
- _buildOr(statementNode) {
2414
- const nameNode = statementNode.find(n => n.name === "name");
2415
- const orNode = statementNode.find(n => n.name === "or-literal");
2416
- const patternNodes = orNode.children.filter(n => n.name === "pattern-name");
2417
- const name = nameNode.value;
2418
- const patterns = patternNodes.map(n => this._getPattern(n.value));
2419
- const or = new Or(name, patterns, false, true);
2420
- this._parseContext.patternsByName.set(name, or);
2421
- }
2422
2753
  _getPattern(name) {
2423
2754
  let pattern = this._parseContext.patternsByName.get(name);
2424
2755
  if (pattern == null) {
@@ -2432,82 +2763,12 @@
2432
2763
  }
2433
2764
  return pattern;
2434
2765
  }
2435
- _buildAnd(statementNode) {
2436
- const nameNode = statementNode.find(n => n.name === "name");
2437
- const andNode = statementNode.find(n => n.name === "and-literal");
2438
- const patternNodes = andNode.children.filter(n => n.name === "pattern");
2439
- const name = nameNode.value;
2440
- const patterns = patternNodes.map(n => {
2441
- const nameNode = n.find(n => n.name === "pattern-name");
2442
- const isNot = n.find(n => n.name === "not") != null;
2443
- const isOptional = n.find(n => n.name === "is-optional") != null;
2444
- const name = nameNode.value;
2445
- const pattern = this._getPattern(name);
2446
- if (isNot) {
2447
- return new Not(`not-${name}`, pattern.clone(name, isOptional));
2448
- }
2449
- return pattern.clone(name, isOptional);
2450
- });
2451
- const and = new And(name, patterns);
2452
- this._parseContext.patternsByName.set(name, and);
2453
- }
2454
- _buildRepeat(statementNode) {
2455
- const nameNode = statementNode.find(n => n.name === "name");
2456
- const repeatNode = statementNode.find(n => n.name === "repeat-literal");
2457
- const patternNameNode = statementNode.find(n => n.name === "pattern-name");
2458
- const dividerNode = repeatNode.find(n => n.name === "divider-pattern");
2459
- const bounds = repeatNode.find(n => n.name === "bounds");
2460
- const exactCount = repeatNode.find(n => n.name === "exact-count");
2461
- const quantifier = repeatNode.find(n => n.name === "quantifier-shorthand");
2462
- const isPatternOptional = repeatNode.find(n => n.name === "is-optional") != null;
2463
- const trimDivider = repeatNode.find(n => n.name === "trim-divider") != null;
2464
- const name = nameNode.value;
2465
- const pattern = this._getPattern(patternNameNode.value);
2466
- const options = {
2467
- min: 1,
2468
- max: Infinity
2469
- };
2470
- if (trimDivider) {
2471
- options.trimDivider = trimDivider;
2472
- }
2473
- if (dividerNode != null) {
2474
- options.divider = this._getPattern(dividerNode.value);
2475
- }
2476
- if (bounds != null) {
2477
- const minNode = bounds.find(p => p.name === "min");
2478
- const maxNode = bounds.find(p => p.name === "max");
2479
- const min = minNode == null ? 0 : Number(minNode.value);
2480
- const max = maxNode == null ? Infinity : Number(maxNode.value);
2481
- options.min = min;
2482
- options.max = max;
2483
- }
2484
- else if (exactCount != null) {
2485
- const integerNode = exactCount.find(p => p.name === "integer");
2486
- const integer = Number(integerNode.value);
2487
- options.min = integer;
2488
- options.max = integer;
2489
- }
2490
- else if (quantifier != null) {
2491
- const type = quantifier.value;
2492
- if (type === "+") {
2493
- options.min = 1;
2494
- options.max = Infinity;
2495
- }
2496
- else {
2497
- options.min = 0;
2498
- options.max = Infinity;
2499
- }
2500
- }
2501
- const repeat = new Repeat(name, pattern.clone(pattern.name, isPatternOptional), options);
2502
- this._parseContext.patternsByName.set(name, repeat);
2503
- }
2504
- _buildAlias(statementNode) {
2766
+ _saveAlias(statementNode) {
2505
2767
  const nameNode = statementNode.find(n => n.name === "name");
2506
2768
  const aliasNode = statementNode.find(n => n.name === "alias-literal");
2507
2769
  const aliasName = aliasNode.value;
2508
2770
  const name = nameNode.value;
2509
- const pattern = this._getPattern(aliasName);
2510
- const alias = pattern.clone(name);
2771
+ const alias = this._getPattern(aliasName).clone(name);
2511
2772
  this._parseContext.patternsByName.set(name, alias);
2512
2773
  }
2513
2774
  static parse(expression, options) {
@@ -2524,6 +2785,30 @@
2524
2785
  }
2525
2786
  }
2526
2787
 
2788
+ function arePatternsEqual(a, b) {
2789
+ if (a === b) {
2790
+ return true;
2791
+ }
2792
+ else if (a == null || b == null) {
2793
+ return false;
2794
+ }
2795
+ return a.isEqual(b);
2796
+ }
2797
+
2798
+ const kebabRegex = /-([a-z])/g; // Define the regex once
2799
+ function kebabToCamelCase(str) {
2800
+ return str.replace(kebabRegex, (_, char) => char.toUpperCase());
2801
+ }
2802
+ function patterns(strings, ...values) {
2803
+ const combinedString = strings.reduce((result, str, i) => result + str + (values[i] || ''), '');
2804
+ const result = {};
2805
+ const patterns = Grammar.parseString(combinedString);
2806
+ Object.keys(patterns).forEach(k => {
2807
+ result[kebabToCamelCase(k)] = patterns[k];
2808
+ });
2809
+ return result;
2810
+ }
2811
+
2527
2812
  exports.And = And;
2528
2813
  exports.AutoComplete = AutoComplete;
2529
2814
  exports.Cursor = Cursor;
@@ -2537,7 +2822,9 @@
2537
2822
  exports.Reference = Reference;
2538
2823
  exports.Regex = Regex;
2539
2824
  exports.Repeat = Repeat;
2825
+ exports.arePatternsEqual = arePatternsEqual;
2540
2826
  exports.grammar = grammar;
2827
+ exports.patterns = patterns;
2541
2828
 
2542
2829
  Object.defineProperty(exports, '__esModule', { value: true });
2543
2830