clarity-pattern-parser 5.0.0 → 6.0.2

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 (61) hide show
  1. package/README.md +328 -38
  2. package/TODO.md +63 -7
  3. package/dist/ast/Node.d.ts +8 -2
  4. package/dist/index.browser.js +520 -205
  5. package/dist/index.browser.js.map +1 -1
  6. package/dist/index.d.ts +6 -1
  7. package/dist/index.esm.js +519 -206
  8. package/dist/index.esm.js.map +1 -1
  9. package/dist/index.js +520 -205
  10. package/dist/index.js.map +1 -1
  11. package/dist/intellisense/AutoComplete.d.ts +34 -0
  12. package/dist/intellisense/Suggestion.d.ts +10 -0
  13. package/dist/intellisense/SuggestionOption.d.ts +4 -0
  14. package/dist/patterns/And.d.ts +8 -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 +8 -8
  18. package/dist/patterns/Not.d.ts +9 -5
  19. package/dist/patterns/Or.d.ts +8 -5
  20. package/dist/patterns/Pattern.d.ts +8 -4
  21. package/dist/patterns/Reference.d.ts +11 -7
  22. package/dist/patterns/Regex.d.ts +8 -8
  23. package/dist/patterns/Repeat.d.ts +8 -7
  24. package/package.json +1 -1
  25. package/src/ast/Node.test.ts +116 -0
  26. package/src/ast/Node.ts +71 -5
  27. package/src/index.ts +14 -3
  28. package/src/intellisense/AutoComplete.test.ts +168 -23
  29. package/src/intellisense/AutoComplete.ts +102 -21
  30. package/src/intellisense/Suggestion.ts +3 -4
  31. package/src/intellisense/javascript/Javascript.test.ts +86 -62
  32. package/src/intellisense/javascript/{expressionStatement.ts → assignment.ts} +7 -8
  33. package/src/intellisense/javascript/escapedCharacter.ts +0 -1
  34. package/src/intellisense/javascript/exponent.ts +0 -2
  35. package/src/intellisense/javascript/expression.ts +44 -26
  36. package/src/intellisense/javascript/fraction.ts +0 -2
  37. package/src/intellisense/javascript/infixOperator.ts +6 -2
  38. package/src/intellisense/javascript/keywords.ts +3 -0
  39. package/src/intellisense/javascript/objectAccess.ts +9 -0
  40. package/src/intellisense/javascript/objectLiteral.ts +3 -3
  41. package/src/intellisense/javascript/propertyAccess.ts +8 -3
  42. package/src/intellisense/javascript/stringLiteral.ts +16 -8
  43. package/src/patterns/And.test.ts +74 -50
  44. package/src/patterns/And.ts +72 -36
  45. package/src/patterns/Cursor.ts +17 -14
  46. package/src/patterns/CursorHistory.ts +8 -8
  47. package/src/patterns/Literal.test.ts +79 -38
  48. package/src/patterns/Literal.ts +34 -41
  49. package/src/patterns/Not.test.ts +99 -8
  50. package/src/patterns/Not.ts +58 -14
  51. package/src/patterns/Or.test.ts +128 -13
  52. package/src/patterns/Or.ts +46 -13
  53. package/src/patterns/Pattern.ts +8 -4
  54. package/src/patterns/Reference.test.ts +127 -28
  55. package/src/patterns/Reference.ts +62 -32
  56. package/src/patterns/Regex.test.ts +76 -35
  57. package/src/patterns/Regex.ts +35 -43
  58. package/src/patterns/Repeat.test.ts +72 -41
  59. package/src/patterns/Repeat.ts +55 -38
  60. package/src/patterns/getNextPattern.test.ts +0 -39
  61. package/src/patterns/getNextPattern.ts +0 -18
@@ -3,6 +3,7 @@ import { Regex } from "./Regex";
3
3
  import { Node } from "../ast/Node"
4
4
  import { And } from "./And";
5
5
  import { Literal } from "./Literal";
6
+ import { Pattern } from "./Pattern";
6
7
 
