clarity-pattern-parser 8.4.14 → 9.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 (100) hide show
  1. package/TODO.md +4 -1
  2. package/dist/grammar/Grammar.d.ts +18 -10
  3. package/dist/grammar/patterns/andLiteral.d.ts +2 -0
  4. package/dist/grammar/patterns/anonymousPattern.d.ts +2 -0
  5. package/dist/grammar/patterns/inlinePattern.d.ts +1 -0
  6. package/dist/grammar/patterns/literals.d.ts +3 -0
  7. package/dist/grammar/patterns/pattern.d.ts +2 -2
  8. package/dist/grammar/patterns.d.ts +2 -0
  9. package/dist/index.browser.js +472 -185
  10. package/dist/index.browser.js.map +1 -1
  11. package/dist/index.d.ts +3 -1
  12. package/dist/index.esm.js +471 -186
  13. package/dist/index.esm.js.map +1 -1
  14. package/dist/index.js +472 -185
  15. package/dist/index.js.map +1 -1
  16. package/dist/patterns/And.d.ts +4 -1
  17. package/dist/patterns/Cursor.d.ts +5 -0
  18. package/dist/patterns/CursorHistory.d.ts +7 -0
  19. package/dist/patterns/FiniteRepeat.d.ts +4 -1
  20. package/dist/patterns/InfiniteRepeat.d.ts +5 -4
  21. package/dist/patterns/Literal.d.ts +6 -5
  22. package/dist/patterns/Not.d.ts +5 -4
  23. package/dist/patterns/Or.d.ts +5 -4
  24. package/dist/patterns/Pattern.d.ts +4 -2
  25. package/dist/patterns/Reference.d.ts +5 -4
  26. package/dist/patterns/Regex.d.ts +5 -4
  27. package/dist/patterns/Repeat.d.ts +3 -0
  28. package/dist/patterns/arePatternsEqual.d.ts +2 -0
  29. package/package.json +1 -1
  30. package/src/grammar/Grammar.test.ts +126 -72
  31. package/src/grammar/Grammar.ts +241 -158
  32. package/src/grammar/patterns/anonymousPattern.ts +23 -0
  33. package/src/grammar/patterns/body.ts +9 -6
  34. package/src/grammar/patterns/comment.ts +3 -2
  35. package/src/grammar/patterns/grammar.ts +15 -12
  36. package/src/grammar/patterns/import.ts +18 -12
  37. package/src/grammar/patterns/literal.ts +2 -3
  38. package/src/grammar/patterns/literals.ts +20 -0
  39. package/src/grammar/patterns/optionsLiteral.ts +19 -0
  40. package/src/grammar/patterns/pattern.ts +23 -9
  41. package/src/grammar/patterns/regexLiteral.ts +1 -0
  42. package/src/grammar/patterns/repeatLiteral.ts +30 -25
  43. package/src/grammar/patterns/sequenceLiteral.ts +24 -0
  44. package/src/grammar/patterns/spaces.ts +8 -6
  45. package/src/grammar/patterns/statement.ts +8 -20
  46. package/src/grammar/patterns.test.ts +38 -0
  47. package/src/grammar/patterns.ts +24 -0
  48. package/src/grammar/spec.md +4 -12
  49. package/src/index.ts +11 -5
  50. package/src/intellisense/AutoComplete.test.ts +41 -40
  51. package/src/intellisense/css/method.ts +2 -2
  52. package/src/intellisense/css/unit.ts +2 -2
  53. package/src/intellisense/css/value.ts +1 -1
  54. package/src/intellisense/javascript/Javascript.test.ts +31 -32
  55. package/src/intellisense/javascript/arrayLiteral.ts +7 -6
  56. package/src/intellisense/javascript/assignment.ts +6 -6
  57. package/src/intellisense/javascript/deleteStatement.ts +2 -2
  58. package/src/intellisense/javascript/escapedCharacter.ts +6 -6
  59. package/src/intellisense/javascript/exponent.ts +6 -6
  60. package/src/intellisense/javascript/expression.ts +18 -17
  61. package/src/intellisense/javascript/fraction.ts +3 -3
  62. package/src/intellisense/javascript/infixOperator.ts +10 -10
  63. package/src/intellisense/javascript/integer.ts +1 -1
  64. package/src/intellisense/javascript/invocation.ts +8 -7
  65. package/src/intellisense/javascript/literal.ts +3 -3
  66. package/src/intellisense/javascript/numberLiteral.ts +5 -4
  67. package/src/intellisense/javascript/objectAccess.ts +2 -3
  68. package/src/intellisense/javascript/objectLiteral.ts +8 -7
  69. package/src/intellisense/javascript/optionalSpaces.ts +2 -1
  70. package/src/intellisense/javascript/parameters.ts +5 -5
  71. package/src/intellisense/javascript/prefixOperator.ts +3 -4
  72. package/src/intellisense/javascript/propertyAccess.ts +9 -8
  73. package/src/intellisense/javascript/stringLiteral.ts +14 -15
  74. package/src/patterns/Cursor.ts +42 -4
  75. package/src/patterns/CursorHistory.ts +20 -4
  76. package/src/patterns/FiniteRepeat.test.ts +52 -51
  77. package/src/patterns/FiniteRepeat.ts +60 -38
  78. package/src/patterns/InfiniteRepeat.test.ts +36 -49
  79. package/src/patterns/InfiniteRepeat.ts +70 -37
  80. package/src/patterns/Literal.test.ts +16 -27
  81. package/src/patterns/Literal.ts +34 -27
  82. package/src/patterns/Not.test.ts +7 -7
  83. package/src/patterns/Not.ts +24 -6
  84. package/src/patterns/Optional.test.ts +164 -0
  85. package/src/patterns/Optional.ts +143 -0
  86. package/src/patterns/{Or.test.ts → Options.test.ts} +51 -49
  87. package/src/patterns/{Or.ts → Options.ts} +32 -23
  88. package/src/patterns/Pattern.ts +6 -5
  89. package/src/patterns/Reference.test.ts +21 -22
  90. package/src/patterns/Reference.ts +26 -15
  91. package/src/patterns/Regex.test.ts +15 -15
  92. package/src/patterns/Regex.ts +29 -19
  93. package/src/patterns/Repeat.test.ts +12 -22
  94. package/src/patterns/Repeat.ts +22 -21
  95. package/src/patterns/{And.test.ts → Sequence.test.ts} +78 -78
  96. package/src/patterns/{And.ts → Sequence.ts} +40 -29
  97. package/src/patterns/arePatternsEqual.ts +12 -0
  98. package/src/patterns/clonePatterns.ts +2 -2
  99. package/src/grammar/patterns/andLiteral.ts +0 -8
  100. package/src/grammar/patterns/orLiteral.ts +0 -8
