clarity-pattern-parser 6.0.0 → 7.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 (94) hide show
  1. package/TODO.md +1 -76
  2. package/dist/ast/Node.d.ts +1 -0
  3. package/dist/grammar/Grammar.d.ts +17 -0
  4. package/dist/grammar/patterns/andLiteral.d.ts +2 -0
  5. package/dist/grammar/patterns/comment.d.ts +2 -0
  6. package/dist/grammar/patterns/grammar.d.ts +2 -0
  7. package/dist/grammar/patterns/literal.d.ts +2 -0
  8. package/dist/grammar/patterns/name.d.ts +2 -0
  9. package/dist/grammar/patterns/orLiteral.d.ts +2 -0
  10. package/dist/grammar/patterns/pattern.d.ts +2 -0
  11. package/dist/grammar/patterns/regexLiteral.d.ts +2 -0
  12. package/dist/grammar/patterns/repeatLiteral.d.ts +3 -0
  13. package/dist/grammar/patterns/spaces.d.ts +2 -0
  14. package/dist/grammar/patterns/statement.d.ts +2 -0
  15. package/dist/index.browser.js +1205 -550
  16. package/dist/index.browser.js.map +1 -1
  17. package/dist/index.d.ts +5 -4
  18. package/dist/index.esm.js +1203 -549
  19. package/dist/index.esm.js.map +1 -1
  20. package/dist/index.js +1203 -548
  21. package/dist/index.js.map +1 -1
  22. package/dist/intellisense/AutoComplete.d.ts +9 -7
  23. package/dist/intellisense/Suggestion.d.ts +1 -2
  24. package/dist/patterns/And.d.ts +2 -1
  25. package/dist/patterns/Cursor.d.ts +1 -0
  26. package/dist/patterns/CursorHistory.d.ts +2 -1
  27. package/dist/patterns/FiniteRepeat.d.ts +39 -0
  28. package/dist/patterns/InfiniteRepeat.d.ts +47 -0
  29. package/dist/patterns/Literal.d.ts +2 -1
  30. package/dist/patterns/Not.d.ts +2 -1
  31. package/dist/patterns/Or.d.ts +2 -1
  32. package/dist/patterns/Pattern.d.ts +3 -2
  33. package/dist/patterns/Reference.d.ts +2 -1
  34. package/dist/patterns/Regex.d.ts +2 -1
  35. package/dist/patterns/Repeat.d.ts +19 -22
  36. package/jest.config.js +0 -1
  37. package/jest.coverage.config.js +13 -0
  38. package/package.json +3 -3
  39. package/src/ast/Node.test.ts +21 -0
  40. package/src/ast/Node.ts +12 -6
  41. package/src/grammar/Grammar.test.ts +288 -0
  42. package/src/grammar/Grammar.ts +234 -0
  43. package/src/grammar/patterns/andLiteral.ts +8 -0
  44. package/src/grammar/patterns/comment.ts +3 -0
  45. package/src/grammar/patterns/grammar.ts +19 -0
  46. package/src/grammar/patterns/literal.ts +5 -0
  47. package/src/grammar/patterns/name.ts +3 -0
  48. package/src/grammar/patterns/orLiteral.ts +8 -0
  49. package/src/grammar/patterns/pattern.ts +13 -0
  50. package/src/grammar/patterns/regexLiteral.ts +4 -0
  51. package/src/grammar/patterns/repeatLiteral.ts +72 -0
  52. package/src/grammar/patterns/spaces.ts +4 -0
  53. package/src/grammar/patterns/statement.ts +35 -0
  54. package/src/grammar/spec.md +142 -0
  55. package/src/index.ts +6 -3
  56. package/src/intellisense/AutoComplete.test.ts +125 -39
  57. package/src/intellisense/AutoComplete.ts +52 -36
  58. package/src/intellisense/Suggestion.ts +1 -2
  59. package/src/intellisense/css/cssValue.ts +1 -1
  60. package/src/intellisense/css/method.ts +1 -1
  61. package/src/intellisense/css/values.ts +1 -1
  62. package/src/intellisense/javascript/Javascript.test.ts +34 -11
  63. package/src/intellisense/javascript/arrayLiteral.ts +1 -1
  64. package/src/intellisense/javascript/{expressionStatement.ts → assignment.ts} +7 -8
  65. package/src/intellisense/javascript/expression.ts +45 -27
  66. package/src/intellisense/javascript/infixOperator.ts +6 -2
  67. package/src/intellisense/javascript/invocation.ts +1 -1
  68. package/src/intellisense/javascript/keywords.ts +3 -0
  69. package/src/intellisense/javascript/objectAccess.ts +9 -0
  70. package/src/intellisense/javascript/objectLiteral.ts +3 -3
  71. package/src/intellisense/javascript/parameters.ts +1 -1
  72. package/src/intellisense/javascript/propertyAccess.ts +8 -3
  73. package/src/intellisense/javascript/stringLiteral.ts +14 -8
  74. package/src/patterns/And.test.ts +16 -3
  75. package/src/patterns/And.ts +25 -17
  76. package/src/patterns/Cursor.ts +4 -0
  77. package/src/patterns/CursorHistory.ts +34 -5
  78. package/src/patterns/FiniteRepeat.test.ts +481 -0
  79. package/src/patterns/FiniteRepeat.ts +231 -0
  80. package/src/patterns/InfiniteRepeat.test.ts +296 -0
  81. package/src/patterns/InfiniteRepeat.ts +329 -0
  82. package/src/patterns/Literal.test.ts +13 -4
  83. package/src/patterns/Literal.ts +5 -1
  84. package/src/patterns/Not.test.ts +20 -9
  85. package/src/patterns/Not.ts +5 -1
  86. package/src/patterns/Or.test.ts +18 -7
  87. package/src/patterns/Or.ts +11 -1
  88. package/src/patterns/Pattern.ts +3 -2
  89. package/src/patterns/Reference.test.ts +18 -8
  90. package/src/patterns/Reference.ts +5 -1
  91. package/src/patterns/Regex.test.ts +13 -4
  92. package/src/patterns/Regex.ts +5 -1
  93. package/src/patterns/Repeat.test.ts +162 -158
  94. package/src/patterns/Repeat.ts +95 -226
