clarity-pattern-parser 11.3.9 → 11.3.11

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
@@ -1251,12 +1251,10 @@ class FiniteRepeat {
1251
1251
  }
1252
1252
  }
1253
1253
  }
1254
- if (this._trimDivider && this._hasDivider) {
1255
- const isDividerLastMatch = this.children.length > 1 && nodes.length > 1 && nodes[nodes.length - 1].name === this.children[1].name;
1256
- if (isDividerLastMatch) {
1257
- const node = nodes.pop();
1258
- cursor.moveTo(node.firstIndex);
1259
- }
1254
+ const endedOnDivider = this._hasDivider && nodes.length % modulo === 0;
1255
+ if (this._trimDivider && endedOnDivider) {
1256
+ const node = nodes.pop();
1257
+ cursor.moveTo(node.firstIndex);
1260
1258
  }
1261
1259
  if (matchCount < this._min) {
1262
1260
  const lastIndex = cursor.index;
@@ -1392,6 +1390,7 @@ class InfiniteRepeat {
1392
1390
  this._firstIndex = 0;
1393
1391
  this._nodes = [];
1394
1392
  this._trimDivider = options.trimDivider == null ? false : options.trimDivider;
1393
+ this._patterns = [];
1395
1394
  }
1396
1395
  _assignChildrenToParent(children) {
1397
1396
  for (const child of children) {
@@ -1407,6 +1406,7 @@ class InfiniteRepeat {
1407
1406
  parse(cursor) {
1408
1407
  this._firstIndex = cursor.index;
1409
1408
  this._nodes = [];
1409
+ this._patterns = [];
1410
1410
  const passed = this._tryToParse(cursor);
1411
1411
  if (passed) {
1412
1412
  cursor.resolveError();
@@ -1458,6 +1458,7 @@ class InfiniteRepeat {
1458
1458
  }
1459
1459
  if (repeatNode != null) {
1460
1460
  this._nodes.push(repeatNode);
1461
+ this._patterns.push(this._pattern);
1461
1462
  if (!cursor.hasNext()) {
1462
1463
  passed = true;
1463
1464
  break;
@@ -1482,6 +1483,7 @@ class InfiniteRepeat {
1482
1483
  }
1483
1484
  else {
1484
1485
  this._nodes.push(dividerNode);
1486
+ this._patterns.push(this._divider);
1485
1487
  if (!cursor.hasNext()) {
1486
1488
  passed = true;
1487
1489
  break;
@@ -1504,11 +1506,11 @@ class InfiniteRepeat {
1504
1506
  return passed;
1505
1507
  }
1506
1508
  _createNode(cursor) {
1507
- var _a;
1508
1509
  const hasDivider = this._divider != null;
1510
+ const lastPattern = this._patterns[this._patterns.length - 1];
1509
1511
  if (hasDivider &&
1510
1512
  this._trimDivider &&
1511
- this._nodes[this._nodes.length - 1].name === ((_a = this._divider) === null || _a === void 0 ? void 0 : _a.name)) {
1513
+ lastPattern === this._divider) {
1512
1514
  const dividerNode = this._nodes.pop();
1513
1515
  cursor.moveTo(dividerNode.firstIndex);
1514
1516
  }
@@ -2715,13 +2717,36 @@ class PrecedenceTree {
2715
2717
  }
2716
2718
  _compileAtomNode() {
2717
2719
  let node = this._atomNode;
2718
- if (this._prefixNode != null && this._atomNode != null) {
2719
- node = this._prefixNode.findRoot();
2720
- this._prefixPlaceholder.replaceWith(this._atomNode);
2720
+ if (this._prefixNode != null && this._postfixNode != null && this._atomNode != null) {
2721
+ let firstNode = this._prefixNode;
2722
+ let secondNode = this._postfixNode;
2723
+ let firstPlaceholder = this._prefixPlaceholder;
2724
+ let secondPlaceholder = this._postfixPlaceholder;
2725
+ const prefixName = this._prefixNode.name;
2726
+ const postfixName = this._postfixNode.name;
2727
+ const prefixPrecedence = this._getPrecedence(prefixName);
2728
+ const postfixPrecedence = this._getPrecedence(postfixName);
2729
+ // The Precedence is the index of the patterns, so its lower not higher :\
2730
+ if (prefixPrecedence > postfixPrecedence) {
2731
+ firstNode = this._postfixNode;
2732
+ secondNode = this._prefixNode;
2733
+ firstPlaceholder = this._postfixPlaceholder;
2734
+ secondPlaceholder = this._prefixPlaceholder;
2735
+ }
2736
+ node = firstNode.findRoot();
2737
+ firstPlaceholder.replaceWith(this._atomNode);
2738
+ secondPlaceholder.replaceWith(node);
2739
+ node = secondNode;
2721
2740
  }
2722
- if (this._postfixNode != null && node != null) {
2723
- this._postfixPlaceholder.replaceWith(node);
2724
- node = this._postfixNode;
2741
+ else {
2742
+ if (this._prefixNode != null && this._atomNode != null) {
2743
+ node = this._prefixNode.findRoot();
2744
+ this._prefixPlaceholder.replaceWith(this._atomNode);
2745
+ }
2746
+ if (this._postfixNode != null && node != null) {
2747
+ this._postfixPlaceholder.replaceWith(node);
2748
+ node = this._postfixNode;
2749
+ }
2725
2750
  }
2726
2751
  this._prefixNode = null;
2727
2752
  this._atomNode = null;
@@ -2829,7 +2854,7 @@ class Expression {
2829
2854
  }
2830
2855
  _organizePatterns(patterns) {
2831
2856
  const finalPatterns = [];
2832
- patterns.forEach((pattern) => {
2857
+ patterns.forEach((pattern, index) => {
2833
2858
  if (this._isAtom(pattern)) {
2834
2859
  const atom = pattern.clone();
2835
2860
  atom.parent = this;
@@ -2840,6 +2865,7 @@ class Expression {
2840
2865
  const name = this._extractName(pattern);
2841
2866
  const prefix = this._extractPrefix(pattern);
2842
2867
  prefix.parent = this;
2868
+ this._precedenceMap[name] = index;
2843
2869
  this._prefixPatterns.push(prefix);
2844
2870
  this._prefixNames.push(name);
2845
2871
  finalPatterns.push(prefix);
@@ -2848,6 +2874,7 @@ class Expression {
2848
2874
  const name = this._extractName(pattern);
2849
2875
  const postfix = this._extractPostfix(pattern);
2850
2876
  postfix.parent = this;
2877
+ this._precedenceMap[name] = index;
2851
2878
  this._postfixPatterns.push(postfix);
2852
2879
  this._postfixNames.push(name);
2853
2880
  finalPatterns.push(postfix);
@@ -2856,7 +2883,7 @@ class Expression {
2856
2883
  const name = this._extractName(pattern);
2857
2884
  const binary = this._extractBinary(pattern);
2858
2885
  binary.parent = this;
2859
- this._precedenceMap[name] = this._binaryPatterns.length;
2886
+ this._precedenceMap[name] = index;
2860
2887
  this._binaryPatterns.push(binary);
2861
2888
  this._binaryNames.push(name);
2862
2889
  if (pattern.type === "right-associated") {
@@ -3654,6 +3681,8 @@ class Grammar {
3654
3681
  return this._isRecursivePattern(name, pattern);
3655
3682
  }
3656
3683
  _isRecursivePattern(name, pattern) {
3684
+ // Because we don't know if the pattern is a sequence with a reference we have to just assume it is.
3685
+ // The better solution here would be to not have options at all and just use expresssion pattern instead.
3657
3686
  if (pattern.type === "reference") {
3658
3687
  return true;
3659
3688
  }
@@ -4005,26 +4034,30 @@ class AutoComplete {
4005
4034
  this._options = options;
4006
4035
  this._text = "";
4007
4036
  }
4037
+ suggestFor(text) {
4038
+ return this.suggestForWithCursor(new Cursor(text));
4039
+ }
4008
4040
  suggestForWithCursor(cursor) {
4009
4041
  cursor.moveTo(0);
4010
4042
  this._cursor = cursor;
4011
4043
  this._text = cursor.text;
4012
4044
  this._cursor.startRecording();
4013
4045
  if (cursor.length === 0) {
4014
- return {
4046
+ const suggestion = {
4015
4047
  isComplete: false,
4016
- options: this._createSuggestionsFromRoot(),
4048
+ options: this._createSuggestionOptionsFromMatch(),
4017
4049
  error: new ParseError(0, 0, this._pattern),
4018
4050
  errorAtIndex: 0,
4019
4051
  cursor,
4020
4052
  ast: null
4021
4053
  };
4054
+ return suggestion;
4022
4055
  }
4023
4056
  let errorAtIndex = null;
4024
4057
  let error = null;
4025
4058
  const ast = this._pattern.parse(this._cursor);
4026
4059
  const isComplete = (ast === null || ast === void 0 ? void 0 : ast.value) === this._text;
4027
- const options = this._getAllOptions();
4060
+ const options = this._getAllSuggestionsOptions();
4028
4061
  if (!isComplete && options.length > 0 && !this._cursor.hasError) {
4029
4062
  const startIndex = options.reduce((lowestIndex, o) => {
4030
4063
  return Math.min(lowestIndex, o.startIndex);
@@ -4071,14 +4104,11 @@ class AutoComplete {
4071
4104
  }
4072
4105
  return 0;
4073
4106
  }
4074
- suggestFor(text) {
4075
- return this.suggestForWithCursor(new Cursor(text));
4076
- }
4077
- _getAllOptions() {
4078
- const errorMatches = this._getOptionsFromErrors();
4079
- const leafMatches = this._cursor.leafMatches.map((m) => this._createSuggestionsFromMatch(m)).flat();
4107
+ _getAllSuggestionsOptions() {
4108
+ const errorMatchOptions = this._createSuggestionOptionsFromErrors();
4109
+ const leafMatchOptions = this._cursor.leafMatches.map((m) => this._createSuggestionOptionsFromMatch(m)).flat();
4080
4110
  const finalResults = [];
4081
- [...leafMatches, ...errorMatches].forEach(m => {
4111
+ [...leafMatchOptions, ...errorMatchOptions].forEach(m => {
4082
4112
  const index = finalResults.findIndex(f => m.text === f.text);
4083
4113
  if (index === -1) {
4084
4114
  finalResults.push(m);
@@ -4086,135 +4116,190 @@ class AutoComplete {
4086
4116
  });
4087
4117
  return finalResults;
4088
4118
  }
4089
- _getOptionsFromErrors() {
4119
+ _createSuggestionOptionsFromErrors() {
4090
4120
  // These errored because the length of the string.
4091
4121
  const errors = this._cursor.errors.filter(e => e.lastIndex === this._cursor.length);
4092
- const suggestions = errors.map(e => {
4093
- const tokens = this._getTokensForPattern(e.pattern);
4094
- const adjustedTokens = new Set();
4095
- const currentText = this._cursor.getChars(e.startIndex, e.lastIndex);
4096
- tokens.forEach((token) => {
4097
- if (token.startsWith(currentText) && token.length > currentText.length) {
4098
- const difference = token.length - currentText.length;
4099
- const suggestedText = token.slice(-difference);
4100
- adjustedTokens.add(suggestedText);
4101
- }
4102
- });
4103
- return Array.from(adjustedTokens).map(t => {
4104
- return {
4105
- text: t,
4106
- startIndex: e.lastIndex,
4107
- };
4108
- });
4109
- });
4110
- return suggestions.flat();
4111
- }
4112
- _createSuggestionsFromRoot() {
4113
- const suggestions = [];
4114
- const tokens = [...this._pattern.getTokens(), ...this._getTokensForPattern(this._pattern)];
4115
- for (const token of tokens) {
4116
- if (suggestions.findIndex(s => s.text === token) === -1) {
4117
- suggestions.push(this._createSuggestion("", token));
4118
- }
4119
- }
4120
- return suggestions;
4121
- }
4122
- _createSuggestionsFromMatch(match) {
4123
- if (match.pattern == null) {
4124
- return this._createSuggestions(-1, this._getTokensForPattern(this._pattern));
4125
- }
4126
- if (match.node != null) {
4127
- const textStartingMatch = this._text.slice(match.node.startIndex, match.node.endIndex);
4128
- const currentPatternsTokens = this._getTokensForPattern(match.pattern);
4129
- /**
4130
- * Compares tokens to current text and extracts remainder tokens
4131
- * - IE. **currentText:** *abc*, **baseToken:** *abcdef*, **trailingToken:** *def*
4132
- */
4133
- const trailingTokens = currentPatternsTokens.reduce((acc, token) => {
4134
- if (token.startsWith(textStartingMatch)) {
4135
- const sliced = token.slice(textStartingMatch.length);
4136
- if (sliced !== '') {
4137
- acc.push(sliced);
4138
- }
4139
- }
4140
- return acc;
4141
- }, []);
4122
+ const errorSuggestionOptions = errors.map(parseError => {
4123
+ const currentText = this._cursor.getChars(parseError.startIndex, parseError.lastIndex);
4124
+ const compositeSuggestions = this._getCompositeSuggestionsForPattern(parseError.pattern);
4125
+ const trimmedErrorCompositeSuggestions = this._trimSuggestionsByExistingText(currentText, compositeSuggestions);
4126
+ return this._createSuggestions(parseError.lastIndex, trimmedErrorCompositeSuggestions);
4127
+ }).flat();
4128
+ const dedupedErrorSuggestionOptions = this._deDupeCompositeSuggestions(errorSuggestionOptions);
4129
+ return dedupedErrorSuggestionOptions;
4130
+ }
4131
+ _createSuggestionOptionsFromMatch(match) {
4132
+ if ((match === null || match === void 0 ? void 0 : match.pattern) == null) {
4133
+ const compositeSuggestions = this._getCompositeSuggestionsForPattern(this._pattern);
4134
+ return this._createSuggestions(-1, compositeSuggestions);
4135
+ }
4136
+ if ((match === null || match === void 0 ? void 0 : match.node) != null) {
4137
+ const currentText = this._text.slice(match.node.startIndex, match.node.endIndex);
4138
+ /**Captures suggestions for a "completed" match pattern that still has existing possible suggestions.
4139
+ * particularly relevant when working with set/custom tokens.
4140
+ */
4141
+ const matchCompositeSuggestions = this._getCompositeSuggestionsForPattern(match.pattern);
4142
+ const trimmedMatchCompositeSuggestions = this._trimSuggestionsByExistingText(currentText, matchCompositeSuggestions);
4142
4143
  const leafPatterns = match.pattern.getNextPatterns();
4143
- const leafTokens = leafPatterns.reduce((acc, leafPattern) => {
4144
- acc.push(...this._getTokensForPattern(leafPattern));
4145
- return acc;
4146
- }, []);
4147
- const allTokens = [...trailingTokens, ...leafTokens];
4148
- return this._createSuggestions(match.node.lastIndex, allTokens);
4144
+ const leafCompositeSuggestions = leafPatterns.flatMap(leafPattern => this._getCompositeSuggestionsForPattern(leafPattern));
4145
+ const allCompositeSuggestions = [...leafCompositeSuggestions, ...trimmedMatchCompositeSuggestions,];
4146
+ const dedupedCompositeSuggestions = this._deDupeCompositeSuggestions(allCompositeSuggestions);
4147
+ return this._createSuggestions(match.node.lastIndex, dedupedCompositeSuggestions);
4149
4148
  }
4150
4149
  else {
4151
4150
  return [];
4152
4151
  }
4153
4152
  }
4154
- _getTokensForPattern(pattern) {
4155
- const augmentedTokens = this._getAugmentedTokens(pattern);
4153
+ /**
4154
+ * Compares suggestions with provided text and removes completed sub-sequences and preceding text
4155
+ * - IE. **currentText:** *abc*, **sequence:** *[{ab}{cd}{ef}*
4156
+ * - refines to {d}{ef}
4157
+ */
4158
+ _trimSuggestionsByExistingText(currentText, compositeSuggestions) {
4159
+ const trimmedSuggestions = compositeSuggestions.reduce((acc, compositeSuggestion) => {
4160
+ if (compositeSuggestion.text.startsWith(currentText)) {
4161
+ const filteredSegments = this._filterCompletedSubSegments(currentText, compositeSuggestion);
4162
+ const slicedSuggestionText = compositeSuggestion.text.slice(currentText.length);
4163
+ if (slicedSuggestionText !== '') {
4164
+ const refinedCompositeSuggestion = {
4165
+ text: slicedSuggestionText,
4166
+ suggestionSequence: filteredSegments,
4167
+ };
4168
+ acc.push(refinedCompositeSuggestion);
4169
+ }
4170
+ }
4171
+ return acc;
4172
+ }, []);
4173
+ return trimmedSuggestions;
4174
+ }
4175
+ /** Removed segments already accounted for in the existing text.
4176
+ * ie. sequence pattern segments ≈ [{look}, {an example}, {phrase}]
4177
+ * fullText = "look an"
4178
+ * remove {look} segment as its already been completed by the existing text.
4179
+ */
4180
+ _filterCompletedSubSegments(currentText, compositeSuggestion) {
4181
+ let elementsToRemove = [];
4182
+ let workingText = currentText;
4183
+ compositeSuggestion.suggestionSequence.forEach(segment => {
4184
+ /**sub segment has been completed, remove it from the sequence */
4185
+ if (workingText.startsWith(segment.text)) {
4186
+ workingText = workingText.slice(segment.text.length);
4187
+ elementsToRemove.push(segment);
4188
+ }
4189
+ });
4190
+ const filteredSegments = compositeSuggestion.suggestionSequence.filter(segment => !elementsToRemove.includes(segment));
4191
+ return filteredSegments;
4192
+ }
4193
+ _getCompositeSuggestionsForPattern(pattern) {
4194
+ const suggestionsToReturn = [];
4195
+ const leafPatterns = pattern.getPatterns();
4196
+ // for when pattern has no leafPatterns and only returns itself
4197
+ if (leafPatterns.length === 1 && leafPatterns[0].id === pattern.id) {
4198
+ const currentCustomTokens = this._getCustomTokens(pattern);
4199
+ const currentTokens = pattern.getTokens();
4200
+ const allTokens = [...currentCustomTokens, ...currentTokens];
4201
+ const leafCompositeSuggestions = allTokens.map(token => {
4202
+ const segment = {
4203
+ text: token,
4204
+ pattern: pattern,
4205
+ };
4206
+ const compositeSuggestion = {
4207
+ text: token,
4208
+ suggestionSequence: [segment],
4209
+ };
4210
+ return compositeSuggestion;
4211
+ });
4212
+ suggestionsToReturn.push(...leafCompositeSuggestions);
4213
+ }
4214
+ else {
4215
+ const currentCustomTokens = this._getCustomTokens(pattern);
4216
+ const patternsSuggestionList = currentCustomTokens.map(token => {
4217
+ const segment = {
4218
+ text: token,
4219
+ pattern: pattern,
4220
+ };
4221
+ const patternSuggestion = {
4222
+ text: token,
4223
+ suggestionSequence: [segment],
4224
+ };
4225
+ return patternSuggestion;
4226
+ });
4227
+ const leafCompositeSuggestions = leafPatterns.map(lp => this._getCompositeSuggestionsForPattern(lp)).flat();
4228
+ suggestionsToReturn.push(...patternsSuggestionList, ...leafCompositeSuggestions);
4229
+ }
4156
4230
  if (this._options.greedyPatternNames != null && this._options.greedyPatternNames.includes(pattern.name)) {
4157
4231
  const nextPatterns = pattern.getNextPatterns();
4158
- const nextPatternTokens = nextPatterns.reduce((acc, pattern) => {
4159
- acc.push(...this._getTokensForPattern(pattern));
4232
+ const nextPatternedTokensList = nextPatterns.reduce((acc, pattern) => {
4233
+ const patternedTokensList = this._getCompositeSuggestionsForPattern(pattern);
4234
+ acc.push(...patternedTokensList);
4160
4235
  return acc;
4161
4236
  }, []);
4162
- // using set to prevent duplicates
4163
- const tokens = new Set();
4164
- for (const token of augmentedTokens) {
4165
- for (const nextPatternToken of nextPatternTokens) {
4166
- tokens.add(token + nextPatternToken);
4237
+ const compositeSuggestionList = [];
4238
+ for (const currentSuggestion of suggestionsToReturn) {
4239
+ for (const nextSuggestionWithSubElements of nextPatternedTokensList) {
4240
+ const augmentedTokenWithPattern = {
4241
+ text: currentSuggestion.text + nextSuggestionWithSubElements.text,
4242
+ suggestionSequence: [...currentSuggestion.suggestionSequence, ...nextSuggestionWithSubElements.suggestionSequence],
4243
+ };
4244
+ compositeSuggestionList.push(augmentedTokenWithPattern);
4167
4245
  }
4168
4246
  }
4169
- return [...tokens];
4247
+ return compositeSuggestionList;
4170
4248
  }
4171
4249
  else {
4172
- return augmentedTokens;
4250
+ const dedupedSuggestions = this._deDupeCompositeSuggestions(suggestionsToReturn);
4251
+ return dedupedSuggestions;
4173
4252
  }
4174
4253
  }
4175
- _getAugmentedTokens(pattern) {
4176
- var _a, _b;
4254
+ _getCustomTokens(pattern) {
4255
+ var _a;
4177
4256
  const customTokensMap = this._options.customTokens || {};
4178
- const leafPatterns = pattern.getPatterns();
4179
- /** Using Set to
4180
- * - prevent duplicates
4181
- * - prevent mutation of original customTokensMap
4182
- */
4183
- const customTokensForPattern = new Set((_a = customTokensMap[pattern.name]) !== null && _a !== void 0 ? _a : []);
4184
- for (const lp of leafPatterns) {
4185
- const augmentedTokens = (_b = customTokensMap[lp.name]) !== null && _b !== void 0 ? _b : [];
4186
- const lpsCombinedTokens = [...lp.getTokens(), ...augmentedTokens];
4187
- for (const token of lpsCombinedTokens) {
4188
- customTokensForPattern.add(token);
4257
+ const customTokens = (_a = customTokensMap[pattern.name]) !== null && _a !== void 0 ? _a : [];
4258
+ const allTokens = [...customTokens];
4259
+ return allTokens;
4260
+ }
4261
+ _deDupeCompositeSuggestions(suggestions) {
4262
+ if (this._options.disableDedupe) {
4263
+ return suggestions;
4264
+ }
4265
+ const seen = new Set();
4266
+ const unique = [];
4267
+ for (const suggestion of suggestions) {
4268
+ // Create a unique key based on text and subElements
4269
+ const subElementsKey = suggestion.suggestionSequence
4270
+ .map(sub => ` ${sub.pattern.name} - ${sub.text} `)
4271
+ .sort()
4272
+ .join('|');
4273
+ const key = `${suggestion.text}|${subElementsKey}`;
4274
+ if (!seen.has(key)) {
4275
+ seen.add(key);
4276
+ unique.push(suggestion);
4189
4277
  }
4190
4278
  }
4191
- return [...customTokensForPattern];
4279
+ return unique;
4192
4280
  }
4193
- _createSuggestions(lastIndex, tokens) {
4281
+ _createSuggestions(lastIndex, compositeSuggestionList) {
4194
4282
  let textToIndex = lastIndex === -1 ? "" : this._cursor.getChars(0, lastIndex);
4195
- const suggestionStrings = [];
4196
4283
  const options = [];
4197
- for (const token of tokens) {
4284
+ for (const compositeSuggestion of compositeSuggestionList) {
4198
4285
  // concatenated for start index identification inside createSuggestion
4199
- const suggestion = textToIndex + token;
4200
- const alreadyExist = suggestionStrings.includes(suggestion);
4201
- const isSameAsText = suggestion === this._text;
4202
- if (!alreadyExist && !isSameAsText) {
4203
- suggestionStrings.push(suggestion);
4204
- const suggestionOption = this._createSuggestion(this._cursor.text, suggestion);
4205
- options.push(suggestionOption);
4206
- }
4286
+ const existingTextWithSuggestion = textToIndex + compositeSuggestion.text;
4287
+ existingTextWithSuggestion === this._text;
4288
+ const suggestionOption = this._createSuggestionOption(this._cursor.text, existingTextWithSuggestion, compositeSuggestion.suggestionSequence);
4289
+ options.push(suggestionOption);
4290
+ // }
4207
4291
  }
4208
4292
  const reducedOptions = getFurthestOptions(options);
4209
4293
  reducedOptions.sort((a, b) => a.text.localeCompare(b.text));
4210
4294
  return reducedOptions;
4211
4295
  }
4212
- _createSuggestion(fullText, suggestion) {
4296
+ _createSuggestionOption(fullText, suggestion, segments) {
4213
4297
  const furthestMatch = findMatchIndex(suggestion, fullText);
4214
4298
  const text = suggestion.slice(furthestMatch);
4215
4299
  const option = {
4216
4300
  text: text,
4217
4301
  startIndex: furthestMatch,
4302
+ suggestionSequence: segments,
4218
4303
  };
4219
4304
  return option;
4220
4305
  }