clarity-pattern-parser 5.0.0 → 6.0.0

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.
Files changed (53) hide show
  1. package/README.md +328 -38
  2. package/TODO.md +55 -1
  3. package/dist/ast/Node.d.ts +8 -2
  4. package/dist/index.browser.js +470 -205
  5. package/dist/index.browser.js.map +1 -1
  6. package/dist/index.d.ts +6 -1
  7. package/dist/index.esm.js +469 -206
  8. package/dist/index.esm.js.map +1 -1
  9. package/dist/index.js +470 -205
  10. package/dist/index.js.map +1 -1
  11. package/dist/intellisense/AutoComplete.d.ts +28 -0
  12. package/dist/intellisense/Suggestion.d.ts +11 -0
  13. package/dist/intellisense/SuggestionOption.d.ts +4 -0
  14. package/dist/patterns/And.d.ts +7 -7
  15. package/dist/patterns/Cursor.d.ts +6 -4
  16. package/dist/patterns/CursorHistory.d.ts +2 -2
  17. package/dist/patterns/Literal.d.ts +7 -8
  18. package/dist/patterns/Not.d.ts +8 -5
  19. package/dist/patterns/Or.d.ts +7 -5
  20. package/dist/patterns/Pattern.d.ts +7 -4
  21. package/dist/patterns/Reference.d.ts +10 -7
  22. package/dist/patterns/Regex.d.ts +7 -8
  23. package/dist/patterns/Repeat.d.ts +7 -7
  24. package/package.json +1 -1
  25. package/src/ast/Node.test.ts +110 -0
  26. package/src/ast/Node.ts +71 -5
  27. package/src/index.ts +14 -3
  28. package/src/intellisense/AutoComplete.test.ts +90 -12
  29. package/src/intellisense/AutoComplete.ts +66 -12
  30. package/src/intellisense/Suggestion.ts +3 -4
  31. package/src/intellisense/javascript/Javascript.test.ts +56 -56
  32. package/src/intellisense/javascript/escapedCharacter.ts +0 -1
  33. package/src/intellisense/javascript/exponent.ts +0 -2
  34. package/src/intellisense/javascript/fraction.ts +0 -2
  35. package/src/patterns/And.test.ts +63 -52
  36. package/src/patterns/And.ts +58 -36
  37. package/src/patterns/Cursor.ts +17 -14
  38. package/src/patterns/CursorHistory.ts +8 -8
  39. package/src/patterns/Literal.test.ts +70 -38
  40. package/src/patterns/Literal.ts +31 -42
  41. package/src/patterns/Not.test.ts +88 -8
  42. package/src/patterns/Not.ts +54 -14
  43. package/src/patterns/Or.test.ts +117 -13
  44. package/src/patterns/Or.ts +36 -13
  45. package/src/patterns/Pattern.ts +7 -4
  46. package/src/patterns/Reference.test.ts +117 -28
  47. package/src/patterns/Reference.ts +58 -32
  48. package/src/patterns/Regex.test.ts +67 -35
  49. package/src/patterns/Regex.ts +31 -43
  50. package/src/patterns/Repeat.test.ts +63 -41
  51. package/src/patterns/Repeat.ts +51 -38
  52. package/src/patterns/getNextPattern.test.ts +0 -39
  53. package/src/patterns/getNextPattern.ts +0 -18
@@ -15,6 +15,25 @@ describe("Node", () => {
15
15
  expect(node.children.length).toBe(0);
16
16
  });
17
17
 
