clarity-pattern-parser 11.0.22 → 11.0.23

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.
@@ -13,7 +13,6 @@ export declare class Grammar {
13
13
  private _originResource?;
14
14
  private _resolveImport;
15
15
  private _parseContext;
16
- private _autoComplete;
17
16
  constructor(options?: GrammarOptions);
18
17
  import(path: string): Promise<Record<string, Pattern>>;
19
18
  parse(expression: string): Promise<Record<string, Pattern>>;
@@ -606,6 +606,9 @@
606
606
  _tryToParse(cursor) {
607
607
  let passed = false;
608
608
  const literalRuneLength = this._runes.length;
609
+ if (!cursor.hasNext) {
610
+ return false;
611
+ }
609
612
  for (let i = 0; i < literalRuneLength; i++) {
610
613
  const literalRune = this._runes[i];
611
614
  const cursorRune = cursor.currentChar;
@@ -871,6 +874,7 @@
871
874
  }
872
875
  _cacheAncestors(id) {
873
876
  if (!this._cachedAncestors) {
877
+ this._cachedAncestors = true;
874
878
  let pattern = this.parent;
875
879
  while (pattern != null) {
876
880
  if (pattern.id === id) {
@@ -883,7 +887,7 @@
883
887
  _isBeyondRecursiveAllowance() {
884
888
  let depth = 0;
885
889
  for (let pattern of this._recursiveAncestors) {
886
- if (pattern._firstIndex === this._firstIndex) {
890
+ if (pattern.startedOnIndex === this.startedOnIndex) {
887
891
  depth++;
888
892
  if (depth > 0) {
889
893
  return true;
@@ -1769,7 +1773,7 @@
1769
1773
  else {
1770
1774
  // We are at the end of the text, it may still be valid, if all the
1771
1775
  // following patterns are optional.
1772
- if (this.areRemainingPatternsOptional(i)) {
1776
+ if (this._areRemainingPatternsOptional(i)) {
1773
1777
  passed = true;
1774
1778
  break;
1775
1779
  }
@@ -1788,7 +1792,7 @@
1788
1792
  else {
1789
1793
  // If we don't have any results from what we parsed then record error.
1790
1794
  const lastNode = this.getLastValidNode();
1791
- if (lastNode === null) {
1795
+ if (lastNode === null && !this._areAllPatternsOptional()) {
1792
1796
  cursor.recordErrorAt(this._firstIndex, cursor.index, this);
1793
1797
  break;
1794
1798
  }
@@ -1812,7 +1816,10 @@
1812
1816
  }
1813
1817
  return nodes[nodes.length - 1];
1814
1818
  }
1815
- areRemainingPatternsOptional(fromIndex) {
1819
+ _areAllPatternsOptional() {
1820
+ return this._areRemainingPatternsOptional(-1);
1821
+ }
1822
+ _areRemainingPatternsOptional(fromIndex) {
1816
1823
  const startOnIndex = fromIndex + 1;
1817
1824
  const length = this._children.length;
1818
1825
  for (let i = startOnIndex; i < length; i++) {
@@ -1825,6 +1832,10 @@
1825
1832
  }
1826
1833
  createNode(cursor) {
1827
1834
  const children = filterOutNull(this._nodes);
1835
+ if (children.length === 0) {
1836
+ cursor.moveTo(this._firstIndex);
1837
+ return null;
1838
+ }
1828
1839
  const lastIndex = children[children.length - 1].lastIndex;
1829
1840
  cursor.moveTo(lastIndex);
1830
1841
  return new Node("sequence", this._name, this._firstIndex, lastIndex, children);
@@ -2368,239 +2379,6 @@
2368
2379
  }
2369
2380
  }
2370
2381
 
2371
- const defaultOptions = { greedyPatternNames: [], customTokens: {} };
2372
- class AutoComplete {
2373
- constructor(pattern, options = defaultOptions) {
2374
- this._pattern = pattern;
2375
- this._options = options;
2376
- this._text = "";
2377
- }
2378
- suggestForWithCursor(cursor) {
2379
- cursor.moveTo(0);
2380
- this._cursor = cursor;
2381
- this._text = cursor.text;
2382
- this._cursor.startRecording();
2383
- if (cursor.length === 0) {
2384
- return {
2385
- isComplete: false,
2386
- options: this._createSuggestionsFromRoot(),
2387
- error: new ParseError(0, 0, this._pattern),
2388
- errorAtIndex: 0,
2389
- cursor,
2390
- ast: null
2391
- };
2392
- }
2393
- let errorAtIndex = null;
2394
- let error = null;
2395
- const ast = this._pattern.parse(this._cursor);
2396
- const isComplete = (ast === null || ast === void 0 ? void 0 : ast.value) === this._text;
2397
- const options = this._getAllOptions();
2398
- if (!isComplete && options.length > 0 && !this._cursor.hasError) {
2399
- const startIndex = options.reduce((lowestIndex, o) => {
2400
- return Math.min(lowestIndex, o.startIndex);
2401
- }, Infinity);
2402
- const lastIndex = cursor.getLastIndex() + 1;
2403
- error = new ParseError(startIndex, lastIndex, this._pattern);
2404
- errorAtIndex = startIndex;
2405
- }
2406
- else if (!isComplete && options.length === 0 && ast != null) {
2407
- const startIndex = ast.endIndex;
2408
- const lastIndex = cursor.getLastIndex() + 1;
2409
- error = new ParseError(startIndex, lastIndex, this._pattern);
2410
- errorAtIndex = startIndex;
2411
- }
2412
- else if (!isComplete && this._cursor.hasError && this._cursor.furthestError != null) {
2413
- errorAtIndex = this.getFurthestPosition(cursor);
2414
- error = new ParseError(errorAtIndex, errorAtIndex, this._pattern);
2415
- }
2416
- return {
2417
- isComplete: isComplete,
2418
- options: options,
2419
- error,
2420
- errorAtIndex,
2421
- cursor: cursor,
2422
- ast,
2423
- };
2424
- }
2425
- getFurthestPosition(cursor) {
2426
- const furthestError = cursor.furthestError;
2427
- const furthestMatch = cursor.allMatchedNodes[cursor.allMatchedNodes.length - 1];
2428
- if (furthestError && furthestMatch) {
2429
- if (furthestError.lastIndex > furthestMatch.endIndex) {
2430
- return furthestMatch.endIndex;
2431
- }
2432
- else {
2433
- return furthestError.lastIndex;
2434
- }
2435
- }
2436
- if (furthestError == null && furthestMatch != null) {
2437
- return furthestMatch.endIndex;
2438
- }
2439
- if (furthestMatch == null && furthestError != null) {
2440
- return furthestError.lastIndex;
2441
- }
2442
- return 0;
2443
- }
2444
- suggestFor(text) {
2445
- return this.suggestForWithCursor(new Cursor(text));
2446
- }
2447
- _getAllOptions() {
2448
- const errorMatches = this._getOptionsFromErrors();
2449
- const leafMatches = this._cursor.leafMatches.map((m) => this._createSuggestionsFromMatch(m)).flat();
2450
- const finalResults = [];
2451
- [...leafMatches, ...errorMatches].forEach(m => {
2452
- const index = finalResults.findIndex(f => m.text === f.text);
2453
- if (index === -1) {
2454
- finalResults.push(m);
2455
- }
2456
- });
2457
- return finalResults;
2458
- }
2459
- _getOptionsFromErrors() {
2460
- // These errored because the length of the string.
2461
- const errors = this._cursor.errors.filter(e => e.lastIndex === this._cursor.length);
2462
- const suggestions = errors.map(e => {
2463
- const tokens = this._getTokensForPattern(e.pattern);
2464
- const adjustedTokens = new Set();
2465
- const currentText = this._cursor.getChars(e.startIndex, e.lastIndex);
2466
- tokens.forEach((token) => {
2467
- if (token.startsWith(currentText) && token.length > currentText.length) {
2468
- const difference = token.length - currentText.length;
2469
- const suggestedText = token.slice(-difference);
2470
- adjustedTokens.add(suggestedText);
2471
- }
2472
- });
2473
- return Array.from(adjustedTokens).map(t => {
2474
- return {
2475
- text: t,
2476
- startIndex: e.lastIndex,
2477
- };
2478
- });
2479
- });
2480
- return suggestions.flat();
2481
- }
2482
- _createSuggestionsFromRoot() {
2483
- const suggestions = [];
2484
- const tokens = this._pattern.getTokens();
2485
- for (const token of tokens) {
2486
- if (suggestions.findIndex(s => s.text === token) === -1) {
2487
- suggestions.push(this._createSuggestion("", token));
2488
- }
2489
- }
2490
- return suggestions;
2491
- }
2492
- _createSuggestionsFromMatch(match) {
2493
- if (match.pattern == null) {
2494
- return this._createSuggestions(-1, this._getTokensForPattern(this._pattern));
2495
- }
2496
- const leafPattern = match.pattern;
2497
- const parent = match.pattern.parent;
2498
- if (parent !== null && match.node != null) {
2499
- const patterns = leafPattern.getNextPatterns();
2500
- const tokens = patterns.reduce((acc, pattern) => {
2501
- acc.push(...this._getTokensForPattern(pattern));
2502
- return acc;
2503
- }, []);
2504
- return this._createSuggestions(match.node.lastIndex, tokens);
2505
- }
2506
- else {
2507
- return [];
2508
- }
2509
- }
2510
- _getTokensForPattern(pattern) {
2511
- const augmentedTokens = this._getAugmentedTokens(pattern);
2512
- if (this._options.greedyPatternNames != null && this._options.greedyPatternNames.includes(pattern.name)) {
2513
- const nextPatterns = pattern.getNextPatterns();
2514
- const tokens = [];
2515
- const nextPatternTokens = nextPatterns.reduce((acc, pattern) => {
2516
- acc.push(...this._getTokensForPattern(pattern));
2517
- return acc;
2518
- }, []);
2519
- for (let token of augmentedTokens) {
2520
- for (let nextPatternToken of nextPatternTokens) {
2521
- tokens.push(token + nextPatternToken);
2522
- }
2523
- }
2524
- return tokens;
2525
- }
2526
- else {
2527
- return augmentedTokens;
2528
- }
2529
- }
2530
- _getAugmentedTokens(pattern) {
2531
- const customTokensMap = this._options.customTokens || {};
2532
- const leafPatterns = pattern.getPatterns();
2533
- const tokens = customTokensMap[pattern.name] || [];
2534
- leafPatterns.forEach(p => {
2535
- const augmentedTokens = customTokensMap[p.name] || [];
2536
- tokens.push(...p.getTokens(), ...augmentedTokens);
2537
- });
2538
- return tokens;
2539
- }
2540
- _createSuggestions(lastIndex, tokens) {
2541
- let substring = lastIndex === -1 ? "" : this._cursor.getChars(0, lastIndex);
2542
- const suggestionStrings = [];
2543
- const options = [];
2544
- for (const token of tokens) {
2545
- const suggestion = substring + token;
2546
- const startsWith = suggestion.startsWith(substring);
2547
- const alreadyExist = suggestionStrings.includes(suggestion);
2548
- const isSameAsText = suggestion === this._text;
2549
- if (startsWith && !alreadyExist && !isSameAsText) {
2550
- suggestionStrings.push(suggestion);
2551
- options.push(this._createSuggestion(this._cursor.text, suggestion));
2552
- }
2553
- }
2554
- const reducedOptions = getFurthestOptions(options);
2555
- reducedOptions.sort((a, b) => a.text.localeCompare(b.text));
2556
- return reducedOptions;
2557
- }
2558
- _createSuggestion(fullText, suggestion) {
2559
- const furthestMatch = findMatchIndex(suggestion, fullText);
2560
- const text = suggestion.slice(furthestMatch);
2561
- return {
2562
- text: text,
2563
- startIndex: furthestMatch,
2564
- };
2565
- }
2566
- static suggestFor(text, pattern, options) {
2567
- return new AutoComplete(pattern, options).suggestFor(text);
2568
- }
2569
- static suggestForWithCursor(cursor, pattern, options) {
2570
- return new AutoComplete(pattern, options).suggestForWithCursor(cursor);
2571
- }
2572
- }
2573
- function findMatchIndex(str1, str2) {
2574
- let matchCount = 0;
2575
- let minLength = str1.length;
2576
- if (str2.length < minLength) {
2577
- minLength = str2.length;
2578
- }
2579
- for (let i = 0; i < minLength; i++) {
2580
- if (str1[i] === str2[i]) {
2581
- matchCount++;
2582
- }
2583
- else {
2584
- break;
2585
- }
2586
- }
2587
- return matchCount;
2588
- }
2589
- function getFurthestOptions(options) {
2590
- let furthestOptions = [];
2591
- let furthestIndex = -1;
2592
- for (const option of options) {
2593
- if (option.startIndex > furthestIndex) {
2594
- furthestIndex = option.startIndex;
2595
- furthestOptions = [];
2596
- }
2597
- if (option.startIndex === furthestIndex) {
2598
- furthestOptions.push(option);
2599
- }
2600
- }
2601
- return furthestOptions;
2602
- }
2603
-
2604
2382
  let contextId = 0;
2605
2383
  class Context {
2606
2384
  get id() {
@@ -3363,6 +3141,30 @@
3363
3141
  }
3364
3142
  }
3365
3143
 
3144
+ function generateErrorMessage(pattern, cursor) {
3145
+ const furthestMatch = cursor.leafMatch;
3146
+ if (furthestMatch == null || furthestMatch.node == null || furthestMatch.pattern == null) {
3147
+ const suggestions = cleanSuggestions(pattern.getTokens()).join(", ");
3148
+ return `Error at line 1, column 1. Hint: ${suggestions}`;
3149
+ }
3150
+ const endIndex = furthestMatch.node.endIndex;
3151
+ if (endIndex === 0) {
3152
+ const suggestions = cleanSuggestions(pattern.getTokens()).join(", ");
3153
+ return `Error at line 1, column 1. Hint: ${suggestions}`;
3154
+ }
3155
+ const lastPattern = furthestMatch.pattern;
3156
+ const suggestions = cleanSuggestions(lastPattern.getTokens());
3157
+ const strUpToError = cursor.getChars(0, endIndex);
3158
+ const lines = strUpToError.split("\n");
3159
+ const lastLine = lines[lines.length - 1];
3160
+ const line = lines.length;
3161
+ const column = lastLine.length;
3162
+ return `Error at line ${line}, column ${column}. Hint: ${suggestions}`;
3163
+ }
3164
+ function cleanSuggestions(suggestions) {
3165
+ return suggestions.map(s => s.trim()).filter(s => s.length > 0);
3166
+ }
3167
+
3366
3168
  let anonymousIndexId = 0;
3367
3169
  const patternNodes = {
3368
3170
  "literal": true,
@@ -3390,9 +3192,6 @@
3390
3192
  this._originResource = (options === null || options === void 0 ? void 0 : options.originResource) == null ? null : options.originResource;
3391
3193
  this._resolveImport = options.resolveImport == null ? defaultImportResolver : options.resolveImport;
3392
3194
  this._parseContext = new ParseContext(this._params);
3393
- this._autoComplete = new AutoComplete(grammar, {
3394
- greedyPatternNames: ["spaces", "optional-spaces", "whitespace", "new-line"],
3395
- });
3396
3195
  }
3397
3196
  import(path) {
3398
3197
  return __awaiter(this, void 0, void 0, function* () {
@@ -3432,19 +3231,11 @@
3432
3231
  return patterns;
3433
3232
  }
3434
3233
  _tryToParse(expression) {
3435
- const { ast, cursor, options, isComplete } = this._autoComplete.suggestFor(expression);
3436
- if (!isComplete) {
3437
- const text = (cursor === null || cursor === void 0 ? void 0 : cursor.text) || "";
3438
- const index = options.reduce((num, o) => Math.max(o.startIndex, num), 0);
3439
- const foundText = text.slice(Math.max(index - 10, 0), index + 10);
3440
- const expectedTexts = "'" + options.map(o => {
3441
- const startText = text.slice(Math.max(o.startIndex - 10), o.startIndex);
3442
- return startText + o.text;
3443
- }).join("' or '") + "'";
3444
- const message = `[Parse Error] Found: '${foundText}', expected: ${expectedTexts}.`;
3445
- throw new Error(message);
3446
- }
3447
- // If it is complete it will always have a node. So we have to cast it.
3234
+ const { ast, cursor } = grammar.exec(expression, true);
3235
+ if (ast == null) {
3236
+ const message = generateErrorMessage(grammar, cursor);
3237
+ throw new Error(`[Invalid Grammar] ${message}`);
3238
+ }
3448
3239
  return ast;
3449
3240
  }
3450
3241
  _hasImports(ast) {
@@ -3811,6 +3602,239 @@
3811
3602
  }
3812
3603
  }
3813
3604
 
3605
+ const defaultOptions = { greedyPatternNames: [], customTokens: {} };
3606
+ class AutoComplete {
3607
+ constructor(pattern, options = defaultOptions) {
3608
+ this._pattern = pattern;
3609
+ this._options = options;
3610
+ this._text = "";
3611
+ }
3612
+ suggestForWithCursor(cursor) {
3613
+ cursor.moveTo(0);
3614
+ this._cursor = cursor;
3615
+ this._text = cursor.text;
3616
+ this._cursor.startRecording();
3617
+ if (cursor.length === 0) {
3618
+ return {
3619
+ isComplete: false,
3620
+ options: this._createSuggestionsFromRoot(),
3621
+ error: new ParseError(0, 0, this._pattern),
3622
+ errorAtIndex: 0,
3623
+ cursor,
3624
+ ast: null
3625
+ };
3626
+ }
3627
+ let errorAtIndex = null;
3628
+ let error = null;
3629
+ const ast = this._pattern.parse(this._cursor);
3630
+ const isComplete = (ast === null || ast === void 0 ? void 0 : ast.value) === this._text;
3631
+ const options = this._getAllOptions();
3632
+ if (!isComplete && options.length > 0 && !this._cursor.hasError) {
3633
+ const startIndex = options.reduce((lowestIndex, o) => {
3634
+ return Math.min(lowestIndex, o.startIndex);
3635
+ }, Infinity);
3636
+ const lastIndex = cursor.getLastIndex() + 1;
3637
+ error = new ParseError(startIndex, lastIndex, this._pattern);
3638
+ errorAtIndex = startIndex;
3639
+ }
3640
+ else if (!isComplete && options.length === 0 && ast != null) {
3641
+ const startIndex = ast.endIndex;
3642
+ const lastIndex = cursor.getLastIndex() + 1;
3643
+ error = new ParseError(startIndex, lastIndex, this._pattern);
3644
+ errorAtIndex = startIndex;
3645
+ }
3646
+ else if (!isComplete && this._cursor.hasError && this._cursor.furthestError != null) {
3647
+ errorAtIndex = this.getFurthestPosition(cursor);
3648
+ error = new ParseError(errorAtIndex, errorAtIndex, this._pattern);
3649
+ }
3650
+ return {
3651
+ isComplete: isComplete,
3652
+ options: options,
3653
+ error,
3654
+ errorAtIndex,
3655
+ cursor: cursor,
3656
+ ast,
3657
+ };
3658
+ }
3659
+ getFurthestPosition(cursor) {
3660
+ const furthestError = cursor.furthestError;
3661
+ const furthestMatch = cursor.allMatchedNodes[cursor.allMatchedNodes.length - 1];
3662
+ if (furthestError && furthestMatch) {
3663
+ if (furthestError.lastIndex > furthestMatch.endIndex) {
3664
+ return furthestMatch.endIndex;
3665
+ }
3666
+ else {
3667
+ return furthestError.lastIndex;
3668
+ }
3669
+ }
3670
+ if (furthestError == null && furthestMatch != null) {
3671
+ return furthestMatch.endIndex;
3672
+ }
3673
+ if (furthestMatch == null && furthestError != null) {
3674
+ return furthestError.lastIndex;
3675
+ }
3676
+ return 0;
3677
+ }
3678
+ suggestFor(text) {
3679
+ return this.suggestForWithCursor(new Cursor(text));
3680
+ }
3681
+ _getAllOptions() {
3682
+ const errorMatches = this._getOptionsFromErrors();
3683
+ const leafMatches = this._cursor.leafMatches.map((m) => this._createSuggestionsFromMatch(m)).flat();
3684
+ const finalResults = [];
3685
+ [...leafMatches, ...errorMatches].forEach(m => {
3686
+ const index = finalResults.findIndex(f => m.text === f.text);
3687
+ if (index === -1) {
3688
+ finalResults.push(m);
3689
+ }
3690
+ });
3691
+ return finalResults;
3692
+ }
3693
+ _getOptionsFromErrors() {
3694
+ // These errored because the length of the string.
3695
+ const errors = this._cursor.errors.filter(e => e.lastIndex === this._cursor.length);
3696
+ const suggestions = errors.map(e => {
3697
+ const tokens = this._getTokensForPattern(e.pattern);
3698
+ const adjustedTokens = new Set();
3699
+ const currentText = this._cursor.getChars(e.startIndex, e.lastIndex);
3700
+ tokens.forEach((token) => {
3701
+ if (token.startsWith(currentText) && token.length > currentText.length) {
3702
+ const difference = token.length - currentText.length;
3703
+ const suggestedText = token.slice(-difference);
3704
+ adjustedTokens.add(suggestedText);
3705
+ }
3706
+ });
3707
+ return Array.from(adjustedTokens).map(t => {
3708
+ return {
3709
+ text: t,
3710
+ startIndex: e.lastIndex,
3711
+ };
3712
+ });
3713
+ });
3714
+ return suggestions.flat();
3715
+ }
3716
+ _createSuggestionsFromRoot() {
3717
+ const suggestions = [];
3718
+ const tokens = this._pattern.getTokens();
3719
+ for (const token of tokens) {
3720
+ if (suggestions.findIndex(s => s.text === token) === -1) {
3721
+ suggestions.push(this._createSuggestion("", token));
3722
+ }
3723
+ }
3724
+ return suggestions;
3725
+ }
3726
+ _createSuggestionsFromMatch(match) {
3727
+ if (match.pattern == null) {
3728
+ return this._createSuggestions(-1, this._getTokensForPattern(this._pattern));
3729
+ }
3730
+ const leafPattern = match.pattern;
3731
+ const parent = match.pattern.parent;
3732
+ if (parent !== null && match.node != null) {
3733
+ const patterns = leafPattern.getNextPatterns();
3734
+ const tokens = patterns.reduce((acc, pattern) => {
3735
+ acc.push(...this._getTokensForPattern(pattern));
3736
+ return acc;
3737
+ }, []);
3738
+ return this._createSuggestions(match.node.lastIndex, tokens);
3739
+ }
3740
+ else {
3741
+ return [];
3742
+ }
3743
+ }
3744
+ _getTokensForPattern(pattern) {
3745
+ const augmentedTokens = this._getAugmentedTokens(pattern);
3746
+ if (this._options.greedyPatternNames != null && this._options.greedyPatternNames.includes(pattern.name)) {
3747
+ const nextPatterns = pattern.getNextPatterns();
3748
+ const tokens = [];
3749
+ const nextPatternTokens = nextPatterns.reduce((acc, pattern) => {
3750
+ acc.push(...this._getTokensForPattern(pattern));
3751
+ return acc;
3752
+ }, []);
3753
+ for (let token of augmentedTokens) {
3754
+ for (let nextPatternToken of nextPatternTokens) {
3755
+ tokens.push(token + nextPatternToken);
3756
+ }
3757
+ }
3758
+ return tokens;
3759
+ }
3760
+ else {
3761
+ return augmentedTokens;
3762
+ }
3763
+ }
3764
+ _getAugmentedTokens(pattern) {
3765
+ const customTokensMap = this._options.customTokens || {};
3766
+ const leafPatterns = pattern.getPatterns();
3767
+ const tokens = customTokensMap[pattern.name] || [];
3768
+ leafPatterns.forEach(p => {
3769
+ const augmentedTokens = customTokensMap[p.name] || [];
3770
+ tokens.push(...p.getTokens(), ...augmentedTokens);
3771
+ });
3772
+ return tokens;
3773
+ }
3774
+ _createSuggestions(lastIndex, tokens) {
3775
+ let substring = lastIndex === -1 ? "" : this._cursor.getChars(0, lastIndex);
3776
+ const suggestionStrings = [];
3777
+ const options = [];
3778
+ for (const token of tokens) {
3779
+ const suggestion = substring + token;
3780
+ const startsWith = suggestion.startsWith(substring);
3781
+ const alreadyExist = suggestionStrings.includes(suggestion);
3782
+ const isSameAsText = suggestion === this._text;
3783
+ if (startsWith && !alreadyExist && !isSameAsText) {
3784
+ suggestionStrings.push(suggestion);
3785
+ options.push(this._createSuggestion(this._cursor.text, suggestion));
3786
+ }
3787
+ }
3788
+ const reducedOptions = getFurthestOptions(options);
3789
+ reducedOptions.sort((a, b) => a.text.localeCompare(b.text));
3790
+ return reducedOptions;
3791
+ }
3792
+ _createSuggestion(fullText, suggestion) {
3793
+ const furthestMatch = findMatchIndex(suggestion, fullText);
3794
+ const text = suggestion.slice(furthestMatch);
3795
+ return {
3796
+ text: text,
3797
+ startIndex: furthestMatch,
3798
+ };
3799
+ }
3800
+ static suggestFor(text, pattern, options) {
3801
+ return new AutoComplete(pattern, options).suggestFor(text);
3802
+ }
3803
+ static suggestForWithCursor(cursor, pattern, options) {
3804
+ return new AutoComplete(pattern, options).suggestForWithCursor(cursor);
3805
+ }
3806
+ }
3807
+ function findMatchIndex(str1, str2) {
3808
+ let matchCount = 0;
3809
+ let minLength = str1.length;
3810
+ if (str2.length < minLength) {
3811
+ minLength = str2.length;
3812
+ }
3813
+ for (let i = 0; i < minLength; i++) {
3814
+ if (str1[i] === str2[i]) {
3815
+ matchCount++;
3816
+ }
3817
+ else {
3818
+ break;
3819
+ }
3820
+ }
3821
+ return matchCount;
3822
+ }
3823
+ function getFurthestOptions(options) {
3824
+ let furthestOptions = [];
3825
+ let furthestIndex = -1;
3826
+ for (const option of options) {
3827
+ if (option.startIndex > furthestIndex) {
3828
+ furthestIndex = option.startIndex;
3829
+ furthestOptions = [];
3830
+ }
3831
+ if (option.startIndex === furthestIndex) {
3832
+ furthestOptions.push(option);
3833
+ }
3834
+ }
3835
+ return furthestOptions;
3836
+ }
3837
+
3814
3838
  const kebabRegex = /-([a-z])/g; // Define the regex once
3815
3839
  function kebabToCamelCase(str) {
3816
3840
  return str.replace(kebabRegex, (_, char) => char.toUpperCase());