@@ -1,21 +1,21 @@
1
1
  import { Cursor } from "./Cursor";
2
2
  import { Regex } from "./Regex";
3
3
  import { Node } from "../ast/Node"
4
- import { And } from "./And";
4
+ import { Sequence } from "./Sequence";
5
5
  import { Literal } from "./Literal";
6
6
  import { Pattern } from "./Pattern";
7
7
 
8
8
  describe("Regex", () => {
9
9
  test("Empty String", () => {
10
- expect(() => new Regex("empty", "")).toThrowError()
10
+ expect(() => new Regex("empty", "")).toThrowError();
11
11
  });
12
12
 
13
13
  test("Starts With ^", () => {
14
- expect(() => new Regex("carrot", "^")).toThrowError()
14
+ expect(() => new Regex("carrot", "^")).toThrowError();
15
15
  });
16
16
 
17
17
  test("Ends With $", () => {
18
- expect(() => new Regex("money", ".$")).toThrowError()
18
+ expect(() => new Regex("money", ".$")).toThrowError();
19
19
  });
20
20
 
21
21
  test("Successful Parse", () => {
@@ -25,8 +25,8 @@ describe("Regex", () => {
25
25
  const expected = new Node("regex", "number", 0, 0, [], "1");
26
26
 
27
27
  expect(result).toEqual(expected);
28
- expect(cursor.hasError).toBeFalsy()
29
- })
28
+ expect(cursor.hasError).toBeFalsy();
29
+ });
30
30
 
31
31
  test("Failed Parse", () => {
32
32
  const number = new Regex("number", "\\d");
@@ -34,7 +34,7 @@ describe("Regex", () => {
34
34
  const result = number.parse(cursor);
35
35
 
36
36
  expect(result).toBeNull();
37
- expect(cursor.hasError).toBeTruthy()
37
+ expect(cursor.hasError).toBeTruthy();
38
38
  });
39
39
 
40
40
 
@@ -54,7 +54,7 @@ describe("Regex", () => {
54
54
  const tokens = regex.getTokensAfter(new Literal("bogus", "bogus"));
55
55
  const expected: string[] = [];
56
56
 
57
- expect(tokens).toEqual(expected)
57
+ expect(tokens).toEqual(expected);
58
58
  });
59
59
 
60
60
  test("Properties", () => {
@@ -85,7 +85,7 @@ describe("Regex", () => {
85
85
  });
86
86
 
87
87
  test("Get Next Tokens", () => {
88
- const parent = new And("parent", [new Regex("a", "A"), new Literal("b", "B")]);
88
+ const parent = new Sequence("parent", [new Regex("a", "A"), new Literal("b", "B")]);
89
89
  const aClone = parent.find(p => p.name === "a") as Pattern;
90
90
  const tokens = aClone.getNextTokens();
91
91
 
@@ -93,7 +93,7 @@ describe("Regex", () => {
93
93
  });
94
94
 
95
95
  test("Get Next Tokens With Null Parent", () => {
96
- const a = new Regex("a", "A")
96
+ const a = new Regex("a", "A");
97
97
  const tokens = a.getNextTokens();
98
98
 
99
99
  expect(tokens).toEqual([]);
@@ -109,21 +109,21 @@ describe("Regex", () => {
109
109
  });
110
110
 
111
111
  test("Get Patterns After", () => {
112
- const a = new Regex("a", "A")
112
+ const a = new Regex("a", "A");
113
113
  const patterns = a.getPatternsAfter(new Literal("bogus", "bogus"));
114
114
 
115
115
  expect(patterns).toEqual([]);
116
116
  });
117
117
 
118
118
  test("Find Pattern", () => {
119
- const a = new Regex("a", "A")
119
+ const a = new Regex("a", "A");
120
120
  const pattern = a.find(p => p.name === "other");
121
121
 
122
122
  expect(pattern).toBeNull();
123
123
  });
124
124
 
125
125
  test("Get Next Patterns", () => {
126
- const parent = new And("parent", [new Regex("a", "A"), new Literal("b", "B")]);
126
+ const parent = new Sequence("parent", [new Regex("a", "A"), new Literal("b", "B")]);
127
127
  const aClone = parent.find(p => p.name === "a") as Pattern;
128
128
  const bClone = parent.find(p => p.name === "b") as Pattern;
129
129
  const patterns = aClone.getNextPatterns();
@@ -133,10 +133,10 @@ describe("Regex", () => {
133
133
  });
134
134
 
135
135
  test("Get Next Patterns With Null Parent", () => {
136
- const a = new Regex("a", "A")
136
+ const a = new Regex("a", "A");
137
137
  const patterns = a.getNextPatterns();
138
138
 
139
- expect(patterns).toEqual([])
139
+ expect(patterns).toEqual([]);
140
140
  });
141
141
 
142
142
  });
@@ -1,11 +1,14 @@
1
1
  import { Node } from "../ast/Node";
2
2
  import { Pattern } from "./Pattern";
3
3
  import { Cursor } from "./Cursor";
4
+ import { ParseResult } from "./ParseResult";
5
+
6
+ let idIndex = 0;
4
7
 
5
8
  export class Regex implements Pattern {
9
+ private _id: string;
6
10
  private _type: string;
7
11
  private _name: string;
8
- private _isOptional: boolean;
9
12
  private _parent: Pattern | null;
10
13
  private _originalRegexString: string;
11
14
  private _regex: RegExp;
@@ -15,6 +18,10 @@ export class Regex implements Pattern {
15
18
  private _substring = "";
16
19
  private _tokens: string[] = [];
17
20
 
21
+ get id(): string {
22
+ return this._id;
23
+ }
24
+
18
25
  get type(): string {
19
26
  return this._type;
20
27
  }
@@ -35,14 +42,10 @@ export class Regex implements Pattern {
35
42
  return [];
36
43
  }
37
44
 
38
- get isOptional(): boolean {
39
- return this._isOptional;
40
- }
41
-
42
- constructor(name: string, regex: string, isOptional = false) {
43
- this._type = "regex"
45
+ constructor(name: string, regex: string) {
46
+ this._id = `regex-${idIndex++}`;
47
+ this._type = "regex";
44
48
  this._name = name;
45
- this._isOptional = isOptional;
46
49
  this._parent = null;
47
50
  this._originalRegexString = regex;
48
51
  this._regex = new RegExp(`^${regex}`, "g");
@@ -76,8 +79,10 @@ export class Regex implements Pattern {
76
79
  return ast?.value === text;
77
80
  }
78
81
 
79
- exec(text: string) {
82
+ exec(text: string, record = false): ParseResult {
80
83
  const cursor = new Cursor(text);
84
+ record && cursor.startRecording();
85
+
81
86
  const ast = this.parse(cursor);
82
87
 
83
88
  return {
@@ -87,10 +92,13 @@ export class Regex implements Pattern {
87
92
  }
88
93
 
89
94
  parse(cursor: Cursor) {
95
+ cursor.startParseWith(this);
96
+
90
97
  this._firstIndex = cursor.index;
91
98
  this.resetState(cursor);
92
99
  this.tryToParse(cursor);
93
100
 
101
+ cursor.endParse();
94
102
  return this._node;
95
103
  }
96
104
 
@@ -129,18 +137,16 @@ export class Regex implements Pattern {
129
137
  }
130
138
 
131
139
  private processError(cursor: Cursor) {
132
- if (!this._isOptional) {
133
- cursor.recordErrorAt(this._firstIndex, this._firstIndex, this);
134
- }
135
-
140
+ cursor.recordErrorAt(this._firstIndex, this._firstIndex, this);
136
141
  this._node = null;
137
142
  }
138
143
 
139
- clone(name = this._name, isOptional = this._isOptional) {
140
- const pattern = new Regex(name, this._originalRegexString, isOptional);
141
- pattern._tokens = this._tokens.slice();
144
+ clone(name = this._name) {
145
+ const clone = new Regex(name, this._originalRegexString);
146
+ clone._tokens = this._tokens.slice();
142
147
 
143
- return pattern;
148
+ clone._id = this._id;
149
+ return clone;
144
150
  }
145
151
 
146
152
  getTokens() {
@@ -153,7 +159,7 @@ export class Regex implements Pattern {
153
159
 
154
160
  getNextTokens(): string[] {
155
161
  if (this.parent == null) {
156
- return []
162
+ return [];
157
163
  }
158
164
 
159
165
  return this.parent.getTokensAfter(this);
@@ -172,7 +178,7 @@ export class Regex implements Pattern {
172
178
  return [];
173
179
  }
174
180
 
175
- return this.parent.getPatternsAfter(this)
181
+ return this.parent.getPatternsAfter(this);
176
182
  }
177
183
 
178
184
  find(_predicate: (p: Pattern) => boolean): Pattern | null {
@@ -183,4 +189,8 @@ export class Regex implements Pattern {
183
189
  this._tokens = tokens;
184
190
  }
185
191
 
192
+ isEqual(pattern: Regex): boolean {
193
+ return pattern.type === this.type && pattern._originalRegexString === this._originalRegexString;
194
+ }
195
+
186
196
  }
@@ -1,5 +1,6 @@
1
1
  import { Node } from "../ast/Node";
2
- import { And } from "./And";
2
+ import { Sequence } from "./Sequence";
3
+ import { arePatternsEqual } from "./arePatternsEqual";
3
4
  import { Cursor } from "./Cursor";
4
5
  import { InfiniteRepeat } from "./InfiniteRepeat";
5
6
  import { Literal } from "./Literal";
@@ -26,7 +27,7 @@ describe("Repeat", () => {
26
27
  new Node("regex", "number", 0, 0, [], "1")
27
28
  ]);
28
29
 
29
- expect(result).toEqual(expected);
30
+ expect(result?.toJson()).toEqual(expected.toJson());
30
31
  expect(cursor.hasError).toBeFalsy();
31
32
 
32
33
  cursor = new Cursor("12");
@@ -36,7 +37,7 @@ describe("Repeat", () => {
36
37
  new Node("regex", "number", 1, 1, [], "2")
37
38
  ]);
38
39
 
39
- expect(result).toEqual(expected);
40
+ expect(result?.toJson()).toEqual(expected.toJson());
40
41
  expect(cursor.hasError).toBeFalsy();
41
42
 
42
43
  cursor = new Cursor("123");
@@ -46,7 +47,7 @@ describe("Repeat", () => {
46
47
  new Node("regex", "number", 1, 1, [], "2")
47
48
  ]);
48
49
 
49
- expect(result).toEqual(expected);
50
+ expect(result?.toJson()).toEqual(expected.toJson());
50
51
  expect(cursor.hasError).toBeFalsy();
51
52
  expect(cursor.index).toBe(1);
52
53
  });
@@ -76,7 +77,7 @@ describe("Repeat", () => {
76
77
  new Node("regex", "number", 1, 1, [], "2")
77
78
  ]);
78
79
 
79
- expect(result).toEqual(expected);
80
+ expect(result?.toJson()).toEqual(expected.toJson());
80
81
  expect(cursor.hasError).toBeFalsy();
81
82
 
82
83
  cursor = new Cursor("123");
@@ -86,7 +87,7 @@ describe("Repeat", () => {
86
87
  new Node("regex", "number", 1, 1, [], "2")
87
88
  ]);
88
89
 
89
- expect(result).toEqual(expected);
90
+ expect(result?.toJson()).toEqual(expected.toJson());
90
91
  expect(cursor.hasError).toBeFalsy();
91
92
  expect(cursor.index).toBe(1);
92
93
  });
@@ -115,7 +116,7 @@ describe("Repeat", () => {
115
116
  test("Get Tokens After", () => {
116
117
  const number = new Literal("number", "1");
117
118
  const repeat = new Repeat("numbers", number);
118
- const parent = new And("parent", [repeat, new Literal("b", "B")]);
119
+ const parent = new Sequence("parent", [repeat, new Literal("b", "B")]);
119
120
  const numberClone = parent.find(p => p.name === "number") as Pattern;
120
121
  const repeatClone = parent.children[0];
121
122
 
@@ -128,7 +129,7 @@ describe("Repeat", () => {
128
129
  test("Get Next Tokens", () => {
129
130
  const number = new Literal("number", "1");
130
131
  const repeat = new Repeat("numbers", number);
131
- const parent = new And("parent", [repeat, new Literal("b", "B")]);
132
+ const parent = new Sequence("parent", [repeat, new Literal("b", "B")]);
132
133
  const repeatClone = parent.children[0];
133
134
 
134
135
  let tokens = repeatClone.getNextTokens();
@@ -140,7 +141,7 @@ describe("Repeat", () => {
140
141
  test("Get Next Patterns", () => {
141
142
  const number = new Literal("number", "1");
142
143
  const repeat = new Repeat("numbers", number);
143
- const parent = new And("parent", [repeat, new Literal("b", "B")]);
144
+ const parent = new Sequence("parent", [repeat, new Literal("b", "B")]);
144
145
  const repeatClone = parent.children[0];
145
146
  const bClone = parent.find(p => p.name === "b") as Pattern;
146
147
 
@@ -178,7 +179,6 @@ describe("Repeat", () => {
178
179
  expect(repeat.type).toBe("infinite-repeat");
179
180
  expect(repeat.name).toBe("numbers");
180
181
  expect(repeat.parent).toBeNull();
181
- expect(repeat.isOptional).toBeFalsy();
182
182
  });
183
183
 
184
184
  test("test", () => {
@@ -202,21 +202,11 @@ describe("Repeat", () => {
202
202
  let repeatClone = repeat.clone();
203
203
  let expected = new Repeat("numbers", number);
204
204
 
205
- expect(repeatClone).toEqual(expected);
205
+ expect(arePatternsEqual(repeatClone, expected)).toBeTruthy();
206
206
 
207
207
  repeatClone = repeat.clone("new-name");
208
208
  expected = new Repeat("new-name", number);
209
209
 
210
- expect(repeatClone).toEqual(expected);
211
-
212
- repeatClone = repeat.clone("new-name", false);
213
- expected = new Repeat("new-name", number);
214
-
215
- expect(repeatClone).toEqual(expected);
216
-
217
- repeatClone = repeat.clone("new-name", true);
218
- expected = new Repeat("new-name", number, { min: 0 });
219
-
220
- expect(repeatClone).toEqual(expected);
210
+ expect(arePatternsEqual(repeatClone, expected)).toBeTruthy();
221
211
  });
222
212
  });
@@ -5,6 +5,8 @@ import { InfiniteRepeat } from "./InfiniteRepeat";
5
5
  import { ParseResult } from "./ParseResult";
6
6
  import { Pattern } from "./Pattern";
7
7
 
8
+ let idIndex = 0;
9
+
8
10
  export interface RepeatOptions {
9
11
  min?: number;
10
12
  max?: number;
@@ -19,12 +21,17 @@ interface InternalRepeatOptions {
19
21
  }
20
22
 
21
23
  export class Repeat implements Pattern {
24
+ private _id: string;
22
25
  private _repeatPattern: InfiniteRepeat | FiniteRepeat;
23
26
  private _parent: Pattern | null;
24
27
  private _pattern: Pattern;
25
28
  private _options: InternalRepeatOptions;
26
29
  private _children: Pattern[];
27
30
 
31
+ get id() {
32
+ return this._id;
33
+ }
34
+
28
35
  get type() {
29
36
  return this._repeatPattern.type;
30
37
  }
@@ -45,11 +52,8 @@ export class Repeat implements Pattern {
45
52
  return this._children;
46
53
  }
47
54
 
48
- get isOptional() {
49
- return this._repeatPattern.isOptional;
50
- }
51
-
52
55
  constructor(name: string, pattern: Pattern, options: RepeatOptions = {}) {
56
+ this._id = `repeat-${idIndex++}`;
53
57
  this._pattern = pattern;
54
58
  this._parent = null;
55
59
  this._options = {
@@ -59,12 +63,12 @@ export class Repeat implements Pattern {
59
63
  };
60
64
 
61
65
  if (this._options.max !== Infinity) {
62
- this._repeatPattern = new FiniteRepeat(name, pattern, this._options.max, this._options);
66
+ this._repeatPattern = new FiniteRepeat(name, pattern, this._options);
63
67
  } else {
64
- this._repeatPattern = new InfiniteRepeat(name, pattern, this._options)
68
+ this._repeatPattern = new InfiniteRepeat(name, pattern, this._options);
65
69
  }
66
70
 
67
- this._children = [this._repeatPattern]
71
+ this._children = [this._repeatPattern];
68
72
  this._repeatPattern.parent = this;
69
73
  }
70
74
 
@@ -80,18 +84,12 @@ export class Repeat implements Pattern {
80
84
  return this._repeatPattern.test(text);
81
85
  }
82
86
 
83
- clone(name = this.name, isOptional?: boolean) {
87
+ clone(name = this.name) {
84
88
  let min = this._options.min;
89
+ const clone = new Repeat(name, this._pattern, { ...this._options, min });
85
90
 
86
- if (isOptional != null) {
87
- if (isOptional) {
88
- min = 0
89
- } else {
90
- min = Math.max(this._options.min, 1);
91
- }
92
- }
93
-
94
- return new Repeat(name, this._pattern, { ...this._options, min });
91
+ clone._id = this._id;
92
+ return clone;
95
93
  }
96
94
 
97
95
  getTokens(): string[] {
@@ -100,7 +98,7 @@ export class Repeat implements Pattern {
100
98
 
101
99
  getTokensAfter(_childReference: Pattern): string[] {
102
100
  if (this._parent == null) {
103
- return []
101
+ return [];
104
102
  }
105
103
 
106
104
  return this._parent.getTokensAfter(this);
@@ -108,7 +106,7 @@ export class Repeat implements Pattern {
108
106
 
109
107
  getNextTokens(): string[] {
110
108
  if (this._parent == null) {
111
- return []
109
+ return [];
112
110
  }
113
111
 
114
112
  return this._parent.getTokensAfter(this);
@@ -120,7 +118,7 @@ export class Repeat implements Pattern {
120
118
 
121
119
  getPatternsAfter(_childReference: Pattern): Pattern[] {
122
120
  if (this._parent == null) {
123
- return []
121
+ return [];
124
122
  }
125
123
 
126
124
  return this._parent.getPatternsAfter(this);
@@ -128,7 +126,7 @@ export class Repeat implements Pattern {
128
126
 
129
127
  getNextPatterns(): Pattern[] {
130
128
  if (this._parent == null) {
131
- return []
129
+ return [];
132
130
  }
133
131
 
134
132
  return this._parent.getPatternsAfter(this);
@@ -138,4 +136,7 @@ export class Repeat implements Pattern {
138
136
  return this._repeatPattern.find(predicate);
139
137
  }
140
138
 
139
+ isEqual(pattern: Repeat): boolean {
140
+ return pattern.type === this.type && this.children.every((c, index) => c.isEqual(pattern.children[index]));
141
+ }
141
142
  }