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
@@ -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,62 @@ 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 Next Patterns", () => {
202
+ const integer = new Repeat("integer", new Regex("digit", "\\d"));
203
+ const parent = new And("parent", [integer, new Literal("pow", "!")]);
204
+ const integerClone = parent.findPattern(p => p.name === "integer") as Pattern;
205
+ const powClone = parent.findPattern(p => p.name === "pow") as Pattern;
206
+ const patterns = integerClone.getNextPatterns();
207
+
208
+ expect(patterns.length).toBe(1);
209
+ expect(patterns[0]).toBe(powClone);
210
+ });
211
+
212
+ test("Get Next Patterns With Null Parents", () => {
213
+ const integer = new Repeat("integer", new Regex("digit", "\\d"));
214
+ const patterns = integer.getNextPatterns();
215
+
216
+ expect(patterns.length).toBe(0);
217
+ });
196
218
  });
@@ -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,78 @@ 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
200
  }
201
201
 
202
- disableAstReduction(): void {
203
- this._shouldReduceAst = false;
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;
204
209
  }
205
210
 
206
- getTokens(): string[] {
207
- return this._pattern.getTokens();
211
+ getNextTokens(): string[] {
212
+ if (this.parent == null) {
213
+ return []
214
+ }
215
+
216
+ return this.parent.getTokensAfter(this);
208
217
  }
209
218
 
210
- getNextTokens(lastMatched: Pattern): string[] {
219
+ getPatternsAfter(childReference: Pattern): Pattern[] {
211
220
  let index = -1;
212
- const tokens: string[] = [];
221
+ const patterns: Pattern[] = [];
213
222
 
214
223
  for (let i = 0; i < this._children.length; i++) {
215
- if (this._children[i] === lastMatched) {
224
+ if (this._children[i] === childReference) {
216
225
  index = i;
217
226
  }
218
227
  }
219
228
 
229
+ // If the last match isn't a child of this pattern.
220
230
  if (index === -1) {
221
231
  return [];
222
232
  }
223
233
 
234
+ // If the last match was the repeated patterns, then suggest the divider.
224
235
  if (index === 0 && this._divider) {
225
- tokens.push(...this._children[1].getTokens());
236
+ patterns.push(this._children[1]);
226
237
 
227
238
  if (this._parent) {
228
- tokens.push(...this._parent.getNextTokens(this));
239
+ patterns.push(...this._parent.getPatternsAfter(this));
229
240
  }
230
241
  }
231
242
 
243
+ // Suggest the pattern because the divider was the last match.
232
244
  if (index === 1) {
233
- tokens.push(...this._children[0].getTokens());
245
+ patterns.push(this._children[0]);
234
246
  }
235
247
 
236
248
  if (index === 0 && !this._divider && this._parent) {
237
- tokens.push(...this._children[0].getTokens());
238
- tokens.push(...this._parent.getNextTokens(this));
249
+ patterns.push(this._children[0]);
250
+ patterns.push(...this._parent.getPatternsAfter(this));
239
251
  }
240
252
 
241
- return tokens;
253
+ return patterns;
242
254
  }
243
255
 
244
- getNextPattern(): Pattern | null {
245
- return getNextPattern(this)
256
+ getNextPatterns(): Pattern[] {
257
+ if (this.parent == null) {
258
+ return [];
259
+ }
260
+
261
+ return this.parent.getPatternsAfter(this)
246
262
  }
247
263
 
248
- findPattern(isMatch: (p: Pattern) => boolean): Pattern | null {
249
- return findPattern(this, isMatch);
264
+ findPattern(predicate: (p: Pattern) => boolean): Pattern | null {
265
+ return findPattern(this, predicate);
250
266
  }
251
267
 
252
268
  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;
269
+ return new Repeat(name, this._pattern, this._divider, isOptional);
257
270
  }
258
271
  }
259
272
 
@@ -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
- });
@@ -1,18 +0,0 @@
1
- import { Pattern } from "./Pattern";
2
-
3
- export function getNextPattern(pattern: Pattern): Pattern | null {
4
- const parent = pattern.parent;
5
-
6
- if (parent == null) {
7
- return null;
8
- }
9
-
10
- const patternIndex = parent.children.indexOf(pattern);
11
- const nextPattern = parent.children[patternIndex + 1] || null;
12
-
13
- if (nextPattern == null) {
14
- return parent.getNextPattern();
15
- }
16
-
17
- return nextPattern;
18
- }