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.
- package/dist/index.browser.js +23 -1
- package/dist/index.browser.js.map +1 -1
- package/dist/index.esm.js +23 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +23 -1
- package/dist/index.js.map +1 -1
- package/dist/patterns/Expression.d.ts +3 -0
- package/package.json +1 -1
- package/src/generator/generator.ts +0 -5
- package/src/intellisense/AutoComplete.test.ts +63 -1
- package/src/intellisense/AutoComplete.ts +23 -15
- package/src/patterns/Expression.ts +28 -0
- package/src/patterns/Reference.ts +1 -1
|
@@ -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,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
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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
|
-
|
|
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
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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
|
-
|
|
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
|
|