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.
- package/TODO.md +1 -76
- 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 +1205 -550
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.esm.js +1203 -549
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1203 -548
- package/dist/index.js.map +1 -1
- package/dist/intellisense/AutoComplete.d.ts +9 -7
- package/dist/intellisense/Suggestion.d.ts +1 -2
- package/dist/patterns/And.d.ts +2 -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 +2 -1
- package/dist/patterns/Not.d.ts +2 -1
- package/dist/patterns/Or.d.ts +2 -1
- package/dist/patterns/Pattern.d.ts +3 -2
- package/dist/patterns/Reference.d.ts +2 -1
- package/dist/patterns/Regex.d.ts +2 -1
- package/dist/patterns/Repeat.d.ts +19 -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 +21 -0
- package/src/ast/Node.ts +12 -6
- package/src/grammar/Grammar.test.ts +288 -0
- package/src/grammar/Grammar.ts +234 -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 +35 -0
- package/src/grammar/spec.md +142 -0
- package/src/index.ts +6 -3
- package/src/intellisense/AutoComplete.test.ts +125 -39
- package/src/intellisense/AutoComplete.ts +52 -36
- package/src/intellisense/Suggestion.ts +1 -2
- 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 +34 -11
- package/src/intellisense/javascript/arrayLiteral.ts +1 -1
- package/src/intellisense/javascript/{expressionStatement.ts → assignment.ts} +7 -8
- package/src/intellisense/javascript/expression.ts +45 -27
- package/src/intellisense/javascript/infixOperator.ts +6 -2
- package/src/intellisense/javascript/invocation.ts +1 -1
- package/src/intellisense/javascript/keywords.ts +3 -0
- package/src/intellisense/javascript/objectAccess.ts +9 -0
- package/src/intellisense/javascript/objectLiteral.ts +3 -3
- package/src/intellisense/javascript/parameters.ts +1 -1
- package/src/intellisense/javascript/propertyAccess.ts +8 -3
- package/src/intellisense/javascript/stringLiteral.ts +14 -8
- package/src/patterns/And.test.ts +16 -3
- package/src/patterns/And.ts +25 -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 +13 -4
- package/src/patterns/Literal.ts +5 -1
- package/src/patterns/Not.test.ts +20 -9
- package/src/patterns/Not.ts +5 -1
- package/src/patterns/Or.test.ts +18 -7
- package/src/patterns/Or.ts +11 -1
- package/src/patterns/Pattern.ts +3 -2
- package/src/patterns/Reference.test.ts +18 -8
- package/src/patterns/Reference.ts +5 -1
- package/src/patterns/Regex.test.ts +13 -4
- package/src/patterns/Regex.ts +5 -1
- package/src/patterns/Repeat.test.ts +162 -158
- package/src/patterns/Repeat.ts +95 -226
|
@@ -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,35 @@
|
|
|
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
|
+
]);
|
|
24
|
+
|
|
25
|
+
export const statement = new And("statement", [
|
|
26
|
+
optionalSpaces,
|
|
27
|
+
name,
|
|
28
|
+
optionalSpaces,
|
|
29
|
+
assignOperator,
|
|
30
|
+
optionalSpaces,
|
|
31
|
+
statements,
|
|
32
|
+
optionalSpaces,
|
|
33
|
+
optionalComment,
|
|
34
|
+
optionalSpaces,
|
|
35
|
+
]);
|
|
@@ -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";
|
|
@@ -10,11 +9,11 @@ describe("AutoComplete", () => {
|
|
|
10
9
|
test("No Text", () => {
|
|
11
10
|
const name = new Literal("name", "Name");
|
|
12
11
|
const autoComplete = new AutoComplete(name);
|
|
13
|
-
let result = autoComplete.
|
|
12
|
+
let result = autoComplete.suggestFor("");
|
|
14
13
|
|
|
15
14
|
expect(result.options[0].text).toBe("Name");
|
|
16
15
|
expect(result.options[0].startIndex).toBe(0);
|
|
17
|
-
expect(result.
|
|
16
|
+
expect(result.errorAtIndex).toBe(0);
|
|
18
17
|
expect(result.isComplete).toBeFalsy();
|
|
19
18
|
});
|
|
20
19
|
|
|
@@ -26,11 +25,11 @@ describe("AutoComplete", () => {
|
|
|
26
25
|
const name = new And("name", [john, space, new Or("last-name", [smith, doe])]);
|
|
27
26
|
|
|
28
27
|
const autoComplete = new AutoComplete(name);
|
|
29
|
-
const result = autoComplete.
|
|
28
|
+
const result = autoComplete.suggestFor("John Doe");
|
|
30
29
|
|
|
31
30
|
expect(result.ast?.value).toBe("John Doe");
|
|
32
31
|
expect(result.options.length).toBe(0);
|
|
33
|
-
expect(result.
|
|
32
|
+
expect(result.errorAtIndex).toBeNull();
|
|
34
33
|
expect(result.isComplete).toBeTruthy();
|
|
35
34
|
expect(result.cursor).not.toBeNull();
|
|
36
35
|
});
|
|
@@ -42,14 +41,20 @@ describe("AutoComplete", () => {
|
|
|
42
41
|
const smith = new Literal("smith", "Smith");
|
|
43
42
|
const name = new And("name", [john, space, new Or("last-name", [smith, doe])]);
|
|
44
43
|
|
|
44
|
+
const text = "John "
|
|
45
45
|
const autoComplete = new AutoComplete(name);
|
|
46
|
-
const result = autoComplete.
|
|
46
|
+
const result = autoComplete.suggestFor(text);
|
|
47
|
+
const expectedOptions = [{
|
|
48
|
+
text: "Doe",
|
|
49
|
+
startIndex: 5
|
|
50
|
+
}, {
|
|
51
|
+
text: "Smith",
|
|
52
|
+
startIndex: 5
|
|
53
|
+
}];
|
|
47
54
|
|
|
48
55
|
expect(result.ast).toBeNull();
|
|
49
|
-
expect(result.options
|
|
50
|
-
expect(result.
|
|
51
|
-
expect(result.nextPatterns[0].type).toBe("or");
|
|
52
|
-
expect(result.nextPatterns[0].name).toBe("last-name");
|
|
56
|
+
expect(result.options).toEqual(expectedOptions);
|
|
57
|
+
expect(result.errorAtIndex).toBe(text.length)
|
|
53
58
|
expect(result.isComplete).toBeFalsy();
|
|
54
59
|
expect(result.cursor).not.toBeNull();
|
|
55
60
|
});
|
|
@@ -64,12 +69,17 @@ describe("AutoComplete", () => {
|
|
|
64
69
|
|
|
65
70
|
divider.setTokens([", "])
|
|
66
71
|
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
const text = "John Doe";
|
|
73
|
+
const autoComplete = new AutoComplete(new Repeat("last-names", name, { divider }));
|
|
74
|
+
const result = autoComplete.suggestFor(text);
|
|
75
|
+
const expectedOptions = [{
|
|
76
|
+
text: ", ",
|
|
77
|
+
startIndex: 8
|
|
78
|
+
}];
|
|
79
|
+
|
|
80
|
+
expect(result.ast?.value).toBe(text);
|
|
81
|
+
expect(result.options).toEqual(expectedOptions);
|
|
82
|
+
expect(result.errorAtIndex).toBeNull()
|
|
73
83
|
expect(result.isComplete).toBeTruthy();
|
|
74
84
|
expect(result.cursor).not.toBeNull();
|
|
75
85
|
});
|
|
@@ -77,36 +87,51 @@ describe("AutoComplete", () => {
|
|
|
77
87
|
test("Partial", () => {
|
|
78
88
|
const name = new Literal("name", "Name");
|
|
79
89
|
const autoComplete = new AutoComplete(name);
|
|
80
|
-
|
|
90
|
+
// Use deprecated suggest for code coverage.
|
|
91
|
+
const result = autoComplete.suggestFor("Na");
|
|
92
|
+
const expectedOptions = [{
|
|
93
|
+
text: "me",
|
|
94
|
+
startIndex: 2
|
|
95
|
+
}];
|
|
81
96
|
|
|
82
|
-
expect(result.
|
|
83
|
-
expect(result.options
|
|
84
|
-
expect(result.
|
|
97
|
+
expect(result.ast).toBeNull();
|
|
98
|
+
expect(result.options).toEqual(expectedOptions);
|
|
99
|
+
expect(result.errorAtIndex).toBe(2);
|
|
85
100
|
expect(result.isComplete).toBeFalsy();
|
|
101
|
+
expect(result.cursor).not.toBeNull();
|
|
86
102
|
});
|
|
87
103
|
|
|
88
104
|
test("Partial Match With Bad Characters", () => {
|
|
89
105
|
const name = new Literal("name", "Name");
|
|
90
106
|
const autoComplete = new AutoComplete(name);
|
|
91
|
-
|
|
107
|
+
const result = autoComplete.suggestFor("Ni");
|
|
108
|
+
|
|
109
|
+
const expectedOptions = [{
|
|
110
|
+
text: "ame",
|
|
111
|
+
startIndex: 1
|
|
112
|
+
}];
|
|
92
113
|
|
|
93
|
-
expect(result.
|
|
94
|
-
expect(result.options
|
|
95
|
-
|
|
114
|
+
expect(result.ast).toBeNull();
|
|
115
|
+
expect(result.options).toEqual(expectedOptions);
|
|
116
|
+
expect(result.errorAtIndex).toBe(1);
|
|
96
117
|
expect(result.isComplete).toBeFalsy();
|
|
118
|
+
expect(result.cursor).not.toBeNull();
|
|
97
119
|
});
|
|
98
120
|
|
|
99
121
|
test("Complete", () => {
|
|
100
122
|
const name = new Literal("name", "Name");
|
|
101
123
|
const autoComplete = new AutoComplete(name);
|
|
102
|
-
|
|
124
|
+
const text = "Name"
|
|
125
|
+
const result = autoComplete.suggestFor(text);
|
|
103
126
|
|
|
104
|
-
expect(result.
|
|
105
|
-
expect(result.
|
|
127
|
+
expect(result.ast?.value).toBe(text);
|
|
128
|
+
expect(result.options).toEqual([]);
|
|
129
|
+
expect(result.errorAtIndex).toBeNull();
|
|
106
130
|
expect(result.isComplete).toBeTruthy();
|
|
131
|
+
expect(result.cursor).not.toBeNull();
|
|
107
132
|
});
|
|
108
133
|
|
|
109
|
-
test("Options", ()=>{
|
|
134
|
+
test("Options AutoComplete on Composing Pattern", () => {
|
|
110
135
|
const autoCompleteOptions: AutoCompleteOptions = {
|
|
111
136
|
greedyPatternNames: ["space"],
|
|
112
137
|
customTokens: {
|
|
@@ -123,28 +148,89 @@ describe("AutoComplete", () => {
|
|
|
123
148
|
const lastName = new Or("last-name", [doe, smith]);
|
|
124
149
|
const fullName = new And("full-name", [firstName, space, lastName]);
|
|
125
150
|
|
|
126
|
-
const text = "
|
|
151
|
+
const text = "Jack";
|
|
127
152
|
const autoComplete = new AutoComplete(fullName, autoCompleteOptions);
|
|
128
|
-
const { options, ast,
|
|
153
|
+
const { options, ast, errorAtIndex } = autoComplete.suggestFor(text);
|
|
154
|
+
|
|
129
155
|
const expectedOptions = [
|
|
130
|
-
{text: " Doe", startIndex: 4},
|
|
131
|
-
{text: " Smith", startIndex: 4},
|
|
132
|
-
{text: " Sparrow", startIndex: 4},
|
|
156
|
+
{ text: " Doe", startIndex: 4 },
|
|
157
|
+
{ text: " Smith", startIndex: 4 },
|
|
158
|
+
{ text: " Sparrow", startIndex: 4 },
|
|
133
159
|
];
|
|
134
160
|
|
|
135
|
-
const results = expectedOptions.map(o=>text.slice(0, o.startIndex) + o.text);
|
|
161
|
+
const results = expectedOptions.map(o => text.slice(0, o.startIndex) + o.text);
|
|
136
162
|
const expectedResults = [
|
|
137
|
-
"
|
|
138
|
-
"
|
|
139
|
-
"
|
|
163
|
+
"Jack Doe",
|
|
164
|
+
"Jack Smith",
|
|
165
|
+
"Jack Sparrow",
|
|
140
166
|
]
|
|
141
167
|
|
|
168
|
+
expect(ast).toBeNull();
|
|
169
|
+
expect(errorAtIndex).toBe(4);
|
|
142
170
|
expect(options).toEqual(expectedOptions);
|
|
171
|
+
expect(results).toEqual(expectedResults);
|
|
172
|
+
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test("Options AutoComplete On Leaf Pattern", () => {
|
|
176
|
+
const autoCompleteOptions: AutoCompleteOptions = {
|
|
177
|
+
greedyPatternNames: ["space"],
|
|
178
|
+
customTokens: {
|
|
179
|
+
"space": [" "]
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const jack = new Literal("jack", "Jack");
|
|
184
|
+
const john = new Literal("john", "John");
|
|
185
|
+
const space = new Literal("space", " ");
|
|
186
|
+
const doe = new Literal("doe", "Doe");
|
|
187
|
+
const smith = new Literal("smith", "Smith");
|
|
188
|
+
const firstName = new Or("first-name", [jack, john]);
|
|
189
|
+
const lastName = new Or("last-name", [doe, smith]);
|
|
190
|
+
const fullName = new And("full-name", [firstName, space, lastName]);
|
|
191
|
+
|
|
192
|
+
const text = "Jack";
|
|
193
|
+
const autoComplete = new AutoComplete(fullName, autoCompleteOptions);
|
|
194
|
+
const { options, ast, errorAtIndex } = autoComplete.suggestFor(text);
|
|
195
|
+
const expectedOptions = [
|
|
196
|
+
{ text: " Doe", startIndex: 4 },
|
|
197
|
+
{ text: " Smith", startIndex: 4 },
|
|
198
|
+
{ text: " Doe", startIndex: 4 },
|
|
199
|
+
{ text: " Smith", startIndex: 4 },
|
|
200
|
+
];
|
|
201
|
+
|
|
202
|
+
const results = expectedOptions.map(o => text.slice(0, o.startIndex) + o.text);
|
|
203
|
+
const expectedResults = [
|
|
204
|
+
"Jack Doe",
|
|
205
|
+
"Jack Smith",
|
|
206
|
+
"Jack Doe",
|
|
207
|
+
"Jack Smith",
|
|
208
|
+
]
|
|
209
|
+
|
|
143
210
|
expect(ast).toBeNull();
|
|
144
|
-
expect(
|
|
145
|
-
expect(
|
|
211
|
+
expect(errorAtIndex).toBe(4);
|
|
212
|
+
expect(options).toEqual(expectedOptions);
|
|
146
213
|
expect(results).toEqual(expectedResults)
|
|
147
214
|
|
|
148
215
|
});
|
|
149
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
|
+
|
|
150
236
|
});
|