clarity-pattern-parser 11.4.1 → 11.5.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.
@@ -40,13 +40,13 @@ export declare class Node {
40
40
  append(...nodes: Node[]): void;
41
41
  nextSibling(): Node | null;
42
42
  previousSibling(): Node | null;
43
- find(predicate: (node: Node) => boolean): Node | null;
44
- findAll(predicate: (node: Node) => boolean): Node[];
43
+ find(predicate: (node: Node) => boolean, breadthFirst?: boolean): Node | null;
44
+ findAll(predicate: (node: Node) => boolean, breadthFirst?: boolean): Node[];
45
45
  findRoot(): Node;
46
46
  findAncestor(predicate: (node: Node) => boolean): Node | null;
47
- walkUp(callback: (node: Node) => void): void;
48
- walkDown(callback: (node: Node) => void): void;
49
- walkBreadthFirst(callback: (node: Node) => void): void;
47
+ walkUp(callback: (node: Node) => boolean | void): boolean;
48
+ walkDown(callback: (node: Node) => boolean | void): boolean;
49
+ walkBreadthFirst(callback: (node: Node) => boolean | void): boolean;
50
50
  transform(visitors: Record<string, (node: Node) => Node>): Node;
51
51
  flatten(): Node[];
52
52
  compact(): void;
@@ -130,16 +130,42 @@
130
130
  }
131
131
  return null;
132
132
  }