18
+ test("Properties", () => {
19
+ const child = new Node("child", "child", 0, 0, undefined, "Content")
20
+ const parent = new Node("parent", "parent", 0, 0, [
21
+ child,
22
+ ]);
23
+
24
+ expect(parent.hasChildren).toBeTruthy();
25
+ expect(child.parent).toBe(parent);
26
+ expect(parent.children[0]).toBe(child);
27
+ expect(child.type).toBe("child");
28
+ expect(parent.value).toBe("Content");
29
+ expect(child.value).toBe("Content");
30
+ expect(child.name).toBe("child");
31
+ expect(child.firstIndex).toBe(0);
32
+ expect(child.lastIndex).toBe(0);
33
+ expect(child.startIndex).toBe(0);
34
+ expect(child.endIndex).toBe(1);
35
+ });
36
+
18
37
  test("Create Tree", () => {
19
38
  const child = new Node("child", "child", 0, 0, [], "Child");
20
39
  const parent = new Node("parent", "parent", 0, 0, [child]);
@@ -164,6 +183,56 @@ describe("Node", () => {
164
183
  expect(b.value).toBe("B");
165
184
  });
166
185
 
186
+ test("Next Sibling", () => {
187
+ const a = new Node("a", "a", 0, 0, [], "A");
188
+ const b = new Node("b", "b", 0, 0, [], "B");
189
+ new Node("parent", "parent", 0, 0, [a, b]);
190
+
191
+ const nextSibling = a.nextSibling()
192
+
193
+ expect(nextSibling).toBe(b);
194
+ });
195
+
196
+ test("Next Sibling (No Parent)", () => {
197
+ const a = new Node("a", "a", 0, 0, [], "A");
198
+
199
+ const nextSibling = a.nextSibling()
200
+ expect(nextSibling).toBeNull;
201
+ });
202
+
203
+ test("Next Sibling (Last Child)", () => {
204
+ const a = new Node("a", "a", 0, 0, [], "A");
205
+ const b = new Node("b", "b", 0, 0, [], "B");
206
+ new Node("parent", "parent", 0, 0, [a, b]);
207
+
208
+ const nextSibling = b.nextSibling()
209
+ expect(nextSibling).toBeNull;
210
+ });
211
+
212
+ test("Previous Sibling", () => {
213
+ const a = new Node("a", "a", 0, 0, [], "A");
214
+ const b = new Node("b", "b", 0, 0, [], "B");
215
+ new Node("parent", "parent", 0, 0, [a, b]);
216
+
217
+ const previousSibling = b.previousSibling()
218
+
219
+ expect(previousSibling).toBe(a);
220
+ });
221
+
222
+ test("Previous Sibling (No Parent)", () => {
223
+ const a = new Node("a", "a", 0, 0, [], "A");
224
+ const previousSibling = a.previousSibling()
225
+ expect(previousSibling).toBeNull();
226
+ });
227
+
228
+ test("Previous Sibling (First Child)", () => {
229
+ const a = new Node("a", "a", 0, 0, [], "A");
230
+ const b = new Node("b", "b", 0, 0, [], "B");
231
+ new Node("parent", "parent", 0, 0, [a, b]);
232
+
233
+ const previousSibling = a.previousSibling()
234
+ expect(previousSibling).toBeNull;
235
+ });
167
236
 
168
237
  test("Find", () => {
169
238
  const a = new Node("a", "a", 0, 0, [], "A");
@@ -251,4 +320,45 @@ describe("Node", () => {
251
320
  expect(result).toEqual(expected)
252
321
  });
253
322
 
323
+ test("Reduce", () => {
324
+ const parent = new Node("parent", "parent", 0, 6, [
325
+ new Node("child", "child", 0, 6, undefined, "Content")
326
+ ]);
327
+
328
+ parent.reduce();
329
+
330
+ expect(parent.hasChildren).toBeFalsy();
331
+ expect(parent.value).toBe("Content")
332
+ });
333
+
334
+ test("Flatten", () => {
335
+ const a = new Node("a", "a", 0, 0, [], "A");
336
+ const b = new Node("b", "b", 1, 1, [], "B");
337
+ const c = new Node("c", "c", 2, 2, [], "C");
338
+
339
+ const parent = new Node("parent", "parent", 0, 1, [
340
+ a,
341
+ b,
342
+ ]);
343
+
344
+ const grandParent = new Node("grand-parent", "grand-parent", 0, 2, [
345
+ parent,
346
+ c,
347
+ ]);
348
+
349
+ const nodes = grandParent.flatten();
350
+ const expected = [a, b, c];
351
+
352
+ expect(nodes).toEqual(expected)
353
+ });
354
+
355
+ test("Find Ancester", () => {
356
+ const child = new Node("child", "child", 0, 0, []);
357
+ const parent = new Node("parent", "parent", 0, 0, [child]);
358
+ const grandParent = new Node("grand-parent", "grand-parent", 0, 0, [parent]);
359
+ const result = child.findAncester(p => p.name === "grand-parent")
360
+
361
+ expect(result).toBe(grandParent)
362
+ });
363
+
254
364
  });
package/src/ast/Node.ts CHANGED
@@ -50,6 +50,10 @@ export class Node {
50
50
  return this._children;
51
51
  }
52
52
 
53
+ get hasChildren(): boolean {
54
+ return this._children.length > 0;
55
+ }
56
+
53
57
  get value() {
54
58
  return this.toString();
55
59
  }
@@ -120,25 +124,69 @@ export class Node {
120
124
  spliceChildren(index: number, deleteCount: number, ...items: Node[]) {
121
125
  const removedItems = this._children.splice(index, deleteCount, ...items);
122
126
 
123
- items.forEach(i => i._parent = this);
124
127
  removedItems.forEach(i => i._parent = null);
128
+ items.forEach(i => i._parent = this);
125
129
 
126
130
  return removedItems;
127
131
  }
128
132
 
129
- find(isMatch: (node: Node) => boolean): Node | null {
130
- return this.findAll(isMatch)[0] || null
133
+ nextSibling() {
134
+ if (this._parent == null) {
135
+ return null;
136
+ }
137
+
138
+ const children = this._parent._children;
139
+ const index = children.indexOf(this);
140
+
141
+ if (index > -1 && index < children.length - 1) {
142
+ return children[index + 1]
143
+ }
144
+
145
+ return null
146
+ }
147
+
148
+ previousSibling() {
149
+ if (this._parent == null) {
150
+ return null;
151
+ }
152
+
153
+ const children = this._parent._children;
154
+ const index = children.indexOf(this);
155
+
156
+ if (index > -1 && index > 0) {
157
+ return children[index - 1]
158
+ }
159
+
160
+ return null
131
161
  }
132
162
 
133
- findAll(isMatch: (node: Node) => boolean): Node[] {
163
+ find(predicate: (node: Node) => boolean): Node | null {
164
+ return this.findAll(predicate)[0] || null
165
+ }
166
+
167
+ findAll(predicate: (node: Node) => boolean): Node[] {
134
168
  const matches: Node[] = [];
135
169
  this.walkUp(n => {
136
- if (isMatch(n)) { matches.push(n); }
170
+ if (predicate(n)) { matches.push(n); }
137
171
  })
138
172
 
139
173
  return matches;
140
174
  }
141
175
 
176
+ findAncester(predicate: (node: Node) => boolean){
177
+ let parent = this._parent;
178
+
179
+ while(parent != null){
180
+ if (predicate(parent)){
181
+ return parent;
182
+ }
183
+
184
+ parent = parent._parent;
185
+ }
186
+
187
+ return null;
188
+ }
189
+
142
190
  walkUp(callback: (node: Node) => void) {
143
191
  this.children.forEach(c => c.walkUp(callback))
144
192
  callback(this);
@@ -149,6 +197,24 @@ export class Node {
149
197
  this.children.forEach(c => c.walkDown(callback))
150
198
  }
151
199
 
200
+ flatten(){
201
+ const nodes: Node[] = [];
202
+
203
+ this.walkDown((node: Node)=>{
204
+ if (!node.hasChildren){
205
+ nodes.push(node);
206
+ }
207
+ });
208
+
209
+ return nodes;
210
+ }
211
+
212
+ reduce() {
213
+ const value = this.toString();
214
+ this.removeAllChildren();
215
+ this._value = value;
216
+ }
217
+
152
218
  clone(): Node {
153
219
  return new Node(
154
220
  this._type,
package/src/index.ts CHANGED
@@ -9,17 +9,28 @@ import { Repeat } from "./patterns/Repeat";
9
9
  import { ParseError } from "./patterns/ParseError";
10
10
  import { Pattern } from "./patterns/Pattern";
11
11
  import { Reference } from "./patterns/Reference";
12
+ import { AutoComplete } from './intellisense/AutoComplete';
13
+ import { CursorHistory, Match } from "./patterns/CursorHistory";
14
+ import { ParseResult } from "./patterns/ParseResult";
15
+ import { Suggestion } from "./intellisense/Suggestion";
16
+ import { SuggestionOption } from "./intellisense/SuggestionOption";
12
17
 
13
18
  export {
14
19
  Node,
15
- Cursor,
16
- Regex,
20
+ AutoComplete,
21
+ Suggestion,
22
+ SuggestionOption,
17
23
  And,
24
+ Cursor,
25
+ CursorHistory,
26
+ Match,
18
27
  Literal,
19
28
  Not,
20
29
  Or,
21
- Repeat,
22
30
  ParseError,
31
+ ParseResult,
23
32
  Pattern,
24
33
  Reference,
34
+ Regex,
35
+ Repeat,
25
36
  };
@@ -2,7 +2,9 @@ import { And } from "../patterns/And";
2
2
  import { findPattern } from "../patterns/findPattern";
3
3
  import { Literal } from "../patterns/Literal";
4
4
  import { Or } from "../patterns/Or";
5
- import { AutoComplete } from "./AutoComplete";
5
+ import { Regex } from "../patterns/Regex";
6
+ import { Repeat } from "../patterns/Repeat";
7
+ import { AutoComplete, AutoCompleteOptions } from "./AutoComplete";
6
8
 
7
9
  describe("AutoComplete", () => {
8
10
  test("No Text", () => {
@@ -12,7 +14,7 @@ describe("AutoComplete", () => {
12
14
 
13
15
  expect(result.options[0].text).toBe("Name");
14
16
  expect(result.options[0].startIndex).toBe(0);
15
- expect(result.nextPattern).toBe(name);
17
+ expect(result.nextPatterns[0]).toBe(name);
16
18
  expect(result.isComplete).toBeFalsy();
17
19
  });
18
20
 
@@ -21,21 +23,55 @@ describe("AutoComplete", () => {
21
23
  const space = new Literal("space", " ");
22
24
  const doe = new Literal("doe", "Doe");
23
25
  const smith = new Literal("smith", "Smith");
26
+ const name = new And("name", [john, space, new Or("last-name", [smith, doe])]);
24
27
 
25
- space.enableContextualTokenAggregation();
28
+ const autoComplete = new AutoComplete(name);
29
+ const result = autoComplete.suggest("John Doe");
26
30
 
31
+ expect(result.ast?.value).toBe("John Doe");
32
+ expect(result.options.length).toBe(0);
33
+ expect(result.nextPatterns.length).toBe(0);
34
+ expect(result.isComplete).toBeTruthy();
35
+ expect(result.cursor).not.toBeNull();
36
+ });
37
+
38
+ test("More Than One Option", () => {
39
+ const john = new Literal("john", "John");
40
+ const space = new Literal("space", " ");
41
+ const doe = new Literal("doe", "Doe");
42
+ const smith = new Literal("smith", "Smith");
27
43
  const name = new And("name", [john, space, new Or("last-name", [smith, doe])]);
28
44
 
29
45
  const autoComplete = new AutoComplete(name);
30
- let result = autoComplete.suggest("John");
46
+ const result = autoComplete.suggest("John ");
31
47
 
48
+ expect(result.ast).toBeNull();
32
49
  expect(result.options.length).toBe(2);
33
- expect(result.nextPattern).toBe(findPattern(name, p=>p.name === "space"));
34
- expect(result.options[0].text).toBe(" Doe");
35
- expect(result.options[0].startIndex).toBe(4);
36
- expect(result.options[1].text).toBe(" Smith");
37
- expect(result.options[1].startIndex).toBe(4);
50
+ expect(result.nextPatterns.length).toBe(1);
51
+ expect(result.nextPatterns[0].type).toBe("or");
52
+ expect(result.nextPatterns[0].name).toBe("last-name");
38
53
  expect(result.isComplete).toBeFalsy();
54
+ expect(result.cursor).not.toBeNull();
55
+ });
56
+
57
+ test("Full Pattern Match With Root Repeat", () => {
58
+ const john = new Literal("john", "John");
59
+ const space = new Literal("space", " ");
60
+ const doe = new Literal("doe", "Doe");
61
+ const smith = new Literal("smith", "Smith");
62
+ const name = new And("name", [john, space, new Or("last-name", [smith, doe])]);
63
+ const divider = new Regex("divider", "\\s+,\\s+");
64
+
65
+ divider.setTokens([", "])
66
+
67
+ const autoComplete = new AutoComplete(new Repeat("last-names", name, divider));
68
+ const result = autoComplete.suggest("John Doe");
69
+
70
+ expect(result.ast?.value).toBe("John Doe");
71
+ expect(result.options.length).toBe(1);
72
+ expect(result.nextPatterns.length).toBe(result.options.length);
73
+ expect(result.isComplete).toBeTruthy();
74
+ expect(result.cursor).not.toBeNull();
39
75
  });
40
76
 
41
77
  test("Partial", () => {
@@ -45,7 +81,7 @@ describe("AutoComplete", () => {
45
81
 
46
82
  expect(result.options[0].text).toBe("me");
47
83
  expect(result.options[0].startIndex).toBe(2);
48
- expect(result.nextPattern).toBe(name);
84
+ expect(result.nextPatterns[0]).toBe(name);
49
85
  expect(result.isComplete).toBeFalsy();
50
86
  });
51
87
 
@@ -56,7 +92,7 @@ describe("AutoComplete", () => {
56
92
 
57
93
  expect(result.options[0].text).toBe("ame");
58
94
  expect(result.options[0].startIndex).toBe(1);
59
- expect(result.nextPattern).toBe(name);
95
+ //expect(result.nextPattern).toBe(name);
60
96
  expect(result.isComplete).toBeFalsy();
61
97
  });
62
98
 
@@ -66,7 +102,49 @@ describe("AutoComplete", () => {
66
102
  let result = autoComplete.suggest("Name");
67
103
 
68
104
  expect(result.options.length).toBe(0);
69
- expect(result.nextPattern).toBe(null);
105
+ expect(result.nextPatterns.length).toBe(0);
70
106
  expect(result.isComplete).toBeTruthy();
71
107
  });
108
+
109
+ test("Options", ()=>{
110
+ const autoCompleteOptions: AutoCompleteOptions = {
111
+ greedyPatternNames: ["space"],
112
+ customTokens: {
113
+ "last-name": ["Sparrow"]
114
+ }
115
+ };
116
+
117
+ const jack = new Literal("jack", "Jack");
118
+ const john = new Literal("john", "John");
119
+ const space = new Literal("space", " ");
120
+ const doe = new Literal("doe", "Doe");
121
+ const smith = new Literal("smith", "Smith");
122
+ const firstName = new Or("first-name", [jack, john]);
123
+ const lastName = new Or("last-name", [doe, smith]);
124
+ const fullName = new And("full-name", [firstName, space, lastName]);
125
+
126
+ const text = "John";
127
+ const autoComplete = new AutoComplete(fullName, autoCompleteOptions);
128
+ const { options, ast, nextPatterns } = autoComplete.suggest(text);
129
+ const expectedOptions = [
130
+ {text: " Doe", startIndex: 4},
131
+ {text: " Smith", startIndex: 4},
132
+ {text: " Sparrow", startIndex: 4},
133
+ ];
134
+
135
+ const results = expectedOptions.map(o=>text.slice(0, o.startIndex) + o.text);
136
+ const expectedResults = [
137
+ "John Doe",
138
+ "John Smith",
139
+ "John Sparrow",
140
+ ]
141
+
142
+ expect(options).toEqual(expectedOptions);
143
+ expect(ast).toBeNull();
144
+ expect(nextPatterns.length).toBe(1);
145
+ expect(nextPatterns[0].name).toBe("space");
146
+ expect(results).toEqual(expectedResults)
147
+
148
+ });
149
+
72
150
  });
@@ -1,16 +1,33 @@
1
1
  import { Cursor } from "../patterns/Cursor";
2
- import { ParseError } from "../patterns/ParseError";
3
2
  import { Pattern } from "../patterns/Pattern";
4
3
  import { Suggestion } from "./Suggestion";
5
4
  import { SuggestionOption } from "./SuggestionOption";
6
5
 
6
+ export interface AutoCompleteOptions {
7
+ /**
8
+ * Allows for certain patterns to combine their tokens with the next tokens.
9
+ * Be very careful, this can explode to infinity pretty quick. Usually useful
10
+ * for dividers and spaces.
11
+ */
12
+ greedyPatternNames: string[];
13
+ /**
14
+ * Allows for custom suggestions for patterns. The key is the name of the pattern
15
+ * and the string array are the tokens suggested for that pattern.
16
+ */
17
+ customTokens: Record<string, string[]>;
18
+ }
19
+
20
+ const defaultOptions = { greedyPatternNames: [], customTokens: {} };
21
+
7
22
  export class AutoComplete {
8
23
  private _pattern: Pattern;
24
+ private _options: AutoCompleteOptions;
9
25
  private _cursor!: Cursor;
10
26
  private _text: string;
11
27
 
12
- constructor(pattern: Pattern) {
28
+ constructor(pattern: Pattern, options: AutoCompleteOptions = defaultOptions) {
13
29
  this._pattern = pattern;
30
+ this._options = options;
14
31
  this._text = "";
15
32
  }
16
33
 
@@ -19,28 +36,32 @@ export class AutoComplete {
19
36
  return {
20
37
  isComplete: false,
21
38
  options: this.createSuggestionsFromRoot(),
22
- nextPattern: this._pattern,
39
+ nextPatterns: [this._pattern],
23
40
  cursor: null,
24
- error: new ParseError(0, this._pattern),
41
+ ast: null
25
42
  }
26
43
  }
27
44
 
28
45
  this._text = text;
29
46
  this._cursor = new Cursor(text);
30
- this._pattern.parse(this._cursor);
47
+ const ast = this._pattern.parse(this._cursor);
31
48
 
32
49
  const leafPattern = this._cursor.leafMatch.pattern;
33
- const rootMatch = this._cursor.rootMatch.pattern;
34
- const isComplete = this._cursor.isOnLast && rootMatch === this._pattern;
50
+ const isComplete = ast?.value === text;
35
51
  const options = this.createSuggestionsFromTokens();
36
- const nextPattern = isComplete ? null : leafPattern?.getNextPattern() || this._pattern;
52
+
53
+ let nextPatterns = [this._pattern];
54
+
55
+ if (leafPattern != null) {
56
+ nextPatterns = leafPattern.getNextPatterns();
57
+ }
37
58
 
38
59
  return {
39
60
  isComplete: isComplete,
40
61
  options: options,
41
- nextPattern,
62
+ nextPatterns,
42
63
  cursor: this._cursor,
43
- error: this._cursor.furthestError
64
+ ast,
44
65
  }
45
66
  }
46
67
 
@@ -59,20 +80,53 @@ export class AutoComplete {
59
80
  const leafMatch = this._cursor.leafMatch;
60
81
 
61
82
  if (!leafMatch.pattern) {
62
- return this.createSuggestions(-1, this._pattern.getTokens());
83
+ return this.createSuggestions(-1, this._getTokensForPattern(this._pattern));
63
84
  }
64
85
 
65
86
  const leafPattern = leafMatch.pattern;
87
+ const leafNode = leafMatch.node;
66
88
  const parent = leafMatch.pattern.parent;
67
89
 
68
90
  if (parent !== null && leafMatch.node != null) {
69
- const tokens = parent.getNextTokens(leafPattern);
91
+ const patterns = leafPattern.getNextPatterns();
92
+
93
+ const tokens = patterns.reduce((acc: string[], pattern) => {
94
+ acc.push(...this._getTokensForPattern(pattern));
95
+ return acc;
96
+ }, []);
97
+
70
98
  return this.createSuggestions(leafMatch.node.lastIndex, tokens);
71
99
  } else {
72
100
  return [];
73
101
  }
74
102
  }
75
103
 
104
+ private _getTokensForPattern(pattern: Pattern) {
105
+ if (this._options.greedyPatternNames.includes(pattern.name)) {
106
+ const greedyTokens = pattern.getTokens();
107
+ const nextPatterns = pattern.getNextPatterns();
108
+ const tokens: string[] = [];
109
+
110
+ const nextPatternTokens = nextPatterns.reduce((acc: string[], pattern)=>{
111
+ acc.push(...this._getTokensForPattern(pattern));
112
+ return acc;
113
+ }, []);
114
+
115
+ for (let token of greedyTokens){
116
+ for (let nextPatternToken of nextPatternTokens){
117
+ tokens.push(token + nextPatternToken);
118
+ }
119
+ }
120
+
121
+ return tokens;
122
+ } else {
123
+ const tokens = pattern.getTokens();
124
+ const customTokens = this._options.customTokens[pattern.name] || [];
125
+ tokens.push(...customTokens);
126
+ return tokens;
127
+ }
128
+ }
129
+
76
130
  private createSuggestions(lastIndex: number, tokens: string[]): SuggestionOption[] {
77
131
  let substring = lastIndex === -1 ? "" : this._cursor.getChars(0, lastIndex);
78
132
  const suggestionStrings: string[] = [];
@@ -1,13 +1,12 @@
1
+ import { Node } from "../ast/Node";
1
2
  import { Cursor } from "../patterns/Cursor";
2
- import { Match } from "../patterns/CursorHistory";
3
- import { ParseError } from "../patterns/ParseError";
4
3
  import { Pattern } from "../patterns/Pattern";
5
4
  import { SuggestionOption } from "./SuggestionOption";
6
5
 
7
6
  export interface Suggestion {
8
7
  isComplete: boolean;
9
8
  options: SuggestionOption[];
10
- nextPattern: Pattern | null;
9
+ nextPatterns: Pattern[];
11
10
  cursor: Cursor | null;
12
- error: ParseError | null;
11
+ ast: Node | null;
13
12
  }