clarity-pattern-parser 11.4.0 → 11.4.2

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.
package/dist/index.esm.js CHANGED
@@ -427,6 +427,7 @@ class CursorHistory {
427
427
  }
428
428
  }
429
429
 
430
+ const segmenter = new Intl.Segmenter("und", { granularity: "grapheme" });
430
431
  class Cursor {
431
432
  get text() {
432
433
  return this._text;
@@ -477,33 +478,55 @@ class Cursor {
477
478
  return this._history.error != null;
478
479
  }
479
480
  get currentChar() {
480
- return this._text[this._index];
481
+ const index = this.getCharStartIndex(this._index);
482
+ return this.text.slice(index, index + this._charSize[index]);
481
483
  }
482
484
  constructor(text) {
483
485
  this._text = text;
486
+ this._length = text.length;
487
+ this._charSize = [];
488
+ this._charMap = [];
484
489
  this._index = 0;
485
- this._length = [...text].length;
486
490
  this._history = new CursorHistory();
491
+ let index = 0;
492
+ for (const segment of segmenter.segment(text)) {
493
+ const size = segment.segment.length;
494
+ for (let i = 0; i < size; i++) {
495
+ this._charMap.push(index);
496
+ this._charSize.push(size);
497
+ }
498
+ index += size;
499
+ }
487
500
  }
488
501
  hasNext() {
489
- return this._index + 1 < this._length;
502
+ const index = this._charMap[this._index];
503
+ const charSize = this._charSize[index];
504
+ return index + charSize < this._length;
490
505
  }
491
506
  next() {
492
507
  if (this.hasNext()) {
493
- this._index++;
508
+ const index = this._charMap[this._index];
509
+ const size = this._charSize[index];
510
+ this.moveTo(index + size);
494
511
  }
495
512
  }
496
513
  hasPrevious() {
497
- return this._index - 1 >= 0;
514
+ var _a;
515
+ const index = this._charMap[this._index];
516
+ const previousIndex = (_a = this._charMap[index - 1]) !== null && _a !== void 0 ? _a : -1;
517
+ return previousIndex >= 0;
498
518
  }
499
519
  previous() {
520
+ var _a;
500
521
  if (this.hasPrevious()) {
501
- this._index--;
522
+ const index = this._charMap[this._index];
523
+ const previousIndex = (_a = this._charMap[index - 1]) !== null && _a !== void 0 ? _a : -1;
524
+ this.moveTo(previousIndex);
502
525
  }
503
526
  }
504
527
  moveTo(position) {
505
528
  if (position >= 0 && position < this._length) {
506
- this._index = position;
529
+ this._index = this._charMap[position];
507
530
  }
508
531
  }
509
532
  moveToFirstChar() {
@@ -515,7 +538,7 @@ class Cursor {
515
538
  getLastIndex() {
516
539
  return this._length - 1;
517
540
  }
518
- getChars(first, last) {
541
+ substring(first, last) {
519
542
  return this._text.slice(first, last + 1);
520
543
  }
521
544
  recordMatch(pattern, node) {
@@ -533,6 +556,18 @@ class Cursor {
533
556
  stopRecording() {
534
557
  this._history.stopRecording();
535
558
  }
559
+ getCharStartIndex(index) {
560
+ return this._charMap[index];
561
+ }
562
+ getCharEndIndex(index) {
563
+ var _a;
564
+ let startIndex = this.getCharStartIndex(index);
565
+ return (_a = startIndex + this._charSize[startIndex]) !== null && _a !== void 0 ? _a : 1;
566
+ }
567
+ getCharLastIndex(index) {
568
+ var _a;
569
+ return (_a = this.getCharEndIndex(index) - 1) !== null && _a !== void 0 ? _a : 0;
570
+ }
536
571
  }
537
572
 
538
573
  function execPattern(pattern, text, record = false) {
@@ -598,11 +633,9 @@ class Literal {
598
633
  this._type = "literal";
599
634
  this._name = name;
600
635
  this._token = value;
601
- this._runes = Array.from(value);
602
636
  this._parent = null;
603
637
  this._firstIndex = 0;
604
638
  this._lastIndex = 0;
605
- this._endIndex = 0;
606
639
  }
607
640
  test(text, record = false) {
608
641
  return testPattern(this, text, record);
@@ -612,6 +645,7 @@ class Literal {
612
645
  }
613
646
  parse(cursor) {
614
647
  this._firstIndex = cursor.index;
648
+ this._lastIndex = cursor.index;
615
649
  const passed = this._tryToParse(cursor);
616
650
  if (passed) {
617
651
  cursor.resolveError();
@@ -619,31 +653,28 @@ class Literal {
619
653
  cursor.recordMatch(this, node);
620
654
  return node;
621
655
  }
622
- cursor.recordErrorAt(this._firstIndex, this._endIndex, this);
656
+ cursor.recordErrorAt(this._firstIndex, this._lastIndex, this);
623
657
  return null;
624
658
  }
625
659
  _tryToParse(cursor) {
626
- let passed = false;
627
- const literalRuneLength = this._runes.length;
628
- for (let i = 0; i < literalRuneLength; i++) {
629
- const literalRune = this._runes[i];
630
- const cursorRune = cursor.currentChar;
631
- if (literalRune !== cursorRune) {
632
- this._endIndex = cursor.index;
633
- break;
634
- }
635
- if (i + 1 === literalRuneLength) {
636
- this._lastIndex = this._firstIndex + this._token.length - 1;
637
- passed = true;
638
- break;
639
- }
640
- if (!cursor.hasNext()) {
641
- this._endIndex = cursor.index + 1;
642
- break;
660
+ const token = this._token;
661
+ const compareToToken = cursor.text.slice(this._firstIndex, this._firstIndex + this._token.length);
662
+ const length = Math.min(token.length, compareToToken.length);
663
+ for (let i = 0; i < length; i++) {
664
+ if (token[i] !== compareToToken[i]) {
665
+ this._lastIndex = this._firstIndex + i;
666
+ cursor.moveTo(this._lastIndex);
667
+ return false;
643
668
  }
644
- cursor.next();
645
669
  }
646
- return passed;
670
+ if (token != compareToToken) {
671
+ this._lastIndex = this._firstIndex + compareToToken.length - 1;
672
+ cursor.moveTo(this._lastIndex);
673
+ return false;
674
+ }
675
+ this._lastIndex = this._firstIndex + this._token.length - 1;
676
+ cursor.moveTo(this._lastIndex);
677
+ return true;
647
678
  }
648
679
  _createNode() {
649
680
  return new Node("literal", this._name, this._firstIndex, this._lastIndex, undefined, this._token);
@@ -722,7 +753,7 @@ class Regex {
722
753
  this._name = name;
723
754
  this._parent = null;
724
755
  this._originalRegexString = regex;
725
- this._regex = new RegExp(`^${regex}`, "g");
756
+ this._regex = new RegExp(`^${regex}`, "gu");
726
757
  this.assertArguments();
727
758
  }
728
759
  assertArguments() {
@@ -751,7 +782,7 @@ class Regex {
751
782
  resetState(cursor) {
752
783
  this._cursor = cursor;
753
784
  this._regex.lastIndex = 0;
754
- this._substring = this._cursor.text.substr(this._cursor.index);
785
+ this._substring = this._cursor.text.slice(this._cursor.index);
755
786
  this._node = null;
756
787
  }
757
788
  tryToParse(cursor) {
@@ -765,9 +796,10 @@ class Regex {
765
796
  }
766
797
  processResult(cursor, result) {
767
798
  const currentIndex = cursor.index;
768
- const newIndex = currentIndex + result[0].length - 1;
769
- this._node = new Node("regex", this._name, currentIndex, newIndex, undefined, result[0]);
770
- cursor.moveTo(newIndex);
799
+ const match = result[0];
800
+ const lastIndex = cursor.getCharLastIndex(currentIndex + match.length - 1);
801
+ this._node = new Node("regex", this._name, currentIndex, lastIndex, undefined, result[0]);
802
+ cursor.moveTo(lastIndex);
771
803
  cursor.recordMatch(this, this._node);
772
804
  }
773
805
  processError(cursor) {
@@ -3295,7 +3327,7 @@ class TakeUntil {
3295
3327
  }
3296
3328
  if (foundMatch) {
3297
3329
  cursor.moveTo(cursorIndex - 1);
3298
- const value = cursor.getChars(this.startedOnIndex, cursorIndex - 1);
3330
+ const value = cursor.substring(this.startedOnIndex, cursorIndex - 1);
3299
3331
  const node = Node.createValueNode(this._type, this._name, value);
3300
3332
  cursor.recordMatch(this, node);
3301
3333
  return node;
@@ -3447,7 +3479,7 @@ function generateErrorMessage(pattern, cursor) {
3447
3479
  }
3448
3480
  const lastPattern = furthestMatch.pattern;
3449
3481
  const suggestions = cleanSuggestions(lastPattern.getNextTokens());
3450
- const strUpToError = cursor.getChars(0, endIndex);
3482
+ const strUpToError = cursor.substring(0, endIndex);
3451
3483
  const lines = strUpToError.split("\n");
3452
3484
  const lastLine = lines[lines.length - 1];
3453
3485
  const line = lines.length;
@@ -4185,9 +4217,9 @@ class AutoComplete {
4185
4217
  }
4186
4218
  _createSuggestionOptionsFromErrors() {
4187
4219
  // These errored because the length of the string.
4188
- const errors = this._cursor.errors.filter(e => e.lastIndex === this._cursor.length);
4220
+ const errors = this._cursor.errors.filter(e => e.lastIndex === this._cursor.length - 1);
4189
4221
  const errorSuggestionOptions = errors.map(parseError => {
4190
- const currentText = this._cursor.getChars(parseError.startIndex, parseError.lastIndex);
4222
+ const currentText = this._cursor.substring(parseError.startIndex, parseError.lastIndex);
4191
4223
  const compositeSuggestions = this._getCompositeSuggestionsForPattern(parseError.pattern);
4192
4224
  const trimmedErrorCompositeSuggestions = this._trimSuggestionsByExistingText(currentText, compositeSuggestions);
4193
4225
  return this._createSuggestions(parseError.lastIndex, trimmedErrorCompositeSuggestions);
@@ -4243,7 +4275,7 @@ class AutoComplete {
4243
4275
  * ie. sequence pattern segments ≈ [{look}, {an example}, {phrase}]
4244
4276
  * fullText = "look an"
4245
4277
  * remove {look} segment as its already been completed by the existing text.
4246
- */
4278
+ */
4247
4279
  _filterCompletedSubSegments(currentText, compositeSuggestion) {
4248
4280
  let elementsToRemove = [];
4249
4281
  let workingText = currentText;
@@ -4346,7 +4378,7 @@ class AutoComplete {
4346
4378
  return unique;
4347
4379
  }
4348
4380
  _createSuggestions(lastIndex, compositeSuggestionList) {
4349
- let textToIndex = lastIndex === -1 ? "" : this._cursor.getChars(0, lastIndex);
4381
+ let textToIndex = lastIndex === -1 ? "" : this._cursor.substring(0, lastIndex);
4350
4382
  const options = [];
4351
4383
  for (const compositeSuggestion of compositeSuggestionList) {
4352
4384
  // concatenated for start index identification inside createSuggestion