133
- find(predicate) {
134
- return this.findAll(predicate)[0] || null;
133
+ find(predicate, breadthFirst = false) {
134
+ let match = null;
135
+ if (breadthFirst) {
136
+ this.walkBreadthFirst(n => {
137
+ if (predicate(n)) {
138
+ match = n;
139
+ return false;
140
+ }
141
+ });
142
+ }
143
+ else {
144
+ this.walkUp(n => {
145
+ if (predicate(n)) {
146
+ match = n;
147
+ return false;
148
+ }
149
+ });
150
+ }
151
+ return match;
135
152
  }
136
- findAll(predicate) {
153
+ findAll(predicate, breadthFirst = false) {
137
154
  const matches = [];
138
- this.walkUp(n => {
139
- if (predicate(n)) {
140
- matches.push(n);
141
- }
142
- });
155
+ if (breadthFirst) {
156
+ this.walkBreadthFirst(n => {
157
+ if (predicate(n)) {
158
+ matches.push(n);
159
+ }
160
+ });
161
+ }
162
+ else {
163
+ this.walkUp(n => {
164
+ if (predicate(n)) {
165
+ matches.push(n);
166
+ }
167
+ });
168
+ }
143
169
  return matches;
144
170
  }
145
171
  findRoot() {
@@ -162,22 +188,26 @@
162
188
  return null;
163
189
  }
164
190
  walkUp(callback) {
191
+ var _a;
165
192
  const childrenCopy = this._children.slice();
166
- childrenCopy.forEach(c => c.walkUp(callback));
167
- callback(this);
193
+ const result = childrenCopy.every(c => c.walkUp(callback));
194
+ return ((_a = callback(this)) !== null && _a !== void 0 ? _a : true) && result;
168
195
  }
169
196
  walkDown(callback) {
197
+ var _a;
170
198
  const childrenCopy = this._children.slice();
171
- callback(this);
172
- childrenCopy.forEach(c => c.walkDown(callback));
199
+ return ((_a = callback(this)) !== null && _a !== void 0 ? _a : true) && childrenCopy.every(c => c.walkDown(callback));
173
200
  }
174
201
  walkBreadthFirst(callback) {
175
202
  const queue = [this];
176
203
  while (queue.length > 0) {
177
204
  const current = queue.shift();
178
- callback(current);
205
+ if (callback(current) === false) {
206
+ return false;
207
+ }
179
208
  queue.push(...current.children);
180
209
  }
210
+ return true;
181
211
  }
182
212
  transform(visitors) {
183
213
  const childrenCopy = this._children.slice();
@@ -433,9 +463,10 @@
433
463
  }
434
464
  }
435
465
 
466
+ const segmenter = new Intl.Segmenter("und", { granularity: "grapheme" });
436
467
  class Cursor {
437
468
  get text() {
438
- return this._chars.join("");
469
+ return this._text;
439
470
  }
440
471
  get isOnFirst() {
441
472
  return this._index === 0;
@@ -483,33 +514,55 @@
483
514
  return this._history.error != null;
484
515
  }
485
516
  get currentChar() {
486
- return this._chars[this._index];
517
+ const index = this.getCharStartIndex(this._index);
518
+ return this.text.slice(index, index + this._charSize[index]);
487
519
  }
488
520
  constructor(text) {
489
- this._chars = [...text];
521
+ this._text = text;
522
+ this._length = text.length;
523
+ this._charSize = [];
524
+ this._charMap = [];
490
525
  this._index = 0;
491
- this._length = this._chars.length;
492
526
  this._history = new CursorHistory();
527
+ let index = 0;
528
+ for (const segment of segmenter.segment(text)) {
529
+ const size = segment.segment.length;
530
+ for (let i = 0; i < size; i++) {
531
+ this._charMap.push(index);
532
+ this._charSize.push(size);
533
+ }
534
+ index += size;
535
+ }
493
536
  }
494
537
  hasNext() {
495
- return this._index + 1 < this._length;
538
+ const index = this._charMap[this._index];
539
+ const charSize = this._charSize[index];
540
+ return index + charSize < this._length;
496
541
  }
497
542
  next() {
498
543
  if (this.hasNext()) {
499
- this._index++;
544
+ const index = this._charMap[this._index];
545
+ const size = this._charSize[index];
546
+ this.moveTo(index + size);
500
547
  }
501
548
  }
502
549
  hasPrevious() {
503
- return this._index - 1 >= 0;
550
+ var _a;
551
+ const index = this._charMap[this._index];
552
+ const previousIndex = (_a = this._charMap[index - 1]) !== null && _a !== void 0 ? _a : -1;
553
+ return previousIndex >= 0;
504
554
  }
505
555
  previous() {
556
+ var _a;
506
557
  if (this.hasPrevious()) {
507
- this._index--;
558
+ const index = this._charMap[this._index];
559
+ const previousIndex = (_a = this._charMap[index - 1]) !== null && _a !== void 0 ? _a : -1;
560
+ this.moveTo(previousIndex);
508
561
  }
509
562
  }
510
563
  moveTo(position) {
511
564
  if (position >= 0 && position < this._length) {
512
- this._index = position;
565
+ this._index = this._charMap[position];
513
566
  }
514
567
  }
515
568
  moveToFirstChar() {
@@ -521,8 +574,8 @@
521
574
  getLastIndex() {
522
575
  return this._length - 1;
523
576
  }
524
- getChars(first, last) {
525
- return this._chars.slice(first, last + 1).join("");
577
+ substring(first, last) {
578
+ return this._text.slice(first, last + 1);
526
579
  }
527
580
  recordMatch(pattern, node) {
528
581
  this._history.recordMatch(pattern, node);
@@ -539,6 +592,18 @@
539
592
  stopRecording() {
540
593
  this._history.stopRecording();
541
594
  }
595
+ getCharStartIndex(index) {
596
+ return this._charMap[index];
597
+ }
598
+ getCharEndIndex(index) {
599
+ var _a;
600
+ let startIndex = this.getCharStartIndex(index);
601
+ return (_a = startIndex + this._charSize[startIndex]) !== null && _a !== void 0 ? _a : 1;
602
+ }
603
+ getCharLastIndex(index) {
604
+ var _a;
605
+ return (_a = this.getCharEndIndex(index) - 1) !== null && _a !== void 0 ? _a : 0;
606
+ }
542
607
  }
543
608
 
544
609
  function execPattern(pattern, text, record = false) {
@@ -604,11 +669,9 @@
604
669
  this._type = "literal";
605
670
  this._name = name;
606
671
  this._token = value;
607
- this._runes = Array.from(value);
608
672
  this._parent = null;
609
673
  this._firstIndex = 0;
610
674
  this._lastIndex = 0;
611
- this._endIndex = 0;
612
675
  }
613
676
  test(text, record = false) {
614
677
  return testPattern(this, text, record);
@@ -618,6 +681,7 @@
618
681
  }
619
682
  parse(cursor) {
620
683
  this._firstIndex = cursor.index;
684
+ this._lastIndex = cursor.index;
621
685
  const passed = this._tryToParse(cursor);
622
686
  if (passed) {
623
687
  cursor.resolveError();
@@ -625,31 +689,28 @@
625
689
  cursor.recordMatch(this, node);
626
690
  return node;
627
691
  }
628
- cursor.recordErrorAt(this._firstIndex, this._endIndex, this);
692
+ cursor.recordErrorAt(this._firstIndex, this._lastIndex, this);
629
693
  return null;
630
694
  }
631
695
  _tryToParse(cursor) {
632
- let passed = false;
633
- const literalRuneLength = this._runes.length;
634
- for (let i = 0; i < literalRuneLength; i++) {
635
- const literalRune = this._runes[i];
636
- const cursorRune = cursor.currentChar;
637
- if (literalRune !== cursorRune) {
638
- this._endIndex = cursor.index;
639
- break;
640
- }
641
- if (i + 1 === literalRuneLength) {
642
- this._lastIndex = this._firstIndex + this._token.length - 1;
643
- passed = true;
644
- break;
645
- }
646
- if (!cursor.hasNext()) {
647
- this._endIndex = cursor.index + 1;
648
- break;
696
+ const token = this._token;
697
+ const compareToToken = cursor.text.slice(this._firstIndex, this._firstIndex + this._token.length);
698
+ const length = Math.min(token.length, compareToToken.length);
699
+ for (let i = 0; i < length; i++) {
700
+ if (token[i] !== compareToToken[i]) {
701
+ this._lastIndex = this._firstIndex + i;
702
+ cursor.moveTo(this._lastIndex);
703
+ return false;
649
704
  }
650
- cursor.next();
651
705
  }
652
- return passed;
706
+ if (token != compareToToken) {
707
+ this._lastIndex = this._firstIndex + compareToToken.length - 1;
708
+ cursor.moveTo(this._lastIndex);
709
+ return false;
710
+ }
711
+ this._lastIndex = this._firstIndex + this._token.length - 1;
712
+ cursor.moveTo(this._lastIndex);
713
+ return true;
653
714
  }
654
715
  _createNode() {
655
716
  return new Node("literal", this._name, this._firstIndex, this._lastIndex, undefined, this._token);
@@ -728,7 +789,7 @@
728
789
  this._name = name;
729
790
  this._parent = null;
730
791
  this._originalRegexString = regex;
731
- this._regex = new RegExp(`^${regex}`, "g");
792
+ this._regex = new RegExp(`^${regex}`, "gu");
732
793
  this.assertArguments();
733
794
  }
734
795
  assertArguments() {
@@ -757,7 +818,7 @@
757
818
  resetState(cursor) {
758
819
  this._cursor = cursor;
759
820
  this._regex.lastIndex = 0;
760
- this._substring = this._cursor.text.substr(this._cursor.index);
821
+ this._substring = this._cursor.text.slice(this._cursor.index);
761
822
  this._node = null;
762
823
  }
763
824
  tryToParse(cursor) {
@@ -772,10 +833,9 @@
772
833
  processResult(cursor, result) {
773
834
  const currentIndex = cursor.index;
774
835
  const match = result[0];
775
- const matchLength = [...match].length;
776
- const newIndex = currentIndex + matchLength - 1;
777
- this._node = new Node("regex", this._name, currentIndex, newIndex, undefined, result[0]);
778
- cursor.moveTo(newIndex);
836
+ const lastIndex = cursor.getCharLastIndex(currentIndex + match.length - 1);
837
+ this._node = new Node("regex", this._name, currentIndex, lastIndex, undefined, result[0]);
838
+ cursor.moveTo(lastIndex);
779
839
  cursor.recordMatch(this, this._node);
780
840
  }
781
841
  processError(cursor) {
@@ -3303,7 +3363,7 @@
3303
3363
  }
3304
3364
  if (foundMatch) {
3305
3365
  cursor.moveTo(cursorIndex - 1);
3306
- const value = cursor.getChars(this.startedOnIndex, cursorIndex - 1);
3366
+ const value = cursor.substring(this.startedOnIndex, cursorIndex - 1);
3307
3367
  const node = Node.createValueNode(this._type, this._name, value);
3308
3368
  cursor.recordMatch(this, node);
3309
3369
  return node;
@@ -3455,7 +3515,7 @@
3455
3515
  }
3456
3516
  const lastPattern = furthestMatch.pattern;
3457
3517
  const suggestions = cleanSuggestions(lastPattern.getNextTokens());
3458
- const strUpToError = cursor.getChars(0, endIndex);
3518
+ const strUpToError = cursor.substring(0, endIndex);
3459
3519
  const lines = strUpToError.split("\n");
3460
3520
  const lastLine = lines[lines.length - 1];
3461
3521
  const line = lines.length;
@@ -4193,9 +4253,9 @@
4193
4253
  }
4194
4254
  _createSuggestionOptionsFromErrors() {
4195
4255
  // These errored because the length of the string.
4196
- const errors = this._cursor.errors.filter(e => e.lastIndex === this._cursor.length);
4256
+ const errors = this._cursor.errors.filter(e => e.lastIndex === this._cursor.length - 1);
4197
4257
  const errorSuggestionOptions = errors.map(parseError => {
4198
- const currentText = this._cursor.getChars(parseError.startIndex, parseError.lastIndex);
4258
+ const currentText = this._cursor.substring(parseError.startIndex, parseError.lastIndex);
4199
4259
  const compositeSuggestions = this._getCompositeSuggestionsForPattern(parseError.pattern);
4200
4260
  const trimmedErrorCompositeSuggestions = this._trimSuggestionsByExistingText(currentText, compositeSuggestions);
4201
4261
  return this._createSuggestions(parseError.lastIndex, trimmedErrorCompositeSuggestions);
@@ -4251,7 +4311,7 @@
4251
4311
  * ie. sequence pattern segments ≈ [{look}, {an example}, {phrase}]
4252
4312
  * fullText = "look an"
4253
4313
  * remove {look} segment as its already been completed by the existing text.
4254
- */
4314
+ */
4255
4315
  _filterCompletedSubSegments(currentText, compositeSuggestion) {
4256
4316
  let elementsToRemove = [];
4257
4317
  let workingText = currentText;
@@ -4354,7 +4414,7 @@
4354
4414
  return unique;
4355
4415
  }
4356
4416
  _createSuggestions(lastIndex, compositeSuggestionList) {
4357
- let textToIndex = lastIndex === -1 ? "" : this._cursor.getChars(0, lastIndex);
4417
+ let textToIndex = lastIndex === -1 ? "" : this._cursor.substring(0, lastIndex);
4358
4418
  const options = [];
4359
4419
  for (const compositeSuggestion of compositeSuggestionList) {
4360
4420
  // concatenated for start index identification inside createSuggestion