clarity-pattern-parser 6.0.2 → 7.0.1
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.
- package/TODO.md +1 -78
- package/dist/ast/Node.d.ts +1 -0
- package/dist/grammar/Grammar.d.ts +17 -0
- package/dist/grammar/patterns/andLiteral.d.ts +2 -0
- package/dist/grammar/patterns/comment.d.ts +2 -0
- package/dist/grammar/patterns/grammar.d.ts +2 -0
- package/dist/grammar/patterns/literal.d.ts +2 -0
- package/dist/grammar/patterns/name.d.ts +2 -0
- package/dist/grammar/patterns/orLiteral.d.ts +2 -0
- package/dist/grammar/patterns/pattern.d.ts +2 -0
- package/dist/grammar/patterns/regexLiteral.d.ts +2 -0
- package/dist/grammar/patterns/repeatLiteral.d.ts +3 -0
- package/dist/grammar/patterns/spaces.d.ts +2 -0
- package/dist/grammar/patterns/statement.d.ts +2 -0
- package/dist/index.browser.js +1161 -556
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.esm.js +1159 -555
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1159 -554
- package/dist/index.js.map +1 -1
- package/dist/intellisense/AutoComplete.d.ts +2 -6
- package/dist/patterns/And.d.ts +1 -1
- package/dist/patterns/Cursor.d.ts +1 -0
- package/dist/patterns/CursorHistory.d.ts +2 -1
- package/dist/patterns/FiniteRepeat.d.ts +39 -0
- package/dist/patterns/InfiniteRepeat.d.ts +47 -0
- package/dist/patterns/Literal.d.ts +1 -1
- package/dist/patterns/Not.d.ts +1 -1
- package/dist/patterns/Or.d.ts +1 -1
- package/dist/patterns/Pattern.d.ts +1 -1
- package/dist/patterns/Reference.d.ts +1 -1
- package/dist/patterns/Regex.d.ts +1 -1
- package/dist/patterns/Repeat.d.ts +18 -22
- package/jest.config.js +0 -1
- package/jest.coverage.config.js +13 -0
- package/package.json +3 -3
- package/src/ast/Node.test.ts +15 -0
- package/src/ast/Node.ts +12 -6
- package/src/grammar/Grammar.test.ts +306 -0
- package/src/grammar/Grammar.ts +249 -0
- package/src/grammar/patterns/andLiteral.ts +8 -0
- package/src/grammar/patterns/comment.ts +3 -0
- package/src/grammar/patterns/grammar.ts +19 -0
- package/src/grammar/patterns/literal.ts +5 -0
- package/src/grammar/patterns/name.ts +3 -0
- package/src/grammar/patterns/orLiteral.ts +8 -0
- package/src/grammar/patterns/pattern.ts +13 -0
- package/src/grammar/patterns/regexLiteral.ts +4 -0
- package/src/grammar/patterns/repeatLiteral.ts +72 -0
- package/src/grammar/patterns/spaces.ts +4 -0
- package/src/grammar/patterns/statement.ts +36 -0
- package/src/grammar/spec.md +142 -0
- package/src/index.ts +6 -3
- package/src/intellisense/AutoComplete.test.ts +21 -2
- package/src/intellisense/AutoComplete.ts +14 -25
- package/src/intellisense/Suggestion.ts +0 -1
- package/src/intellisense/css/cssValue.ts +1 -1
- package/src/intellisense/css/method.ts +1 -1
- package/src/intellisense/css/values.ts +1 -1
- package/src/intellisense/javascript/Javascript.test.ts +0 -1
- package/src/intellisense/javascript/arrayLiteral.ts +1 -1
- package/src/intellisense/javascript/expression.ts +1 -1
- package/src/intellisense/javascript/invocation.ts +1 -1
- package/src/intellisense/javascript/objectLiteral.ts +1 -1
- package/src/intellisense/javascript/parameters.ts +1 -1
- package/src/intellisense/javascript/stringLiteral.ts +2 -4
- package/src/patterns/And.test.ts +5 -5
- package/src/patterns/And.ts +11 -17
- package/src/patterns/Cursor.ts +4 -0
- package/src/patterns/CursorHistory.ts +34 -5
- package/src/patterns/FiniteRepeat.test.ts +481 -0
- package/src/patterns/FiniteRepeat.ts +231 -0
- package/src/patterns/InfiniteRepeat.test.ts +296 -0
- package/src/patterns/InfiniteRepeat.ts +329 -0
- package/src/patterns/Literal.test.ts +4 -4
- package/src/patterns/Literal.ts +1 -1
- package/src/patterns/Not.test.ts +11 -11
- package/src/patterns/Not.ts +1 -1
- package/src/patterns/Or.test.ts +9 -9
- package/src/patterns/Or.ts +1 -1
- package/src/patterns/Pattern.ts +1 -1
- package/src/patterns/Reference.test.ts +8 -8
- package/src/patterns/Reference.ts +1 -1
- package/src/patterns/Regex.test.ts +4 -4
- package/src/patterns/Regex.ts +1 -1
- package/src/patterns/Repeat.test.ts +160 -165
- package/src/patterns/Repeat.ts +95 -230
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { And } from "../../patterns/And";
|
|
2
|
+
import { Literal } from "../../patterns/Literal";
|
|
3
|
+
import { Or } from "../../patterns/Or";
|
|
4
|
+
import { Regex } from "../../patterns/Regex";
|
|
5
|
+
import { name } from "./name";
|
|
6
|
+
import { spaces } from "./spaces";
|
|
7
|
+
|
|
8
|
+
const optionalIsOptional = new Literal("is-optional", "?", true);
|
|
9
|
+
const patternName = name.clone("pattern-name");
|
|
10
|
+
|
|
11
|
+
export const pattern = new And("pattern", [
|
|
12
|
+
patternName,
|
|
13
|
+
optionalIsOptional,
|
|
14
|
+
]);
|
|
15
|
+
|
|
16
|
+
const optionalSpaces = spaces.clone("optional-spaces", true);
|
|
17
|
+
const dividerPattern = name.clone("divider-pattern");
|
|
18
|
+
|
|
19
|
+
const openBracket = new Literal("open-bracket", "{");
|
|
20
|
+
const closeBracket = new Literal("close-bracket", "}");
|
|
21
|
+
const comma = new Literal("comma", ",");
|
|
22
|
+
const integer = new Regex("integer", "([1-9][0-9]*)|0");
|
|
23
|
+
integer.setTokens(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]);
|
|
24
|
+
|
|
25
|
+
const optionalInteger = integer.clone("integer", true)
|
|
26
|
+
|
|
27
|
+
const bounds = new And("bounds", [
|
|
28
|
+
openBracket,
|
|
29
|
+
optionalSpaces,
|
|
30
|
+
optionalInteger.clone("min"),
|
|
31
|
+
optionalSpaces,
|
|
32
|
+
comma,
|
|
33
|
+
optionalSpaces,
|
|
34
|
+
optionalInteger.clone("max"),
|
|
35
|
+
optionalSpaces,
|
|
36
|
+
closeBracket
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
const exactCount = new And("exact-count", [
|
|
40
|
+
openBracket,
|
|
41
|
+
optionalSpaces,
|
|
42
|
+
integer,
|
|
43
|
+
optionalSpaces,
|
|
44
|
+
closeBracket,
|
|
45
|
+
]);
|
|
46
|
+
|
|
47
|
+
const quantifierShorthand = new Regex("quantifier-shorthand", "\\*|\\+");
|
|
48
|
+
quantifierShorthand.setTokens(["*", "+"]);
|
|
49
|
+
const quantifier = new Or("quantifier", [
|
|
50
|
+
quantifierShorthand,
|
|
51
|
+
exactCount,
|
|
52
|
+
bounds
|
|
53
|
+
]);
|
|
54
|
+
|
|
55
|
+
const optional = new Literal("is-optional", "?", true);
|
|
56
|
+
const trimDivider = new Literal("trim-divider", "-t");
|
|
57
|
+
const openParen = new Literal("open-paren", "(");
|
|
58
|
+
const closeParen = new Literal("close-paren", ")");
|
|
59
|
+
const dividerComma = new Regex("divider-comma", "\\s*,\\s*");
|
|
60
|
+
dividerComma.setTokens([", "]);
|
|
61
|
+
|
|
62
|
+
export const repeatLiteral = new And("repeat-literal", [
|
|
63
|
+
openParen,
|
|
64
|
+
optionalSpaces,
|
|
65
|
+
pattern,
|
|
66
|
+
optional,
|
|
67
|
+
new And("optional-divider-section", [dividerComma, dividerPattern], true),
|
|
68
|
+
optionalSpaces,
|
|
69
|
+
closeParen,
|
|
70
|
+
new And("quantifier-section", [optionalSpaces, quantifier]),
|
|
71
|
+
new And("optional-trim-divider-section", [spaces, trimDivider], true)
|
|
72
|
+
]);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { And } from "../../patterns/And";
|
|
2
|
+
import { Literal } from "../../patterns/Literal";
|
|
3
|
+
import { Or } from "../../patterns/Or";
|
|
4
|
+
import { andLiteral } from "./andLiteral";
|
|
5
|
+
import { name } from "./name";
|
|
6
|
+
import { orLiteral } from "./orLiteral";
|
|
7
|
+
import { regexLiteral } from "./regexLiteral";
|
|
8
|
+
import { repeatLiteral } from "./repeatLiteral";
|
|
9
|
+
import { spaces } from "./spaces";
|
|
10
|
+
import { literal } from "./literal";
|
|
11
|
+
import { comment } from "./comment";
|
|
12
|
+
|
|
13
|
+
const optionalSpaces = spaces.clone("optional-spaces", true);
|
|
14
|
+
const assignOperator = new Literal("assign-operator", "=");
|
|
15
|
+
const optionalComment = comment.clone("inline-comment", true);
|
|
16
|
+
|
|
17
|
+
const statements = new Or("statements", [
|
|
18
|
+
literal,
|
|
19
|
+
regexLiteral,
|
|
20
|
+
orLiteral,
|
|
21
|
+
andLiteral,
|
|
22
|
+
repeatLiteral,
|
|
23
|
+
name.clone("alias-literal"),
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
export const statement = new And("statement", [
|
|
27
|
+
optionalSpaces,
|
|
28
|
+
name,
|
|
29
|
+
optionalSpaces,
|
|
30
|
+
assignOperator,
|
|
31
|
+
optionalSpaces,
|
|
32
|
+
statements,
|
|
33
|
+
optionalSpaces,
|
|
34
|
+
optionalComment,
|
|
35
|
+
optionalSpaces,
|
|
36
|
+
]);
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Grammar
|
|
2
|
+
|
|
3
|
+
## Literal
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
name = "Literal"
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Regex
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
digits = /\d+/
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Regex Caveats
|
|
16
|
+
|
|
17
|
+
Do not use "^" at the beginning or "$" at the end of your regular expression. If
|
|
18
|
+
you are creating a regular expression that is concerned about the beginning and
|
|
19
|
+
end of the text you should probably just use a regular expression.
|
|
20
|
+
|
|
21
|
+
## Or
|
|
22
|
+
This succeeds if it matches any of the options.
|
|
23
|
+
```
|
|
24
|
+
multiply = "*"
|
|
25
|
+
divide = "/"
|
|
26
|
+
operators = mulitply | divide
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## And
|
|
30
|
+
This succeeds if it matches all of the patterns in the order they are placed.
|
|
31
|
+
```
|
|
32
|
+
space = " "
|
|
33
|
+
first-name = "John"
|
|
34
|
+
last-name = "Doe"
|
|
35
|
+
full-name = first-name & space & last-name
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Optional pattern
|
|
39
|
+
Patterns within the and sequence can be optional.
|
|
40
|
+
```
|
|
41
|
+
space = " "
|
|
42
|
+
first-name = /\w+/
|
|
43
|
+
last-name = /\w+/
|
|
44
|
+
middle-name = /\w+/
|
|
45
|
+
middle-name-with-space = middle-name & space
|
|
46
|
+
|
|
47
|
+
full-name = first-name & space & middle-name-with-space? & last-name
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Negative Look Ahead
|
|
51
|
+
This will ensure that the first name isn't `Jack` before continuing to match for
|
|
52
|
+
a name.
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
space = " "
|
|
56
|
+
first-name = /\w+/
|
|
57
|
+
last-name = /\w+/
|
|
58
|
+
middle-name = /\w+/
|
|
59
|
+
middle-name-with-space = m-middle-name & space
|
|
60
|
+
jack = "Jack"
|
|
61
|
+
|
|
62
|
+
full-name = !jack & first-name & space & middle-name-with-space? & last-name
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Repeat
|
|
66
|
+
```
|
|
67
|
+
digit = /\d/
|
|
68
|
+
digits = (digit)*
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Zero Or More Pattern
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
digit = /\d/
|
|
75
|
+
comma = ","
|
|
76
|
+
digits = (digit, comma)*
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Zero Or More & Trim Trailing Divider
|
|
80
|
+
```
|
|
81
|
+
digit = /\d/
|
|
82
|
+
comma = ","
|
|
83
|
+
digits = (digit, comma)* -t
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
This is a useful feature if you don't want the divider to be the last pattern found. Let's look at the example below to understand.
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
const expression = `
|
|
90
|
+
digit = /\d/
|
|
91
|
+
comma = ","
|
|
92
|
+
digits = (digit, comma)* -t
|
|
93
|
+
`;
|
|
94
|
+
|
|
95
|
+
const { digits } = Gammar.parse(expression);
|
|
96
|
+
|
|
97
|
+
let result = digits.exec("1,2,3");
|
|
98
|
+
expect(result.ast?.value).toBe("1,2,3");
|
|
99
|
+
|
|
100
|
+
result = digits.exec("1,2,");
|
|
101
|
+
expect(result.ast).toBeNull();
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Zero Or More With Optional Repeated Pattern
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
digit = /\d/
|
|
108
|
+
comma = ","
|
|
109
|
+
digits = (digit?, comma)*
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### One Or More With Optional Repeated Pattern
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
digit = /\d/
|
|
116
|
+
comma = ","
|
|
117
|
+
digits = (digit?, comma)+
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Upper Limit
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
digit = /\d/
|
|
124
|
+
comma = ","
|
|
125
|
+
digits = (digit, comma){,3}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Bounded
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
digit = /\d/
|
|
132
|
+
comma = ","
|
|
133
|
+
digits = (digit, comma){1,3}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Lower Limit
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
digit = /\d/
|
|
140
|
+
comma = ","
|
|
141
|
+
digits = (digit, comma){1,3}
|
|
142
|
+
```
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { Node } from "./ast/Node";
|
|
2
|
+
import { Grammar } from "./grammar/Grammar";
|
|
3
|
+
import { Suggestion } from "./intellisense/Suggestion";
|
|
4
|
+
import { SuggestionOption } from "./intellisense/SuggestionOption";
|
|
5
|
+
import { AutoComplete, AutoCompleteOptions } from './intellisense/AutoComplete';
|
|
2
6
|
import { Cursor } from "./patterns/Cursor";
|
|
3
7
|
import { Regex } from "./patterns/Regex";
|
|
4
8
|
import { And } from "./patterns/And";
|
|
@@ -9,15 +13,14 @@ import { Repeat } from "./patterns/Repeat";
|
|
|
9
13
|
import { ParseError } from "./patterns/ParseError";
|
|
10
14
|
import { Pattern } from "./patterns/Pattern";
|
|
11
15
|
import { Reference } from "./patterns/Reference";
|
|
12
|
-
import { AutoComplete } from './intellisense/AutoComplete';
|
|
13
16
|
import { CursorHistory, Match } from "./patterns/CursorHistory";
|
|
14
17
|
import { ParseResult } from "./patterns/ParseResult";
|
|
15
|
-
import { Suggestion } from "./intellisense/Suggestion";
|
|
16
|
-
import { SuggestionOption } from "./intellisense/SuggestionOption";
|
|
17
18
|
|
|
18
19
|
export {
|
|
19
20
|
Node,
|
|
21
|
+
Grammar,
|
|
20
22
|
AutoComplete,
|
|
23
|
+
AutoCompleteOptions,
|
|
21
24
|
Suggestion,
|
|
22
25
|
SuggestionOption,
|
|
23
26
|
And,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { And } from "../patterns/And";
|
|
2
|
-
import { findPattern } from "../patterns/findPattern";
|
|
3
2
|
import { Literal } from "../patterns/Literal";
|
|
4
3
|
import { Or } from "../patterns/Or";
|
|
5
4
|
import { Regex } from "../patterns/Regex";
|
|
@@ -71,7 +70,7 @@ describe("AutoComplete", () => {
|
|
|
71
70
|
divider.setTokens([", "])
|
|
72
71
|
|
|
73
72
|
const text = "John Doe";
|
|
74
|
-
const autoComplete = new AutoComplete(new Repeat("last-names", name, divider));
|
|
73
|
+
const autoComplete = new AutoComplete(new Repeat("last-names", name, { divider }));
|
|
75
74
|
const result = autoComplete.suggestFor(text);
|
|
76
75
|
const expectedOptions = [{
|
|
77
76
|
text: ", ",
|
|
@@ -88,6 +87,7 @@ describe("AutoComplete", () => {
|
|
|
88
87
|
test("Partial", () => {
|
|
89
88
|
const name = new Literal("name", "Name");
|
|
90
89
|
const autoComplete = new AutoComplete(name);
|
|
90
|
+
// Use deprecated suggest for code coverage.
|
|
91
91
|
const result = autoComplete.suggestFor("Na");
|
|
92
92
|
const expectedOptions = [{
|
|
93
93
|
text: "me",
|
|
@@ -214,4 +214,23 @@ describe("AutoComplete", () => {
|
|
|
214
214
|
|
|
215
215
|
});
|
|
216
216
|
|
|
217
|
+
test("Match On Different Pattern Roots", () => {
|
|
218
|
+
const start = new Literal("start", "John went to");
|
|
219
|
+
const a = new Literal("a", "a bank.");
|
|
220
|
+
const the = new Literal("the", "the store.");
|
|
221
|
+
|
|
222
|
+
const first = new And("first", [start, a]);
|
|
223
|
+
const second = new And("second", [start, the]);
|
|
224
|
+
|
|
225
|
+
const both = new Or("both", [first, second]);
|
|
226
|
+
|
|
227
|
+
const autoComplete = new AutoComplete(both);
|
|
228
|
+
const result = autoComplete.suggestFor("John went to a gas station.");
|
|
229
|
+
const expected = [
|
|
230
|
+
{ text: "the store.", startIndex: 12 },
|
|
231
|
+
{ text: "a bank.", startIndex: 12 }
|
|
232
|
+
];
|
|
233
|
+
expect(result.options).toEqual(expected);
|
|
234
|
+
});
|
|
235
|
+
|
|
217
236
|
});
|
|
@@ -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";
|
|
@@ -31,14 +32,6 @@ export class AutoComplete {
|
|
|
31
32
|
this._text = "";
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
/**
|
|
35
|
-
* @deprecated Use suggestFor instead.
|
|
36
|
-
* @param text The text to suggest for.
|
|
37
|
-
*/
|
|
38
|
-
suggest(text: string): Suggestion {
|
|
39
|
-
return this.suggestFor(text);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
35
|
suggestFor(text: string): Suggestion {
|
|
43
36
|
if (text.length === 0) {
|
|
44
37
|
return {
|
|
@@ -52,18 +45,12 @@ export class AutoComplete {
|
|
|
52
45
|
|
|
53
46
|
this._text = text;
|
|
54
47
|
this._cursor = new Cursor(text);
|
|
55
|
-
const ast = this._pattern.parse(this._cursor);
|
|
56
|
-
|
|
57
|
-
const leafPattern = this._cursor.leafMatch.pattern;
|
|
58
|
-
const isComplete = ast?.value === text;
|
|
59
|
-
const options = this._createSuggestionsFromTokens();
|
|
60
48
|
|
|
61
|
-
let nextPatterns = [this._pattern];
|
|
62
49
|
let errorAtIndex = null;
|
|
63
50
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
51
|
+
const ast = this._pattern.parse(this._cursor);
|
|
52
|
+
const isComplete = ast?.value === text;
|
|
53
|
+
const options = this._getAllOptions();
|
|
67
54
|
|
|
68
55
|
if (this._cursor.hasError && this._cursor.furthestError != null) {
|
|
69
56
|
errorAtIndex = this._cursor.furthestError.index;
|
|
@@ -82,6 +69,10 @@ export class AutoComplete {
|
|
|
82
69
|
}
|
|
83
70
|
}
|
|
84
71
|
|
|
72
|
+
private _getAllOptions() {
|
|
73
|
+
return this._cursor.leafMatches.map((m) => this._createSuggestionsFromMatch(m)).flat();
|
|
74
|
+
}
|
|
75
|
+
|
|
85
76
|
private _createSuggestionsFromRoot(): SuggestionOption[] {
|
|
86
77
|
const suggestions: SuggestionOption[] = [];
|
|
87
78
|
const tokens = this._pattern.getTokens();
|
|
@@ -93,17 +84,15 @@ export class AutoComplete {
|
|
|
93
84
|
return suggestions;
|
|
94
85
|
}
|
|
95
86
|
|
|
96
|
-
private
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if (!leafMatch.pattern) {
|
|
87
|
+
private _createSuggestionsFromMatch(match: Match): SuggestionOption[] {
|
|
88
|
+
if (!match.pattern) {
|
|
100
89
|
return this._createSuggestions(-1, this._getTokensForPattern(this._pattern));
|
|
101
90
|
}
|
|
102
91
|
|
|
103
|
-
const leafPattern =
|
|
104
|
-
const parent =
|
|
92
|
+
const leafPattern = match.pattern;
|
|
93
|
+
const parent = match.pattern.parent;
|
|
105
94
|
|
|
106
|
-
if (parent !== null &&
|
|
95
|
+
if (parent !== null && match.node != null) {
|
|
107
96
|
const patterns = leafPattern.getNextPatterns();
|
|
108
97
|
|
|
109
98
|
const tokens = patterns.reduce((acc: string[], pattern) => {
|
|
@@ -111,7 +100,7 @@ export class AutoComplete {
|
|
|
111
100
|
return acc;
|
|
112
101
|
}, []);
|
|
113
102
|
|
|
114
|
-
return this._createSuggestions(
|
|
103
|
+
return this._createSuggestions(match.node.lastIndex, tokens);
|
|
115
104
|
} else {
|
|
116
105
|
return [];
|
|
117
106
|
}
|
|
@@ -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,
|
|
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
|
|
|
@@ -8,7 +8,6 @@ import { integer } from "./integer";
|
|
|
8
8
|
import { name } from "./name";
|
|
9
9
|
import { parameters } from "./parameters";
|
|
10
10
|
import { prefixOperator } from "./prefixOperator";
|
|
11
|
-
import { objectAccess } from "./objectAccess";
|
|
12
11
|
|
|
13
12
|
describe("Ecmascript 3", () => {
|
|
14
13
|
test("Escaped Character", () => {
|
|
@@ -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,
|
|
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,8 +1,8 @@
|
|
|
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";
|
|
@@ -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,
|
|
14
|
+
new Repeat("expressions", new Reference("expression"), { divider, min: 0 }),
|
|
15
15
|
optionalSpaces,
|
|
16
16
|
new Literal("close-paren", ")"),
|
|
17
17
|
]);
|
|
@@ -17,7 +17,7 @@ const property = new And("property", [
|
|
|
17
17
|
new Reference("expression"),
|
|
18
18
|
]);
|
|
19
19
|
const divider = new Regex("property-divider", "\\s*,\\s*");
|
|
20
|
-
const optionalProperties = new Repeat("properties", property, divider,
|
|
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", "{"),
|
|
@@ -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
|
]);
|
|
@@ -12,8 +12,7 @@ const doubleQuoteStringLiteral = new And("double-string-literal", [
|
|
|
12
12
|
new Regex("normal-characters", "[^\\\"]+"),
|
|
13
13
|
escapedCharacter
|
|
14
14
|
]),
|
|
15
|
-
|
|
16
|
-
true
|
|
15
|
+
{ min: 0 }
|
|
17
16
|
),
|
|
18
17
|
new Literal("double-quote", "\""),
|
|
19
18
|
]);
|
|
@@ -25,8 +24,7 @@ const singleQuoteStringLiteral = new And("single-string-literal", [
|
|
|
25
24
|
new Regex("normal-characters", "[^\\']+"),
|
|
26
25
|
escapedCharacter
|
|
27
26
|
]),
|
|
28
|
-
|
|
29
|
-
true
|
|
27
|
+
{ min: 0 }
|
|
30
28
|
),
|
|
31
29
|
new Literal("single-quote", "'"),
|
|
32
30
|
]);
|
package/src/patterns/And.test.ts
CHANGED
|
@@ -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.
|
|
279
|
+
const sequenceClone = parent.find(p => p.name === "sequence");
|
|
280
280
|
const tokens = sequenceClone?.getNextTokens() || [];
|
|
281
281
|
|
|
282
282
|
expect(tokens[0]).toBe("B");
|
|
@@ -295,8 +295,8 @@ describe("And", () => {
|
|
|
295
295
|
new Literal("b", "B"),
|
|
296
296
|
], true);
|
|
297
297
|
const tokens = sequence.getPatterns();
|
|
298
|
-
const a = sequence.
|
|
299
|
-
const b = sequence.
|
|
298
|
+
const a = sequence.find(p=>p.name === "a");
|
|
299
|
+
const b = sequence.find(p=>p.name === "b");
|
|
300
300
|
const expected = [a, b]
|
|
301
301
|
|
|
302
302
|
expect(tokens).toEqual(expected);
|
|
@@ -306,9 +306,9 @@ describe("And", () => {
|
|
|
306
306
|
const sequence = new And("sequence", [new Literal("a", "A")]);
|
|
307
307
|
const parent = new And("parent", [sequence, new Literal("b", "B")]);
|
|
308
308
|
|
|
309
|
-
const sequenceClone = parent.
|
|
309
|
+
const sequenceClone = parent.find(p => p.name === "sequence");
|
|
310
310
|
const nextPatterns = sequenceClone?.getNextPatterns() || [];
|
|
311
|
-
const b = parent.
|
|
311
|
+
const b = parent.find(p => p.name === "b")
|
|
312
312
|
|
|
313
313
|
expect(nextPatterns[0]).toBe(b);
|
|
314
314
|
});
|
package/src/patterns/And.ts
CHANGED
|
@@ -249,10 +249,10 @@ export class And implements Pattern {
|
|
|
249
249
|
}
|
|
250
250
|
|
|
251
251
|
getPatternsAfter(childReference: Pattern): Pattern[] {
|
|
252
|
+
const patterns: Pattern[] = [];
|
|
252
253
|
let nextSibling: Pattern | null = null;
|
|
253
254
|
let nextSiblingIndex = -1;
|
|
254
255
|
let index = -1;
|
|
255
|
-
const patterns: Pattern[] = [];
|
|
256
256
|
|
|
257
257
|
for (let i = 0; i < this._children.length; i++) {
|
|
258
258
|
if (this._children[i] === childReference) {
|
|
@@ -275,24 +275,18 @@ export class And implements Pattern {
|
|
|
275
275
|
return this._parent.getPatternsAfter(this);
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
-
// Next pattern isn't optional so send it back as the next patterns.
|
|
279
|
-
if (nextSibling !== null && !nextSibling.isOptional) {
|
|
280
|
-
return [nextSibling];
|
|
281
|
-
}
|
|
282
|
-
|
|
283
278
|
// Send back as many optional patterns as possible.
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
patterns.push(child);
|
|
279
|
+
for (let i = nextSiblingIndex; i < this._children.length; i++) {
|
|
280
|
+
const child = this._children[i];
|
|
281
|
+
patterns.push(child);
|
|
288
282
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
283
|
+
if (!child.isOptional) {
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
292
286
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
287
|
+
// If we are on the last child and its options then ask for the next pattern from the parent.
|
|
288
|
+
if (i === this._children.length - 1 && this._parent !== null) {
|
|
289
|
+
patterns.push(...this._parent.getPatternsAfter(this));
|
|
296
290
|
}
|
|
297
291
|
}
|
|
298
292
|
|
|
@@ -307,7 +301,7 @@ export class And implements Pattern {
|
|
|
307
301
|
return this.parent.getPatternsAfter(this)
|
|
308
302
|
}
|
|
309
303
|
|
|
310
|
-
|
|
304
|
+
find(predicate: (p: Pattern) => boolean): Pattern | null {
|
|
311
305
|
return findPattern(this, predicate);
|
|
312
306
|
}
|
|
313
307
|
|
package/src/patterns/Cursor.ts
CHANGED