7
8
  describe("Regex", () => {
8
9
  test("Empty String", () => {
@@ -38,52 +39,24 @@ describe("Regex", () => {
38
39
 
39
40
 
40
41
  test("Get Tokens", () => {
41
- const parent = new And("parent", [
42
- new Regex("a", "A"),
43
- new Regex("b", "B")
44
- ]);
45
-
46
- const a = parent.children[0] as Regex;
47
- const b = parent.children[1] as Regex;
42
+ const a = new Regex("a", "A");
48
43
 
49
44
  a.setTokens(["A"]);
50
- b.setTokens(["B"]);
51
-
52
- let tokens = a.getTokens();
53
- let expectedTokens = ["A"];
54
-
55
- expect(tokens).toEqual(expectedTokens);
56
-
57
- a.enableContextualTokenAggregation();
58
-
59
- tokens = a.getTokens();
60
- expectedTokens = ["AB"];
61
45
 
62
- expect(tokens).toEqual(expectedTokens);
63
-
64
- a.disableContextualTokenAggregation();
65
-
66
- tokens = a.getTokens();
67
- expectedTokens = ["A"];
46
+ const tokens = a.getTokens();
47
+ const expectedTokens = ["A"];
68
48
 
69
49
  expect(tokens).toEqual(expectedTokens);
70
50
  });
71
51
 
72
- test("Get Next Tokens", () => {
52
+ test("Get Tokens After", () => {
73
53
  const regex = new Regex("a", "A");
74
- const tokens = regex.getNextTokens(new Literal("bogus", "bogus"));
54
+ const tokens = regex.getTokensAfter(new Literal("bogus", "bogus"));
75
55
  const expected: string[] = [];
76
56
 
77
57
  expect(tokens).toEqual(expected)
78
58
  });
79
59
 
80
- test("Get Next Pattern", () => {
81
- const regex = new Regex("a", "A");
82
- const nextPattern = regex.getNextPattern();
83
-
84
- expect(nextPattern).toBeNull()
85
- });
86
-
87
60
  test("Properties", () => {
88
61
  const regex = new Regex("a", "A");
89
62
 
@@ -93,9 +66,77 @@ describe("Regex", () => {
93
66
  expect(regex.children).toEqual([]);
94
67
  });
95
68
 
96
- test("Parse Text", () => {
69
+ test("Exec", () => {
97
70
  const regex = new Regex("a", "A");
98
- const { ast: result } = regex.parseText("B");
71
+ const { ast: result } = regex.exec("B");
99
72
  expect(result).toBeNull();
100
73
  });
74
+
75
+ test("Test With Match", () => {
76
+ const regex = new Regex("a", "A");
77
+ const result = regex.test("A");
78
+ expect(result).toBeTruthy();
79
+ });
80
+
81
+ test("Test With No Match", () => {
82
+ const regex = new Regex("a", "A");
83
+ const result = regex.test("B");
84
+ expect(result).toBeFalsy();
85
+ });
86
+
87
+ test("Get Next Tokens", () => {
88
+ const parent = new And("parent", [new Regex("a", "A"), new Literal("b", "B")]);
89
+ const aClone = parent.findPattern(p => p.name === "a") as Pattern;
90
+ const tokens = aClone.getNextTokens();
91
+
92
+ expect(tokens).toEqual(["B"]);
93
+ });
94
+
95
+ test("Get Next Tokens With Null Parent", () => {
96
+ const a = new Regex("a", "A")
97
+ const tokens = a.getNextTokens();
98
+
99
+ expect(tokens).toEqual([]);
100
+ });
101
+
102
+ test("Get Patterns", () => {
103
+ const a = new Regex("a", "A");
104
+
105
+ const tokens = a.getPatterns();
106
+ const expectedTokens = [a];
107
+
108
+ expect(tokens).toEqual(expectedTokens);
109
+ });
110
+
111
+ test("Get Patterns After", () => {
112
+ const a = new Regex("a", "A")
113
+ const patterns = a.getPatternsAfter(new Literal("bogus", "bogus"));
114
+
115
+ expect(patterns).toEqual([]);
116
+ });
117
+
118
+ test("Find Pattern", () => {
119
+ const a = new Regex("a", "A")
120
+ const pattern = a.findPattern(p => p.name === "other");
121
+
122
+ expect(pattern).toBeNull();
123
+ });
124
+
125
+ test("Get Next Patterns", () => {
126
+ const parent = new And("parent", [new Regex("a", "A"), new Literal("b", "B")]);
127
+ const aClone = parent.findPattern(p => p.name === "a") as Pattern;
128
+ const bClone = parent.findPattern(p => p.name === "b") as Pattern;
129
+ const patterns = aClone.getNextPatterns();
130
+
131
+ expect(patterns.length).toBe(1);
132
+ expect(patterns[0]).toBe(bClone);
133
+ });
134
+
135
+ test("Get Next Patterns With Null Parent", () => {
136
+ const a = new Regex("a", "A")
137
+ const patterns = a.getNextPatterns();
138
+
139
+ expect(patterns).toEqual([])
140
+ });
141
+
101
142
  });
@@ -1,7 +1,6 @@
1
1
  import { Node } from "../ast/Node";
2
2
  import { Pattern } from "./Pattern";
3
3
  import { Cursor } from "./Cursor";
4
- import { getNextPattern } from "./getNextPattern";
5
4
 
6
5
  export class Regex implements Pattern {
7
6
  private _type: string;
@@ -14,8 +13,6 @@ export class Regex implements Pattern {
14
13
  private _cursor: Cursor | null = null;
15
14
  private _substring: string = "";
16
15
  private _tokens: string[] = [];
17
- private _hasContextualTokenAggregation = false;
18
- private _isRetrievingContextualTokens: boolean = false;
19
16
 
20
17
  get type(): string {
21
18
  return this._type;
@@ -71,12 +68,19 @@ export class Regex implements Pattern {
71
68
  }
72
69
  }
73
70
 
74
- parseText(text: string) {
71
+ test(text: string) {
75
72
  const cursor = new Cursor(text);
76
- const ast = this.parse(cursor)
73
+ const ast = this.parse(cursor);
74
+
75
+ return ast?.value === text;
76
+ }
77
+
78
+ exec(text: string) {
79
+ const cursor = new Cursor(text);
80
+ const ast = this.parse(cursor);
77
81
 
78
82
  return {
79
- ast,
83
+ ast: ast?.value === text ? ast : null,
80
84
  cursor
81
85
  };
82
86
  }
@@ -114,7 +118,7 @@ export class Regex implements Pattern {
114
118
  this._name,
115
119
  currentIndex,
116
120
  newIndex,
117
- [],
121
+ undefined,
118
122
  result[0]
119
123
  );
120
124
 
@@ -133,60 +137,48 @@ export class Regex implements Pattern {
133
137
  clone(name = this._name, isOptional = this._isOptional) {
134
138
  const pattern = new Regex(name, this._originalRegexString, isOptional);
135
139
  pattern._tokens = this._tokens.slice();
136
- pattern._hasContextualTokenAggregation =
137
- this._hasContextualTokenAggregation;
138
140
 
139
141
  return pattern;
140
142
  }
141
143
 
142
144
  getTokens() {
143
- const parent = this._parent;
144
-
145
- if (this._hasContextualTokenAggregation &&
146
- parent != null &&
147
- !this._isRetrievingContextualTokens
148
- ) {
149
- this._isRetrievingContextualTokens = true;
150
-
151
- const tokens = this._tokens;
152
- const aggregateTokens: string[] = [];
153
- const nextTokens = parent.getNextTokens(this);
154
-
155
- for (let nextToken of nextTokens) {
156
- for (let token of tokens) {
157
- aggregateTokens.push(token + nextToken);
158
- }
159
- }
160
-
161
- this._isRetrievingContextualTokens = false
162
- return aggregateTokens;
163
- }
164
-
165
145
  return this._tokens;
166
146
  }
167
147
 
168
- getNextTokens(_reference: Pattern): string[] {
148
+ getTokensAfter(_childReference: Pattern): string[] {
169
149
  return [];
170
150
  }
171
151
 
172
- getNextPattern(): Pattern | null {
173
- return getNextPattern(this)
152
+ getNextTokens(): string[] {
153
+ if (this.parent == null) {
154
+ return []
155
+ }
156
+
157
+ return this.parent.getTokensAfter(this);
174
158
  }
175
-
176
- findPattern(_isMatch: (p: Pattern)=>boolean): Pattern | null{
177
- return null;
159
+
160
+ getPatterns(): Pattern[] {
161
+ return [this];
178
162
  }
179
163
 
180
- setTokens(tokens: string[]) {
181
- this._tokens = tokens;
164
+ getPatternsAfter(_childReference: Pattern): Pattern[] {
165
+ return [];
166
+ }
167
+
168
+ getNextPatterns(): Pattern[] {
169
+ if (this.parent == null) {
170
+ return [];
171
+ }
172
+
173
+ return this.parent.getPatternsAfter(this)
182
174
  }
183
175
 
184
- enableContextualTokenAggregation() {
185
- this._hasContextualTokenAggregation = true;
176
+ findPattern(_predicate: (p: Pattern) => boolean): Pattern | null {
177
+ return null;
186
178
  }
187
179
 
188
- disableContextualTokenAggregation() {
189
- this._hasContextualTokenAggregation = false;
180
+ setTokens(tokens: string[]) {
181
+ this._tokens = tokens;
190
182
  }
191
183
 
192
184
  }
@@ -3,6 +3,7 @@ import { And } from "./And";
3
3
  import { Cursor } from "./Cursor";
4
4
  import { findPattern } from "./findPattern";
5
5
  import { Literal } from "./Literal";
6
+ import { Pattern } from "./Pattern";
6
7
  import { Regex } from "./Regex";
7
8
  import { Repeat } from "./Repeat";
8
9
 
@@ -96,31 +97,6 @@ describe("Repeat", () => {
96
97
  expect(cursor.hasError).toBeFalsy()
97
98
  });
98
99
 
99
- test("Ast Reduction", () => {
100
- const digit = new Regex("digit", "\\d");
101
- const integer = new Repeat("number", digit);
102
- const cursor = new Cursor("337");
103
-
104
- integer.enableAstReduction();
105
-
106
- let result = integer.parse(cursor);
107
- let expected = new Node("repeat", "number", 0, 2, [], "337");
108
-
109
- expect(result).toEqual(expected)
110
-
111
- integer.disableAstReduction()
112
- cursor.moveTo(0)
113
-
114
- result = integer.parse(cursor);
115
- expected = new Node("repeat", "number", 0, 2, [
116
- new Node("regex", "digit", 0, 0, [], "3"),
117
- new Node("regex", "digit", 1, 1, [], "3"),
118
- new Node("regex", "digit", 2, 2, [], "7"),
119
- ]);
120
-
121
- expect(result).toEqual(expected)
122
- });
123
-
124
100
  test("Get Tokens", () => {
125
101
  const a = new Literal("a", "A");
126
102
  const manyA = new Repeat("number", a);
@@ -130,16 +106,16 @@ describe("Repeat", () => {
130
106
  expect(tokens).toEqual(expected)
131
107
  });
132
108
 
133
- test("Get Next Tokens With Bogus Pattern", () => {
109
+ test("Get Tokens After With Bogus Pattern", () => {
134
110
  const a = new Literal("a", "A");
135
111
  const manyA = new Repeat("many-a", a);
136
- const tokens = manyA.getNextTokens(new Literal("bogus", "bogus"));
112
+ const tokens = manyA.getTokensAfter(new Literal("bogus", "bogus"));
137
113
  const expected: string[] = [];
138
114
 
139
115
  expect(tokens).toEqual(expected)
140
116
  });
141
117
 
142
- test("Get Next Tokens With Divider", () => {
118
+ test("Get Tokens After With Divider", () => {
143
119
  const a = new Literal("a", "A");
144
120
  const b = new Literal("b", "B");
145
121
  const divider = new Literal("divider", ",");
@@ -147,37 +123,30 @@ describe("Repeat", () => {
147
123
  const parent = new And("parent", [manyA, b]);
148
124
 
149
125
  const clonedManyA = findPattern(parent, p => p.name == "many-a");
150
- let tokens = clonedManyA?.getNextTokens(clonedManyA.children[0]);
126
+ let tokens = clonedManyA?.getTokensAfter(clonedManyA.children[0]);
151
127
  let expected = [",", "B"];
152
128
 
153
129
  expect(tokens).toEqual(expected)
154
130
 
155
- tokens = clonedManyA?.getNextTokens(clonedManyA.children[1]);
131
+ tokens = clonedManyA?.getTokensAfter(clonedManyA.children[1]);
156
132
  expected = ["A"];
157
133
 
158
134
  expect(tokens).toEqual(expected)
159
135
  });
160
136
 
161
- test("Get Next Tokens Without Divider", () => {
137
+ test("Get Tokens After Without Divider", () => {
162
138
  const a = new Literal("a", "A");
163
139
  const b = new Literal("b", "B");
164
140
  const manyA = new Repeat("many-a", a);
165
141
  const parent = new And("parent", [manyA, b]);
166
142
 
167
143
  const clonedManyA = findPattern(parent, p => p.name == "many-a");
168
- const tokens = clonedManyA?.getNextTokens(clonedManyA.children[0]);
144
+ const tokens = clonedManyA?.getTokensAfter(clonedManyA.children[0]);
169
145
  const expected = ["A", "B"];
170
146
 
171
147
  expect(tokens).toEqual(expected)
172
148
  });
173
149
 
174
- test("Get Next Pattern", () => {
175
- const repeat = new Repeat("many-a", new Literal("a", "A"));
176
- const nextPattern = repeat.getNextPattern();
177
-
178
- expect(nextPattern).toBeNull()
179
- });
180
-
181
150
  test("Properties", () => {
182
151
  const integer = new Repeat("integer", new Regex("digit", "\\d"));
183
152
 
@@ -188,9 +157,71 @@ describe("Repeat", () => {
188
157
  expect(integer.children[0].name).toBe("digit");
189
158
  });
190
159
 
191
- test("Parse Text", () => {
160
+ test("Exec", () => {
192
161
  const integer = new Repeat("integer", new Regex("digit", "\\d"));
193
- const { ast: result } = integer.parseText("B");
162
+ const { ast: result } = integer.exec("B");
194
163
  expect(result).toBeNull()
195
164
  });
165
+
166
+ test("Test With Match", () => {
167
+ const integer = new Repeat("integer", new Regex("digit", "\\d"));
168
+ const result = integer.test("1");
169
+ expect(result).toBeTruthy()
170
+ });
171
+
172
+ test("Test With No Match", () => {
173
+ const integer = new Repeat("integer", new Regex("digit", "\\d"));
174
+ const result = integer.test("b");
175
+ expect(result).toBeFalsy()
176
+ });
177
+
178
+ test("Get Next Tokens", () => {
179
+ const integer = new Repeat("integer", new Regex("digit", "\\d"));
180
+ const parent = new And("parent", [integer, new Literal("pow", "!")]);
181
+ const integerClone = parent.findPattern(p => p.name === "integer") as Pattern;
182
+ const tokens = integerClone.getNextTokens();
183
+
184
+ expect(tokens).toEqual(["!"])
185
+ });
186
+
187
+ test("Get Next Tokens With Null Parents", () => {
188
+ const integer = new Repeat("integer", new Regex("digit", "\\d"));
189
+ const tokens = integer.getNextTokens();
190
+
191
+ expect(tokens.length).toBe(0);
192
+ });
193
+
194
+ test("Find Pattern", () => {
195
+ const integer = new Repeat("integer", new Regex("digit", "\\d"));
196
+ const digitClone = integer.findPattern(p => p.name === "digit") as Pattern;
197
+
198
+ expect(digitClone).not.toBeNull();
199
+ });
200
+
201
+ test("Get Patterns", () => {
202
+ const a = new Literal("a", "A");
203
+ const manyA = new Repeat("number", a);
204
+ const patterns = manyA.getPatterns();
205
+ const expected = [manyA.findPattern(p => p.name === "a")];
206
+
207
+ expect(patterns).toEqual(expected)
208
+ });
209
+
210
+ test("Get Next Patterns", () => {
211
+ const integer = new Repeat("integer", new Regex("digit", "\\d"));
212
+ const parent = new And("parent", [integer, new Literal("pow", "!")]);
213
+ const integerClone = parent.findPattern(p => p.name === "integer") as Pattern;
214
+ const powClone = parent.findPattern(p => p.name === "pow") as Pattern;
215
+ const patterns = integerClone.getNextPatterns();
216
+
217
+ expect(patterns.length).toBe(1);
218
+ expect(patterns[0]).toBe(powClone);
219
+ });
220
+
221
+ test("Get Next Patterns With Null Parents", () => {
222
+ const integer = new Repeat("integer", new Regex("digit", "\\d"));
223
+ const patterns = integer.getNextPatterns();
224
+
225
+ expect(patterns.length).toBe(0);
226
+ });
196
227
  });
@@ -2,7 +2,6 @@ import { Node } from "../ast/Node";
2
2
  import { Cursor } from "./Cursor";
3
3
  import { Pattern } from "./Pattern";
4
4
  import { clonePatterns } from "./clonePatterns";
5
- import { getNextPattern } from "./getNextPattern";
6
5
  import { findPattern } from "./findPattern";
7
6
 
8
7
  export class Repeat implements Pattern {
@@ -15,7 +14,6 @@ export class Repeat implements Pattern {
15
14
  private _isOptional: boolean;
16
15
  private _nodes: Node[];
17
16
  private _firstIndex: number;
18
- private _shouldReduceAst: boolean;
19
17
 
20
18
  get type(): string {
21
19
  return this._type;
@@ -54,7 +52,6 @@ export class Repeat implements Pattern {
54
52
  this._pattern = children[0];
55
53
  this._divider = children[1];
56
54
  this._firstIndex = -1
57
- this._shouldReduceAst = false
58
55
  this._nodes = [];
59
56
  }
60
57
 
@@ -64,12 +61,19 @@ export class Repeat implements Pattern {
64
61
  }
65
62
  }
66
63
 
67
- parseText(text: string) {
64
+ test(text: string) {
68
65
  const cursor = new Cursor(text);
69
- const ast = this.parse(cursor)
66
+ const ast = this.parse(cursor);
67
+
68
+ return ast?.value === text;
69
+ }
70
+
71
+ exec(text: string) {
72
+ const cursor = new Cursor(text);
73
+ const ast = this.parse(cursor);
70
74
 
71
75
  return {
72
- ast,
76
+ ast: ast?.value === text ? ast : null,
73
77
  cursor
74
78
  };
75
79
  }
@@ -84,7 +88,7 @@ export class Repeat implements Pattern {
84
88
  cursor.resolveError();
85
89
  const node = this.createNode(cursor);
86
90
 
87
- if (node) {
91
+ if (node != null) {
88
92
  cursor.recordMatch(this, node);
89
93
  }
90
94
 
@@ -110,7 +114,7 @@ export class Repeat implements Pattern {
110
114
  if (cursor.hasError) {
111
115
  const lastValidNode = this.getLastValidNode();
112
116
 
113
- if (lastValidNode) {
117
+ if (lastValidNode != null) {
114
118
  passed = true;
115
119
  } else {
116
120
  cursor.moveTo(runningCursorIndex);
@@ -129,13 +133,13 @@ export class Repeat implements Pattern {
129
133
 
130
134
  cursor.next();
131
135
 
132
- if (this._divider) {
136
+ if (this._divider != null) {
133
137
  const dividerNode = this._divider.parse(cursor);
134
138
 
135
139
  if (cursor.hasError) {
136
140
  passed = true;
137
141
  break;
138
- } else if (dividerNode) {
142
+ } else if (dividerNode != null) {
139
143
  this._nodes.push(dividerNode);
140
144
 
141
145
  if (!cursor.hasNext()) {
@@ -171,17 +175,13 @@ export class Repeat implements Pattern {
171
175
  const value = cursor.getChars(this._firstIndex, lastIndex);
172
176
  cursor.moveTo(lastIndex);
173
177
 
174
- if (this._shouldReduceAst) {
175
- children = [];
176
- }
177
-
178
178
  return new Node(
179
179
  "repeat",
180
180
  this._name,
181
181
  this._firstIndex,
182
182
  lastIndex,
183
183
  children,
184
- this._shouldReduceAst ? value : undefined
184
+ undefined
185
185
  );
186
186
  }
187
187
 
@@ -195,65 +195,82 @@ export class Repeat implements Pattern {
195
195
  return nodes[nodes.length - 1];
196
196
  }
197
197
 
198
- enableAstReduction(): void {
199
- this._shouldReduceAst = true;
198
+ getTokens(): string[] {
199
+ return this._pattern.getTokens();
200
+ }
201
+
202
+ getTokensAfter(childReference: Pattern): string[] {
203
+ const patterns = this.getPatternsAfter(childReference);
204
+ const tokens: string[] = [];
205
+
206
+ patterns.forEach(p => tokens.push(...p.getTokens()));
207
+
208
+ return tokens;
200
209
  }
201
210
 
202
- disableAstReduction(): void {
203
- this._shouldReduceAst = false;
211
+ getNextTokens(): string[] {
212
+ if (this.parent == null) {
213
+ return []
214
+ }
215
+
216
+ return this.parent.getTokensAfter(this);
204
217
  }
205
218
 
206
- getTokens(): string[] {
207
- return this._pattern.getTokens();
219
+ getPatterns(): Pattern[] {
220
+ return this._pattern.getPatterns();
208
221
  }
209
222
 
210
- getNextTokens(lastMatched: Pattern): string[] {
223
+ getPatternsAfter(childReference: Pattern): Pattern[] {
211
224
  let index = -1;
212
- const tokens: string[] = [];
225
+ const patterns: Pattern[] = [];
213
226
 
214
227
  for (let i = 0; i < this._children.length; i++) {
215
- if (this._children[i] === lastMatched) {
228
+ if (this._children[i] === childReference) {
216
229
  index = i;
217
230
  }
218
231
  }
219
232
 
233
+ // If the last match isn't a child of this pattern.
220
234
  if (index === -1) {
221
235
  return [];
222
236
  }
223
237
 
238
+ // If the last match was the repeated patterns, then suggest the divider.
224
239
  if (index === 0 && this._divider) {
225
- tokens.push(...this._children[1].getTokens());
240
+ patterns.push(this._children[1]);
226
241
 
227
242
  if (this._parent) {
228
- tokens.push(...this._parent.getNextTokens(this));
243
+ patterns.push(...this._parent.getPatternsAfter(this));
229
244
  }
230
245
  }
231
246
 
247
+ // Suggest the pattern because the divider was the last match.
232
248
  if (index === 1) {
233
- tokens.push(...this._children[0].getTokens());
249
+ patterns.push(this._children[0]);
234
250
  }
235
251
 
236
252
  if (index === 0 && !this._divider && this._parent) {
237
- tokens.push(...this._children[0].getTokens());
238
- tokens.push(...this._parent.getNextTokens(this));
253
+ patterns.push(this._children[0]);
254
+ patterns.push(...this._parent.getPatternsAfter(this));
239
255
  }
240
256
 
241
- return tokens;
257
+ return patterns;
242
258
  }
243
259
 
244
- getNextPattern(): Pattern | null {
245
- return getNextPattern(this)
260
+ getNextPatterns(): Pattern[] {
261
+ if (this.parent == null) {
262
+ return [];
263
+ }
264
+
265
+ return this.parent.getPatternsAfter(this)
246
266
  }
247
267
 
248
- findPattern(isMatch: (p: Pattern) => boolean): Pattern | null {
249
- return findPattern(this, isMatch);
268
+ findPattern(predicate: (p: Pattern) => boolean): Pattern | null {
269
+ return findPattern(this, predicate);
250
270
  }
251
271
 
252
272
  clone(name = this._name, isOptional = this._isOptional): Pattern {
253
- const repeat = new Repeat(name, this._pattern, this._divider, isOptional);
254
- repeat._shouldReduceAst = this._shouldReduceAst;
255
-
256
- return repeat;
273
+ return new Repeat(name, this._pattern, this._divider, isOptional);
257
274
  }
258
275
  }
259
276
 
@@ -1,39 +0,0 @@
1
- import { And } from "./And";
2
- import { findPattern } from "./findPattern";
3
- import { Literal } from "./Literal";
4
-
5
- describe("getNextPatter", ()=>{
6
- test("No Parent", ()=>{
7
- const a = new Literal("a", "A");
8
- const nextPattern = a.getNextPattern();
9
-
10
- expect(nextPattern).toBe(null);
11
- });
12
-
13
- test("No Next Sibling", ()=>{
14
- const a = new Literal("a", "A");
15
- const parent = new And("parent", [a]);
16
- const nextPattern = parent.children[0].getNextPattern();
17
-
18
- expect(nextPattern).toBe(null);
19
- });
20
-
21
- test("Get Parents Sibling", ()=>{
22
- const a = new Literal("a", "A");
23
- const parent = new And("parent", [a]);
24
- const grandParent = new And("grand-parent", [parent]);
25
- const clonedA = findPattern(grandParent, p=>p.name === "a");
26
- const nextPattern = clonedA?.getNextPattern();
27
-
28
- expect(nextPattern).toBe(null);
29
- });
30
-
31
- test("Get Sibling", ()=>{
32
- const a = new Literal("a", "A");
33
- const b = new Literal("b", "B");
34
- const parent = new And("parent", [a, b]);
35
-
36
- const nextPattern = parent.children[0].getNextPattern();
37
- expect(nextPattern?.name).toBe("b");
38
- });
39
- });