clarity-pattern-parser 11.3.3 → 11.3.5

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.
@@ -23,6 +23,7 @@ export declare class Expression implements Pattern {
23
23
  private _shouldStopParsing;
24
24
  private _precedenceTree;
25
25
  private _hasOrganized;
26
+ private _atomsIdToAncestorsMap;
26
27
  get id(): string;
27
28
  get type(): string;
28
29
  get name(): string;
@@ -37,6 +38,7 @@ export declare class Expression implements Pattern {
37
38
  get startedOnIndex(): number;
38
39
  constructor(name: string, patterns: Pattern[]);
39
40
  private _organizePatterns;
41
+ private _cacheAncestors;
40
42
  private _extractName;
41
43
  private _isPrefix;
42
44
  private _extractPrefix;
@@ -53,6 +55,7 @@ export declare class Expression implements Pattern {
53
55
  private _tryToParse;
54
56
  private _tryToMatchPrefix;
55
57
  private _tryToMatchAtom;
58
+ private _isBeyondRecursiveAllowance;
56
59
  private _tryToMatchPostfix;
57
60
  private _tryToMatchBinary;
58
61
  test(text: string, record?: boolean): boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clarity-pattern-parser",
3
- "version": "11.3.3",
3
+ "version": "11.3.5",
4
4
  "description": "Parsing Library for Typescript and Javascript.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.esm.js",
@@ -1,9 +1,4 @@
1
- import { Context } from "../patterns/Context";
2
- import { Expression } from "../patterns/Expression";
3
- import { Literal } from "../patterns/Literal";
4
1
  import { Pattern } from "../patterns/Pattern";
5
- import { Regex } from "../patterns/Regex";
6
- import { Repeat } from "../patterns/Repeat";
7
2
  import { IVisitor } from "./ivisitor";
8
3
 
9
4
  export class Generator {
@@ -236,6 +236,39 @@ describe("AutoComplete", () => {
236
236
 
237
237
  });
238
238
 
239
+
240
+ test("Options AutoComplete on Root Pattern", () => {
241
+
242
+ const jack = new Literal("first-name", "Jack");
243
+ const john = new Literal("first-name", "John");
244
+
245
+ const names = new Options('names', [jack,john]);
246
+ const divider = new Literal('divider', ', ');
247
+ const repeat = new Repeat('name-list', names, { divider, trimDivider: true });
248
+
249
+ const text = ''
250
+
251
+ const autoCompleteOptions: AutoCompleteOptions = {
252
+ customTokens: {
253
+ 'first-name': ["James"]
254
+ }
255
+ };
256
+ const autoComplete = new AutoComplete(repeat,autoCompleteOptions);
257
+
258
+ const suggestion = autoComplete.suggestFor(text)
259
+
260
+ console.log('suggestion: ',suggestion)
261
+
262
+ const expectedOptions = [
263
+ { text: "Jack", startIndex: 0 },
264
+ { text: "John", startIndex: 0 },
265
+ { text: "James", startIndex: 0 },
266
+ ];
267
+
268
+ expect(suggestion.options).toEqual(expectedOptions)
269
+
270
+ })
271
+
239
272
  test("Options AutoComplete On Leaf Pattern", () => {
240
273
  const autoCompleteOptions: AutoCompleteOptions = {
241
274
  greedyPatternNames: ["space"],
@@ -648,4 +681,33 @@ describe("AutoComplete", () => {
648
681
  }
649
682
  ]);
650
683
  });
651
- });
684
+
685
+
686
+ test("Calling AutoComplete -> _getAllOptions Does not mutate customTokensMap", () => {
687
+
688
+ const jediLuke = new Literal(`jedi`, 'luke');
689
+ const names = new Options('names', [jediLuke]);
690
+ const divider = new Literal('divider', ', ');
691
+ const pattern = new Repeat('name-list', names, { divider, trimDivider: true });
692
+
693
+ const customTokensMap:Record<string, string[]> = {
694
+ 'jedi': ["leia"]
695
+ }
696
+
697
+ const copiedCustomTokensMap:Record<string, string[]> = JSON.parse(JSON.stringify(customTokensMap));
698
+
699
+ const autoCompleteOptions: AutoCompleteOptions = {
700
+ greedyPatternNames:['jedi'],
701
+ customTokens: customTokensMap
702
+ };
703
+ const autoComplete = new AutoComplete(pattern,autoCompleteOptions);
704
+
705
+ // provide a non-empty input to trigger the logic flow that hits _getAllOptions
706
+ autoComplete.suggestFor('l')
707
+
708
+ expect(customTokensMap).toEqual(copiedCustomTokensMap)
709
+ })
710
+
711
+ });
712
+
713
+
@@ -159,7 +159,7 @@ export class AutoComplete {
159
159
 
160
160
  private _createSuggestionsFromRoot(): SuggestionOption[] {
161
161
  const suggestions: SuggestionOption[] = [];
162
- const tokens = this._pattern.getTokens();
162
+ const tokens = [...this._pattern.getTokens(),... this._getTokensForPattern(this._pattern)];
163
163
 
164
164
  for (const token of tokens) {
165
165
  if (suggestions.findIndex(s => s.text === token) === -1) {
@@ -197,21 +197,21 @@ export class AutoComplete {
197
197
 
198
198
  if (this._options.greedyPatternNames != null && this._options.greedyPatternNames.includes(pattern.name)) {
199
199
  const nextPatterns = pattern.getNextPatterns();
200
- const tokens: string[] = [];
201
-
202
200
  const nextPatternTokens = nextPatterns.reduce((acc: string[], pattern) => {
203
201
  acc.push(...this._getTokensForPattern(pattern));
204
202
  return acc;
205
203
  }, []);
206
-
207
- for (let token of augmentedTokens) {
208
- for (let nextPatternToken of nextPatternTokens) {
209
- tokens.push(token + nextPatternToken);
204
+ // using set to prevent duplicates
205
+ const tokens = new Set<string>();
206
+
207
+ for (const token of augmentedTokens) {
208
+ for (const nextPatternToken of nextPatternTokens) {
209
+ tokens.add(token + nextPatternToken);
210
210
  }
211
211
  }
212
212
 
213
- return tokens;
214
- } else {
213
+ return [...tokens]
214
+ } else {
215
215
  return augmentedTokens;
216
216
  }
217
217
  }
@@ -219,14 +219,22 @@ export class AutoComplete {
219
219
  private _getAugmentedTokens(pattern: Pattern) {
220
220
  const customTokensMap: any = this._options.customTokens || {};
221
221
  const leafPatterns = pattern.getPatterns();
222
- const tokens: string[] = customTokensMap[pattern.name] || [];
223
222
 
224
- leafPatterns.forEach(p => {
225
- const augmentedTokens = customTokensMap[p.name] || [];
226
- tokens.push(...p.getTokens(), ...augmentedTokens);
227
- });
223
+ /** Using Set to
224
+ * - prevent duplicates
225
+ * - prevent mutation of original customTokensMap
226
+ */
227
+ const customTokensForPattern = new Set<string>(customTokensMap[pattern.name] ?? []);
228
+
229
+ for (const lp of leafPatterns) {
230
+ const augmentedTokens = customTokensMap[lp.name] ?? [];
231
+ const lpsCombinedTokens = [...lp.getTokens(), ...augmentedTokens];
228
232
 
229
- return tokens;
233
+ for (const token of lpsCombinedTokens) {
234
+ customTokensForPattern.add(token);
235
+ }
236
+ }
237
+ return [...customTokensForPattern];
230
238
  }
231
239
 
232
240
  private _createSuggestions(lastIndex: number, tokens: string[]): SuggestionOption[] {
@@ -32,6 +32,7 @@ export class Expression implements Pattern {
32
32
  private _shouldStopParsing: boolean;
33
33
  private _precedenceTree: PrecedenceTree;
34
34
  private _hasOrganized: boolean;
35
+ private _atomsIdToAncestorsMap: Record<string, Pattern[]>
35
36
 
36
37
  get id(): string {
37
38
  return this._id;
@@ -106,6 +107,7 @@ export class Expression implements Pattern {
106
107
  this._hasOrganized = false;
107
108
  this._patterns = [];
108
109
  this._precedenceTree = new PrecedenceTree({}, {});
110
+ this._atomsIdToAncestorsMap = {};
109
111
  }
110
112
 
111
113
  private _organizePatterns(patterns: Pattern[]) {
@@ -163,6 +165,21 @@ export class Expression implements Pattern {
163
165
  return finalPatterns;
164
166
  }
165
167
 
168
+ private _cacheAncestors() {
169
+ for (let atom of this._atomPatterns) {
170
+ const id = atom.id;
171
+ const ancestors: Pattern[] = this._atomsIdToAncestorsMap[id] = [];
172
+
173
+ let pattern: Pattern | null = this.parent;
174
+ while (pattern != null) {
175
+ if (pattern.id === id) {
176
+ ancestors.push(pattern);
177
+ }
178
+ pattern = pattern.parent;
179
+ }
180
+ }
181
+ }
182
+
166
183
  private _extractName(pattern: Pattern) {
167
184
  if (pattern.type === "right-associated") {
168
185
  return pattern.children[0].name;
@@ -262,6 +279,7 @@ export class Expression implements Pattern {
262
279
  if (!this._hasOrganized) {
263
280
  this._hasOrganized = true;
264
281
  this._organizePatterns(this._originalPatterns);
282
+ this._cacheAncestors();
265
283
  }
266
284
  }
267
285
 
@@ -367,6 +385,11 @@ export class Expression implements Pattern {
367
385
  cursor.moveTo(onIndex);
368
386
 
369
387
  const pattern = this._atomPatterns[i];
388
+
389
+ if (this._isBeyondRecursiveAllowance(pattern, onIndex)) {
390
+ continue;
391
+ }
392
+
370
393
  const node = pattern.parse(cursor);
371
394
 
372
395
  if (node != null) {
@@ -386,6 +409,11 @@ export class Expression implements Pattern {
386
409
  }
387
410
  }
388
411
 
412
+ private _isBeyondRecursiveAllowance(atom: Pattern, onIndex: number) {
413
+ const ancestors = this._atomsIdToAncestorsMap[atom.id];
414
+ return ancestors.some(a => a.startedOnIndex === onIndex);
415
+ }
416
+
389
417
  private _tryToMatchPostfix(cursor: Cursor) {
390
418
  let onIndex = cursor.index;
391
419
 
@@ -108,7 +108,7 @@ export class Reference implements Pattern {
108
108
  if (pattern.startedOnIndex === this.startedOnIndex) {
109
109
  depth++;
110
110
 
111
- if (depth > 0) {
111
+ if (depth > 1) {
112
112
  return true;
113
113
  }
114
114
  }