@@ -1,4 +1,5 @@
1
1
  import { Cursor } from "../patterns/Cursor";
2
+ import { Match } from "../patterns/CursorHistory";
2
3
  import { Pattern } from "../patterns/Pattern";
3
4
  import { Suggestion } from "./Suggestion";
4
5
  import { SuggestionOption } from "./SuggestionOption";
@@ -9,12 +10,12 @@ export interface AutoCompleteOptions {
9
10
  * Be very careful, this can explode to infinity pretty quick. Usually useful
10
11
  * for dividers and spaces.
11
12
  */
12
- greedyPatternNames: string[];
13
+ greedyPatternNames?: string[];
13
14
  /**
14
15
  * Allows for custom suggestions for patterns. The key is the name of the pattern
15
16
  * and the string array are the tokens suggested for that pattern.
16
17
  */
17
- customTokens: Record<string, string[]>;
18
+ customTokens?: Record<string, string[]>;
18
19
  }
19
20
 
20
21
  const defaultOptions = { greedyPatternNames: [], customTokens: {} };
@@ -31,12 +32,12 @@ export class AutoComplete {
31
32
  this._text = "";
32
33
  }
33
34
 
34
- suggest(text: string): Suggestion {
35
+ suggestFor(text: string): Suggestion {
35
36
  if (text.length === 0) {
36
37
  return {
37
38
  isComplete: false,
38
- options: this.createSuggestionsFromRoot(),
39
- nextPatterns: [this._pattern],
39
+ options: this._createSuggestionsFromRoot(),
40
+ errorAtIndex: 0,
40
41
  cursor: null,
41
42
  ast: null
42
43
  }
@@ -44,50 +45,54 @@ export class AutoComplete {
44
45
 
45
46
  this._text = text;
46
47
  this._cursor = new Cursor(text);
47
- const ast = this._pattern.parse(this._cursor);
48
48
 
49
- const leafPattern = this._cursor.leafMatch.pattern;
49
+ let errorAtIndex = null;
50
+
51
+ const ast = this._pattern.parse(this._cursor);
50
52
  const isComplete = ast?.value === text;
51
- const options = this.createSuggestionsFromTokens();
53
+ const options = this._getAllOptions();
52
54
 
53
- let nextPatterns = [this._pattern];
55
+ if (this._cursor.hasError && this._cursor.furthestError != null) {
56
+ errorAtIndex = this._cursor.furthestError.index;
54
57
 
55
- if (leafPattern != null) {
56
- nextPatterns = leafPattern.getNextPatterns();
58
+ errorAtIndex = options.reduce((errorAtIndex, option) =>
59
+ Math.max(errorAtIndex, option.startIndex),
60
+ errorAtIndex);
57
61
  }
58
62
 
59
63
  return {
60
64
  isComplete: isComplete,
61
65
  options: options,
62
- nextPatterns,
66
+ errorAtIndex,
63
67
  cursor: this._cursor,
64
68
  ast,
65
69
  }
66
70
  }
67
71
 
68
- private createSuggestionsFromRoot(): SuggestionOption[] {
72
+ private _getAllOptions() {
73
+ return this._cursor.leafMatches.map((m) => this._createSuggestionsFromMatch(m)).flat();
74
+ }
75
+
76
+ private _createSuggestionsFromRoot(): SuggestionOption[] {
69
77
  const suggestions: SuggestionOption[] = [];
70
78
  const tokens = this._pattern.getTokens();
71
79
 
72
80
  for (const token of tokens) {
73
- suggestions.push(this.createSuggestion("", token));
81
+ suggestions.push(this._createSuggestion("", token));
74
82
  }
75
83
 
76
84
  return suggestions;
77
85
  }
78
86
 
79
- private createSuggestionsFromTokens(): SuggestionOption[] {
80
- const leafMatch = this._cursor.leafMatch;
81
-
82
- if (!leafMatch.pattern) {
83
- return this.createSuggestions(-1, this._getTokensForPattern(this._pattern));
87
+ private _createSuggestionsFromMatch(match: Match): SuggestionOption[] {
88
+ if (!match.pattern) {
89
+ return this._createSuggestions(-1, this._getTokensForPattern(this._pattern));
84
90
  }
85
91
 
86
- const leafPattern = leafMatch.pattern;
87
- const leafNode = leafMatch.node;
88
- const parent = leafMatch.pattern.parent;
92
+ const leafPattern = match.pattern;
93
+ const parent = match.pattern.parent;
89
94
 
90
- if (parent !== null && leafMatch.node != null) {
95
+ if (parent !== null && match.node != null) {
91
96
  const patterns = leafPattern.getNextPatterns();
92
97
 
93
98
  const tokens = patterns.reduce((acc: string[], pattern) => {
@@ -95,39 +100,50 @@ export class AutoComplete {
95
100
  return acc;
96
101
  }, []);
97
102
 
98
- return this.createSuggestions(leafMatch.node.lastIndex, tokens);
103
+ return this._createSuggestions(match.node.lastIndex, tokens);
99
104
  } else {
100
105
  return [];
101
106
  }
102
107
  }
103
108
 
104
109
  private _getTokensForPattern(pattern: Pattern) {
105
- if (this._options.greedyPatternNames.includes(pattern.name)) {
106
- const greedyTokens = pattern.getTokens();
110
+ const augmentedTokens = this._getAugmentedTokens(pattern)
111
+
112
+ if (this._options.greedyPatternNames != null && this._options.greedyPatternNames.includes(pattern.name)) {
107
113
  const nextPatterns = pattern.getNextPatterns();
108
114
  const tokens: string[] = [];
109
115
 
110
- const nextPatternTokens = nextPatterns.reduce((acc: string[], pattern)=>{
116
+ const nextPatternTokens = nextPatterns.reduce((acc: string[], pattern) => {
111
117
  acc.push(...this._getTokensForPattern(pattern));
112
118
  return acc;
113
119
  }, []);
114
120
 
115
- for (let token of greedyTokens){
116
- for (let nextPatternToken of nextPatternTokens){
121
+ for (let token of augmentedTokens) {
122
+ for (let nextPatternToken of nextPatternTokens) {
117
123
  tokens.push(token + nextPatternToken);
118
124
  }
119
125
  }
120
126
 
121
127
  return tokens;
122
128
  } else {
123
- const tokens = pattern.getTokens();
124
- const customTokens = this._options.customTokens[pattern.name] || [];
125
- tokens.push(...customTokens);
126
- return tokens;
129
+ return augmentedTokens;
127
130
  }
128
131
  }
129
132
 
130
- private createSuggestions(lastIndex: number, tokens: string[]): SuggestionOption[] {
133
+ private _getAugmentedTokens(pattern: Pattern) {
134
+ const customTokensMap: any = this._options.customTokens || {};
135
+ const leafPatterns = pattern.getPatterns();
136
+ const tokens: string[] = customTokensMap[pattern.name] || [];
137
+
138
+ leafPatterns.forEach(p => {
139
+ const augmentedTokens = customTokensMap[p.name] || [];
140
+ tokens.push(...p.getTokens(), ...augmentedTokens);
141
+ });
142
+
143
+ return tokens;
144
+ }
145
+
146
+ private _createSuggestions(lastIndex: number, tokens: string[]): SuggestionOption[] {
131
147
  let substring = lastIndex === -1 ? "" : this._cursor.getChars(0, lastIndex);
132
148
  const suggestionStrings: string[] = [];
133
149
  const options: SuggestionOption[] = [];
@@ -140,7 +156,7 @@ export class AutoComplete {
140
156
 
141
157
  if (startsWith && !alreadyExist && !isSameAsText) {
142
158
  suggestionStrings.push(suggestion);
143
- options.push(this.createSuggestion(this._cursor.text, suggestion));
159
+ options.push(this._createSuggestion(this._cursor.text, suggestion));
144
160
  }
145
161
  }
146
162
 
@@ -150,7 +166,7 @@ export class AutoComplete {
150
166
  return reducedOptions;
151
167
  }
152
168
 
153
- private createSuggestion(fullText: string, suggestion: string): SuggestionOption {
169
+ private _createSuggestion(fullText: string, suggestion: string): SuggestionOption {
154
170
  const furthestMatch = findMatchIndex(suggestion, fullText);
155
171
  const text = suggestion.slice(furthestMatch);
156
172
 
@@ -1,12 +1,11 @@
1
1
  import { Node } from "../ast/Node";
2
2
  import { Cursor } from "../patterns/Cursor";
3
- import { Pattern } from "../patterns/Pattern";
4
3
  import { SuggestionOption } from "./SuggestionOption";
5
4
 
6
5
  export interface Suggestion {
7
6
  isComplete: boolean;
8
7
  options: SuggestionOption[];
9
- nextPatterns: Pattern[];
8
+ errorAtIndex: number | null;
10
9
  cursor: Cursor | null;
11
10
  ast: Node | null;
12
11
  }
@@ -2,6 +2,6 @@ import { Repeat } from "../../patterns/Repeat";
2
2
  import divider from "./divider";
3
3
  import values from "./values";
4
4
 
5
- const cssValue = new Repeat("css-value", values, divider);
5
+ const cssValue = new Repeat("css-value", values, { divider });
6
6
 
7
7
  export default cssValue;
@@ -9,7 +9,7 @@ import divider from "./divider";
9
9
  const openParen = new Literal("open-paren", "(");
10
10
  const closeParen = new Literal("close-paren", ")");
11
11
  const values = new Reference("values");
12
- const args = new Repeat("arguments", values, divider, true);
12
+ const args = new Repeat("arguments", values, { divider, min: 0 });
13
13
  const methodName = name.clone("method-name");
14
14
  methodName.setTokens(["rgba", "radial-gradient", "linear-gradient"]);
15
15
 
@@ -2,6 +2,6 @@ import { Repeat } from "../../patterns/Repeat";
2
2
  import value from "./value";
3
3
  import spaces from "./spaces";
4
4
 
5
- const values = new Repeat("values", value, spaces);
5
+ const values = new Repeat("values", value, { divider: spaces });
6
6
 
7
7
  export default values;
@@ -1,7 +1,8 @@
1
+ import { Cursor } from "../../patterns/Cursor";
1
2
  import { escapedCharacter } from "./escapedCharacter";
2
3
  import { exponent } from "./exponent";
3
4
  import { expression } from "./expression";
4
- import { expressionStatement } from "./expressionStatement";
5
+ import { assignment } from "./assignment";
5
6
  import { infixOperator } from "./infixOperator";
6
7
  import { integer } from "./integer";
7
8
  import { name } from "./name";
@@ -173,30 +174,52 @@ describe("Ecmascript 3", () => {
173
174
  expect(result.ast?.value).toBe(`{"prop":1}`);
174
175
  });
175
176
 
176
- test("Array Literal", () => {
177
+ test("Expression", () => {
178
+
177
179
  let result = expression.exec("[]")
178
180
  expect(result.ast?.value).toBe("[]");
179
181
 
180
182
  result = expression.exec("[{}, 9, 0.9e-10, [1, 2]]")
181
183
  expect(result.ast?.value).toBe("[{}, 9, 0.9e-10, [1, 2]]");
182
- });
184
+
185
+ result = expression.exec(`"John"`);
186
+ expect(result.ast?.value).toBe(`"John"`)
187
+
188
+ result = expression.exec(`variableName.property`);
189
+ expect(result.ast?.value).toBe(`variableName.property`);
190
+
191
+ result = expression.exec(`{property: ""}`);
192
+ expect(result.ast?.value).toBe(`{property: ""}`);
193
+
194
+ const cursor = new Cursor(`name() == name.property === name2 ? {prop: name, blah: [ 0.9e-10 ]} : name`);
195
+ cursor.startRecording();
196
+ const ast = expression.parse(cursor);
197
+ })
183
198
 
184
199
  test("Expression Statement", () => {
185
- let result = expressionStatement.exec(`name = "John"`);
200
+ let result = assignment.exec(`name = "John"`);
186
201
  expect(result.ast?.value).toBe(`name = "John"`);
187
202
 
188
- result = expressionStatement.exec(`name = othername = "John"`)
203
+ result = assignment.exec(`name = othername = "John"`)
189
204
  expect(result.ast?.value).toBe(`name = othername = "John"`);
190
205
 
191
- result = expressionStatement.exec(`name = othername.prop = "John"`)
206
+ result = assignment.exec(`name = othername.prop = "John"`)
192
207
  expect(result.ast?.value).toBe(`name = othername.prop = "John"`);
193
208
 
194
- result = expressionStatement.exec(`name = othername.prop += 2`)
209
+ result = assignment.exec(`name = othername.prop += 2`)
195
210
  expect(result.ast?.value).toBe(`name = othername.prop += 2`);
196
-
197
- result = expressionStatement.exec(`name.prop().method(blah) = blah.prop()`)
198
- expect(result.ast?.value).toBe(`name.prop().method(blah) = blah.prop()`);
199
-
211
+
212
+ result = assignment.exec(`name.prop().method(blah) = blah.prop() == ha ? first : second`)
213
+ expect(result.ast?.value).toBe(`name.prop().method(blah) = blah.prop() == ha ? first : second`);
214
+ });
215
+
216
+
217
+ test("Object Access", () => {
218
+ let result = expression.exec("name.prop");
219
+ expect(result.ast?.value).toBe(`name.prop`);
220
+
221
+ result = expression.exec(`name.prop.anotherProp["Ha"][coolYo] === 1`);
222
+ expect(result.ast?.value).toBe(`name.prop.anotherProp["Ha"][coolYo] === 1`);
200
223
  });
201
224
 
202
225
 
@@ -7,7 +7,7 @@ import { Repeat } from "../../patterns/Repeat";
7
7
  import { optionalSpaces } from "./optionalSpaces";
8
8
 
9
9
  const divider = new Regex("array-divider", "\\s*,\\s*");
10
- const arrayItems = new Repeat("array-items", new Reference("expression"), divider, true);
10
+ const arrayItems = new Repeat("array-items", new Reference("expression"), { divider, min: 0 });
11
11
 
12
12
  export const arrayLiteral = new Or("array-literal",
13
13
  [new And("empty-array-literal", [
@@ -1,7 +1,7 @@
1
1
  import { And } from "../../patterns/And";
2
2
  import { Literal } from "../../patterns/Literal";
3
3
  import { Or } from "../../patterns/Or";
4
- import { Repeat } from "../../patterns/Repeat";
4
+ import { Reference } from "../../patterns/Reference";
5
5
  import { expression } from "./expression";
6
6
  import { optionalSpaces } from "./optionalSpaces";
7
7
 
@@ -16,14 +16,13 @@ const assignment = new And("assignment", [
16
16
  optionalSpaces,
17
17
  assignmentOperators,
18
18
  optionalSpaces,
19
+ new Or("assignment-right-operand", [
20
+ new Reference("assignment"),
21
+ expression
22
+ ]),
19
23
  ]);
20
24
 
21
- const expressionStatement = new And("expressionStatement", [
22
- new Repeat("assignments",
23
- assignment),
24
- optionalSpaces,
25
- expression
26
- ]);
27
25
 
28
26
 
29
- export { expressionStatement }
27
+
28
+ export { assignment }
@@ -1,13 +1,15 @@
1
- import { Regex } from "../..";
2
1
  import { And } from "../../patterns/And";
3
2
  import { Literal } from "../../patterns/Literal";
4
3
  import { Or } from "../../patterns/Or";
5
4
  import { Reference } from "../../patterns/Reference";
5
+ import { Regex } from "../../patterns/Regex";
6
6
  import { Repeat } from "../../patterns/Repeat";
7
7
  import { infixOperator } from "./infixOperator";
8
8
  import { invocation } from "./invocation";
9
+ import { nullKeyword } from "./keywords";
9
10
  import { literal } from "./literal";
10
11
  import { name } from "./name";
12
+ import { objectAccess } from "./objectAccess";
11
13
  import { optionalSpaces } from "./optionalSpaces";
12
14
  import { prefixOperator } from "./prefixOperator";
13
15
  import { propertyAccess } from "./propertyAccess";
@@ -41,46 +43,62 @@ const prefixExpression = new And("prefix-expression", [
41
43
  new Reference("expression")
42
44
  ]);
43
45
 
44
- const optionalInfix = new And("infix-expression", [
45
- infixOperator,
46
- optionalSpaces,
47
- new Reference("expression"),
48
- ], true);
49
-
50
- const optionalTernary = new And("ternary", [
51
- new Literal("question-mark", "?"),
52
- optionalSpaces,
53
- new Reference("expression"),
54
- optionalSpaces,
55
- new Literal("colon", ":"),
56
- optionalSpaces,
57
- new Reference("expression")
58
- ], true);
59
-
60
- const optionalMemberAccesses = new Repeat("object-member-accesses",
61
- new Or("object-member-access", [
46
+ const memberAccess = new Repeat("member-access",
47
+ new Or("member-access", [
62
48
  invocation,
63
49
  propertyAccess,
64
- ]),
65
- undefined, true
50
+ ])
66
51
  );
67
52
 
53
+
68
54
  var variableName = name.clone("variable-name");
69
55
 
70
56
  const expressions = new Or("expressions", [
71
57
  newExpression,
72
58
  deleteExpression,
73
- groupExpression,
74
- prefixExpression,
75
59
  literal,
60
+ nullKeyword,
61
+ objectAccess,
76
62
  variableName,
63
+ groupExpression,
64
+ prefixExpression
77
65
  ]);
78
66
 
79
- const expression = new And("expression", [
67
+ const expressionBody = new And("expression-body", [
80
68
  expressions,
81
- optionalInfix,
82
- optionalTernary,
83
- optionalMemberAccesses
69
+ memberAccess.clone(undefined, true),
70
+ ]);
71
+
72
+ const infixExpression = new And("infix-expression", [
73
+ expressionBody,
74
+ optionalSpaces,
75
+ infixOperator,
76
+ optionalSpaces,
77
+ new Or("infix-right-operand", [
78
+ new Reference("infix-expression"),
79
+ expressionBody,
80
+ ])
81
+ ]);
82
+
83
+ const ternaryExpression = new And("ternary", [
84
+ new Or("ternary-condition", [
85
+ infixExpression,
86
+ expressionBody
87
+ ]),
88
+ optionalSpaces,
89
+ new Literal("question-mark", "?"),
90
+ optionalSpaces,
91
+ new Reference("expression"),
92
+ optionalSpaces,
93
+ new Literal("colon", ":"),
94
+ optionalSpaces,
95
+ new Reference("expression")
96
+ ]);
97
+
98
+ const expression = new Or("expression", [
99
+ ternaryExpression,
100
+ infixExpression,
101
+ expressionBody
84
102
  ]);
85
103
 
86
104
  export { expression }
@@ -10,8 +10,10 @@ const greaterOrEqual = new Literal("greater-or-equal", ">=");
10
10
  const lessOrEqual = new Literal("less-or-equal", "<=");
11
11
  const greater = new Literal("greater", ">");
12
12
  const less = new Literal("less", "<");
13
- const equal = new Literal("equal", "===");
14
- const notEqual = new Literal("not-equal", "!==");
13
+ const equal = new Literal("equal", "==");
14
+ const notEqual = new Literal("not-equal", "!=");
15
+ const strictEqual = new Literal("strict-equal", "===");
16
+ const strictNotEqual = new Literal("strict-not-equal", "!==");
15
17
  const logicalOr = new Literal("logical-or", "||");
16
18
  const logicalAnd = new Literal("logical-and", "&&");
17
19
 
@@ -25,6 +27,8 @@ const infixOperator = new Or("infix-operator", [
25
27
  lessOrEqual,
26
28
  greater,
27
29
  less,
30
+ strictEqual,
31
+ strictNotEqual,
28
32
  equal,
29
33
  notEqual,
30
34
  logicalOr,
@@ -11,7 +11,7 @@ const divider = new Regex("invocation-divider", "\\s*,\\s*");
11
11
  const invocationWithArguments = new And("invocation-with-arguments", [
12
12
  new Literal("open-paren", "("),
13
13
  optionalSpaces,
14
- new Repeat("expressions", new Reference("expression"), divider, true),
14
+ new Repeat("expressions", new Reference("expression"), { divider, min: 0 }),
15
15
  optionalSpaces,
16
16
  new Literal("close-paren", ")"),
17
17
  ]);
@@ -0,0 +1,3 @@
1
+ import { Literal } from "../../patterns/Literal";
2
+
3
+ export const nullKeyword = new Literal("null", "null");
@@ -0,0 +1,9 @@
1
+ import { And } from "../../patterns/And";
2
+ import { Reference } from "../../patterns/Reference";
3
+ import { name } from "./name";
4
+ import { propertyAccess } from "./propertyAccess";
5
+
6
+ export const objectAccess = new And("object-access", [
7
+ name.clone("variable-name"),
8
+ propertyAccess,
9
+ ]);
@@ -8,7 +8,7 @@ import { name } from "./name";
8
8
  import { optionalSpaces } from "./optionalSpaces";
9
9
  import { stringLiteral } from "./stringLiteral";
10
10
 
11
- const propertyName = new Or("property-name", [stringLiteral, name]);
11
+ const propertyName = new Or("property-name", [stringLiteral.clone("object-property"), name.clone("object-property")]);
12
12
  const property = new And("property", [
13
13
  propertyName,
14
14
  optionalSpaces,
@@ -17,12 +17,12 @@ const property = new And("property", [
17
17
  new Reference("expression"),
18
18
  ]);
19
19
  const divider = new Regex("property-divider", "\\s*,\\s*");
20
- const properties = new Repeat("properties", property, divider, true);
20
+ const optionalProperties = new Repeat("properties", property, { divider, min: 0 });
21
21
 
22
22
  const objectLiteral = new And("object-literal", [
23
23
  new Literal("open-curly-bracket", "{"),
24
24
  optionalSpaces,
25
- properties,
25
+ optionalProperties,
26
26
  optionalSpaces,
27
27
  new Literal("close-curly-bracket", "}"),
28
28
  ]);
@@ -12,7 +12,7 @@ const optionalSpace = new Regex("optional-space", "\\s", true)
12
12
  const parameters = new And("parameters", [
13
13
  new Literal("open-paren", "("),
14
14
  optionalSpace,
15
- new Repeat("arguments", name, divider),
15
+ new Repeat("arguments", name, { divider, trimDivider: true }),
16
16
  optionalSpace,
17
17
  new Literal("close-paren", ")"),
18
18
  ]);
@@ -6,7 +6,7 @@ import { name } from "./name";
6
6
 
7
7
  const dotPropertyAccess = new And("dot-property-access", [
8
8
  new Literal("period", "."),
9
- name
9
+ name.clone("property-name")
10
10
  ]);
11
11
 
12
12
  const bracketPropertyAccess = new And("bracket-property-access", [
@@ -15,9 +15,14 @@ const bracketPropertyAccess = new And("bracket-property-access", [
15
15
  new Literal("close-square-bracket", "]"),
16
16
  ]);
17
17
 
18
- const propertyAccess = new Or("property-access", [
18
+ const propertyAccessTypes = new Or("property-access-types", [
19
19
  dotPropertyAccess,
20
- bracketPropertyAccess,
20
+ bracketPropertyAccess
21
+ ]);
22
+
23
+ const propertyAccess = new And("property-access", [
24
+ propertyAccessTypes,
25
+ new Reference("property-access", true)
21
26
  ]);
22
27
 
23
28
  export { propertyAccess }
@@ -7,19 +7,25 @@ import { escapedCharacter } from "./escapedCharacter";
7
7
 
8
8
  const doubleQuoteStringLiteral = new And("double-string-literal", [
9
9
  new Literal("double-quote", "\""),
10
- new Repeat("characters", new Or("characters", [
11
- new Regex("normal-characters", "[^\\\"]+"),
12
- escapedCharacter
13
- ])),
10
+ new Repeat("characters",
11
+ new Or("characters", [
12
+ new Regex("normal-characters", "[^\\\"]+"),
13
+ escapedCharacter
14
+ ]),
15
+ { min: 0 }
16
+ ),
14
17
  new Literal("double-quote", "\""),
15
18
  ]);
16
19
 
17
20
  const singleQuoteStringLiteral = new And("single-string-literal", [
18
21
  new Literal("single-quote", "'"),
19
- new Repeat("characters", new Or("characters", [
20
- new Regex("normal-characters", "[^\\']+"),
21
- escapedCharacter
22
- ])),
22
+ new Repeat("characters",
23
+ new Or("characters", [
24
+ new Regex("normal-characters", "[^\\']+"),
25
+ escapedCharacter
26
+ ]),
27
+ { min: 0 }
28
+ ),
23
29
  new Literal("single-quote", "'"),
24
30
  ]);
25
31
 
@@ -276,7 +276,7 @@ describe("And", () => {
276
276
  const sequence = new And("sequence", [new Literal("a", "A")]);
277
277
  const parent = new And("parent", [sequence, new Literal("b", "B")]);
278
278
 
279
- const sequenceClone = parent.findPattern(p => p.name === "sequence");
279
+ const sequenceClone = parent.find(p => p.name === "sequence");
280
280
  const tokens = sequenceClone?.getNextTokens() || [];
281
281
 
282
282
  expect(tokens[0]).toBe("B");
@@ -289,13 +289,26 @@ describe("And", () => {
289
289
  expect(tokens.length).toBe(0);
290
290
  });
291
291
 
292
+ test("Get Patterns", () => {
293
+ const sequence = new And("sequence", [
294
+ new Literal("a", "A", true),
295
+ new Literal("b", "B"),
296
+ ], true);
297
+ const tokens = sequence.getPatterns();
298
+ const a = sequence.find(p=>p.name === "a");
299
+ const b = sequence.find(p=>p.name === "b");
300
+ const expected = [a, b]
301
+
302
+ expect(tokens).toEqual(expected);
303
+ });
304
+
292
305
  test("Get Next Patterns", () => {
293
306
  const sequence = new And("sequence", [new Literal("a", "A")]);
294
307
  const parent = new And("parent", [sequence, new Literal("b", "B")]);
295
308
 
296
- const sequenceClone = parent.findPattern(p => p.name === "sequence");
309
+ const sequenceClone = parent.find(p => p.name === "sequence");
297
310
  const nextPatterns = sequenceClone?.getNextPatterns() || [];
298
- const b = parent.findPattern(p => p.name === "b")
311
+ const b = parent.find(p => p.name === "b")
299
312
 
300
313
  expect(nextPatterns[0]).toBe(b);
301
314
  });