clarity-pattern-parser 4.0.2 → 5.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/README.md +176 -1
- package/TODO.md +22 -2
- package/dist/ast/Node.d.ts +43 -11
- package/dist/ast/Visitor.d.ts +31 -31
- package/dist/index.browser.js +1248 -1495
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +12 -16
- package/dist/index.esm.js +1218 -1460
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1217 -1464
- package/dist/index.js.map +1 -1
- package/dist/patterns/And.d.ts +37 -24
- package/dist/patterns/Cursor.d.ts +35 -0
- package/dist/patterns/CursorHistory.d.ts +30 -0
- package/dist/patterns/Literal.d.ts +36 -19
- package/dist/patterns/Not.d.ts +26 -11
- package/dist/patterns/Or.d.ts +31 -22
- package/dist/patterns/ParseError.d.ts +6 -8
- package/dist/patterns/ParseResult.d.ts +6 -0
- package/dist/patterns/Pattern.d.ts +17 -26
- package/dist/patterns/Reference.d.ts +31 -12
- package/dist/patterns/Regex.d.ts +42 -21
- package/dist/patterns/Repeat.d.ts +38 -20
- package/dist/patterns/clonePatterns.d.ts +2 -0
- package/dist/patterns/filterOutNull.d.ts +2 -0
- package/dist/patterns/findPattern.d.ts +2 -0
- package/dist/patterns/getNextPattern.d.ts +2 -0
- package/jest.config.js +2 -1
- package/package.json +4 -5
- package/rollup.config.js +1 -1
- package/src/ast/Node.test.ts +254 -0
- package/src/ast/Node.ts +171 -23
- package/src/index.ts +11 -19
- package/src/intellisense/AutoComplete.test.ts +72 -0
- package/src/intellisense/AutoComplete.ts +146 -0
- package/src/intellisense/Suggestion.ts +13 -0
- package/src/intellisense/SuggestionOption.ts +4 -0
- package/src/{tests/cssPatterns → intellisense/css}/cssValue.ts +1 -1
- package/src/{tests/cssPatterns → intellisense/css}/divider.ts +2 -1
- package/src/intellisense/css/hex.ts +6 -0
- package/src/{tests/cssPatterns → intellisense/css}/method.ts +8 -9
- package/src/intellisense/css/name.ts +5 -0
- package/src/{tests/javascriptPatterns → intellisense/css}/number.ts +3 -3
- package/src/intellisense/css/spaces.ts +6 -0
- package/src/intellisense/css/unit.ts +10 -0
- package/src/{tests/cssPatterns → intellisense/css}/value.ts +1 -1
- package/src/{tests/cssPatterns → intellisense/css}/values.ts +1 -1
- package/src/intellisense/javascript/Javascript.test.ts +203 -0
- package/src/intellisense/javascript/arrayLiteral.ts +25 -0
- package/src/intellisense/javascript/deleteStatement.ts +14 -0
- package/src/intellisense/javascript/escapedCharacter.ts +50 -0
- package/src/intellisense/javascript/exponent.ts +26 -0
- package/src/intellisense/javascript/expression.ts +87 -0
- package/src/intellisense/javascript/expressionStatement.ts +29 -0
- package/src/intellisense/javascript/fraction.ts +13 -0
- package/src/intellisense/javascript/infixOperator.ts +36 -0
- package/src/intellisense/javascript/integer.ts +7 -0
- package/src/intellisense/javascript/invocation.ts +28 -0
- package/src/intellisense/javascript/literal.ts +14 -0
- package/src/intellisense/javascript/name.ts +3 -0
- package/src/intellisense/javascript/numberLiteral.ts +10 -0
- package/src/intellisense/javascript/objectLiteral.ts +30 -0
- package/src/intellisense/javascript/optionalSpaces.ts +3 -0
- package/src/intellisense/javascript/parameters.ts +20 -0
- package/src/intellisense/javascript/prefixOperator.ts +13 -0
- package/src/intellisense/javascript/propertyAccess.ts +23 -0
- package/src/intellisense/javascript/stringLiteral.ts +28 -0
- package/src/patterns/And.test.ts +299 -0
- package/src/patterns/And.ts +222 -119
- package/src/patterns/Cursor.test.ts +93 -0
- package/src/patterns/Cursor.ts +130 -0
- package/src/patterns/CursorHistory.test.ts +54 -0
- package/src/patterns/CursorHistory.ts +95 -0
- package/src/patterns/Literal.test.ts +134 -0
- package/src/patterns/Literal.ts +151 -61
- package/src/patterns/Not.test.ts +88 -0
- package/src/patterns/Not.ts +74 -33
- package/src/patterns/Or.test.ts +105 -0
- package/src/patterns/Or.ts +106 -98
- package/src/patterns/ParseError.ts +3 -7
- package/src/patterns/ParseResult.ts +7 -0
- package/src/patterns/Pattern.ts +18 -150
- package/src/patterns/Reference.test.ts +104 -0
- package/src/patterns/Reference.ts +94 -94
- package/src/patterns/Regex.test.ts +101 -0
- package/src/patterns/Regex.ts +129 -60
- package/src/patterns/Repeat.test.ts +196 -0
- package/src/patterns/Repeat.ts +208 -104
- package/src/patterns/clonePatterns.ts +5 -0
- package/src/patterns/filterOutNull.ts +13 -0
- package/src/patterns/findPattern.ts +25 -0
- package/src/patterns/getNextPattern.test.ts +39 -0
- package/src/patterns/getNextPattern.ts +18 -0
- package/src/Cursor.ts +0 -141
- package/src/CursorHistory.ts +0 -146
- package/src/TextSuggester.ts +0 -317
- package/src/ast/Visitor.ts +0 -271
- package/src/patterns/LookAhead.ts +0 -32
- package/src/patterns/Recursive.ts +0 -92
- package/src/tests/And.test.ts +0 -180
- package/src/tests/ComplexExamples.test.ts +0 -86
- package/src/tests/CssPatterns.test.ts +0 -90
- package/src/tests/CursorHistory.test.ts +0 -107
- package/src/tests/Cusor.test.ts +0 -174
- package/src/tests/HtmlPatterns.test.ts +0 -34
- package/src/tests/Literal.test.ts +0 -79
- package/src/tests/LookAhead.test.ts +0 -44
- package/src/tests/Not.test.ts +0 -51
- package/src/tests/Or.test.ts +0 -113
- package/src/tests/Pattern.test.ts +0 -290
- package/src/tests/Recursive.test.ts +0 -64
- package/src/tests/Reference.test.ts +0 -16
- package/src/tests/Repeat.test.ts +0 -75
- package/src/tests/SpeedTest.test.ts +0 -31
- package/src/tests/TextSuggester.test.ts +0 -297
- package/src/tests/Visitor.test.ts +0 -331
- package/src/tests/cssPatterns/hex.ts +0 -5
- package/src/tests/cssPatterns/name.ts +0 -5
- package/src/tests/cssPatterns/number.ts +0 -8
- package/src/tests/cssPatterns/spaces.ts +0 -5
- package/src/tests/cssPatterns/unit.ts +0 -8
- package/src/tests/htmlPatterns/element.ts +0 -49
- package/src/tests/javascriptPatterns/boolean.ts +0 -10
- package/src/tests/javascriptPatterns/json.ts +0 -67
- package/src/tests/javascriptPatterns/name.ts +0 -5
- package/src/tests/javascriptPatterns/objectLiteral.ts +0 -40
- package/src/tests/javascriptPatterns/string.ts +0 -84
- package/src/tests/javascriptPatterns/unit.ts +0 -8
- package/src/tests/javascriptPatterns/whitespace.ts +0 -44
- package/src/tests/naturalLanguage/filter.ts +0 -37
- package/src/tests/patterns/sentence.ts +0 -37
- /package/src/{tests/cssPatterns → intellisense/css}/optionalSpaces.ts +0 -0
package/src/ast/Node.ts
CHANGED
|
@@ -1,39 +1,187 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
export interface CycleFreeNode {
|
|
2
|
+
type: string;
|
|
3
|
+
name: string;
|
|
4
|
+
firstIndex: number;
|
|
5
|
+
lastIndex: number;
|
|
6
|
+
startIndex: number;
|
|
7
|
+
endIndex: number;
|
|
8
|
+
value: string;
|
|
9
|
+
children: CycleFreeNode[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class Node {
|
|
13
|
+
private _type: string;
|
|
14
|
+
private _name: string;
|
|
15
|
+
private _firstIndex: number;
|
|
16
|
+
private _lastIndex: number;
|
|
17
|
+
private _parent: Node | null;
|
|
18
|
+
private _children: Node[];
|
|
19
|
+
private _value: string;
|
|
20
|
+
|
|
21
|
+
get type() {
|
|
22
|
+
return this._type;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get name() {
|
|
26
|
+
return this._name;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get firstIndex() {
|
|
30
|
+
return this._firstIndex;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get lastIndex() {
|
|
34
|
+
return this._lastIndex;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get startIndex() {
|
|
38
|
+
return this._firstIndex;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get endIndex() {
|
|
42
|
+
return this._lastIndex + 1;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get parent() {
|
|
46
|
+
return this._parent;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get children(): readonly Node[] {
|
|
50
|
+
return this._children;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get value() {
|
|
54
|
+
return this.toString();
|
|
55
|
+
}
|
|
8
56
|
|
|
9
57
|
constructor(
|
|
10
58
|
type: string,
|
|
11
59
|
name: string,
|
|
12
|
-
|
|
13
|
-
|
|
60
|
+
firstIndex: number,
|
|
61
|
+
lastIndex: number,
|
|
14
62
|
children: Node[] = [],
|
|
15
63
|
value: string = ""
|
|
16
64
|
) {
|
|
17
|
-
this.
|
|
18
|
-
this.
|
|
19
|
-
this.
|
|
20
|
-
this.
|
|
21
|
-
this.
|
|
22
|
-
this.
|
|
65
|
+
this._type = type;
|
|
66
|
+
this._name = name;
|
|
67
|
+
this._firstIndex = firstIndex;
|
|
68
|
+
this._lastIndex = lastIndex;
|
|
69
|
+
this._parent = null;
|
|
70
|
+
this._children = children;
|
|
71
|
+
this._value = value;
|
|
72
|
+
|
|
73
|
+
this._children.forEach(c => c._parent = this)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
removeChild(node: Node) {
|
|
77
|
+
const index = this._children.indexOf(node);
|
|
78
|
+
|
|
79
|
+
if (index > -1) {
|
|
80
|
+
this._children.splice(index, 1);
|
|
81
|
+
node._parent = null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
removeAllChildren() {
|
|
86
|
+
this._children.forEach(c => c._parent = null);
|
|
87
|
+
this._children.length = 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
replaceChild(newNode: Node, referenceNode: Node) {
|
|
91
|
+
const index = this._children.indexOf(referenceNode);
|
|
92
|
+
|
|
93
|
+
if (index > -1) {
|
|
94
|
+
this._children.splice(index, 1, newNode);
|
|
95
|
+
newNode._parent = this;
|
|
96
|
+
referenceNode._parent = null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
insertBefore(newNode: Node, referenceNode: Node | null) {
|
|
101
|
+
newNode._parent = this;
|
|
102
|
+
|
|
103
|
+
if (referenceNode == null) {
|
|
104
|
+
this._children.push(newNode);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const index = this._children.indexOf(referenceNode);
|
|
109
|
+
|
|
110
|
+
if (index > -1) {
|
|
111
|
+
this._children.splice(index, 0, newNode);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
appendChild(newNode: Node) {
|
|
116
|
+
newNode._parent = this;
|
|
117
|
+
this._children.push(newNode);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
spliceChildren(index: number, deleteCount: number, ...items: Node[]) {
|
|
121
|
+
const removedItems = this._children.splice(index, deleteCount, ...items);
|
|
122
|
+
|
|
123
|
+
items.forEach(i => i._parent = this);
|
|
124
|
+
removedItems.forEach(i => i._parent = null);
|
|
125
|
+
|
|
126
|
+
return removedItems;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
find(isMatch: (node: Node) => boolean): Node | null {
|
|
130
|
+
return this.findAll(isMatch)[0] || null
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
findAll(isMatch: (node: Node) => boolean): Node[] {
|
|
134
|
+
const matches: Node[] = [];
|
|
135
|
+
this.walkUp(n => {
|
|
136
|
+
if (isMatch(n)) { matches.push(n); }
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
return matches;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
walkUp(callback: (node: Node) => void) {
|
|
143
|
+
this.children.forEach(c => c.walkUp(callback))
|
|
144
|
+
callback(this);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
walkDown(callback: (node: Node) => void) {
|
|
148
|
+
callback(this);
|
|
149
|
+
this.children.forEach(c => c.walkDown(callback))
|
|
23
150
|
}
|
|
24
151
|
|
|
25
152
|
clone(): Node {
|
|
26
153
|
return new Node(
|
|
27
|
-
this.
|
|
28
|
-
this.
|
|
29
|
-
this.
|
|
30
|
-
this.
|
|
31
|
-
this.
|
|
32
|
-
this.
|
|
154
|
+
this._type,
|
|
155
|
+
this._name,
|
|
156
|
+
this._firstIndex,
|
|
157
|
+
this._lastIndex,
|
|
158
|
+
this._children.map((c) => c.clone()),
|
|
159
|
+
this._value
|
|
33
160
|
);
|
|
34
161
|
}
|
|
35
162
|
|
|
36
|
-
toString() {
|
|
37
|
-
|
|
163
|
+
toString(): string {
|
|
164
|
+
if (this._children.length === 0) {
|
|
165
|
+
return this._value;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return this._children.map(c => c.toString()).join("")
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
toCycleFreeObject(): CycleFreeNode {
|
|
172
|
+
return {
|
|
173
|
+
type: this._type,
|
|
174
|
+
name: this._name,
|
|
175
|
+
value: this.toString(),
|
|
176
|
+
firstIndex: this._firstIndex,
|
|
177
|
+
lastIndex: this._lastIndex,
|
|
178
|
+
startIndex: this.startIndex,
|
|
179
|
+
endIndex: this.endIndex,
|
|
180
|
+
children: this._children.map(c => c.toCycleFreeObject()),
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
toJson(space?: number): string {
|
|
185
|
+
return JSON.stringify(this.toCycleFreeObject(), null, space)
|
|
38
186
|
}
|
|
39
187
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
|
-
import Node from "./ast/Node";
|
|
2
|
-
import Cursor from "./Cursor";
|
|
3
|
-
import Regex from "./patterns/Regex";
|
|
4
|
-
import And from "./patterns/And";
|
|
5
|
-
import Literal from "./patterns/Literal";
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import Recursive from "./patterns/Recursive";
|
|
13
|
-
import Reference from "./patterns/Reference";
|
|
14
|
-
import TextSuggester from "./TextSuggester";
|
|
15
|
-
import Visitor from "./ast/Visitor";
|
|
1
|
+
import { Node } from "./ast/Node";
|
|
2
|
+
import { Cursor } from "./patterns/Cursor";
|
|
3
|
+
import { Regex } from "./patterns/Regex";
|
|
4
|
+
import { And } from "./patterns/And";
|
|
5
|
+
import { Literal } from "./patterns/Literal";
|
|
6
|
+
import { Not } from "./patterns/Not";
|
|
7
|
+
import { Or } from "./patterns/Or";
|
|
8
|
+
import { Repeat } from "./patterns/Repeat";
|
|
9
|
+
import { ParseError } from "./patterns/ParseError";
|
|
10
|
+
import { Pattern } from "./patterns/Pattern";
|
|
11
|
+
import { Reference } from "./patterns/Reference";
|
|
16
12
|
|
|
17
13
|
export {
|
|
18
14
|
Node,
|
|
@@ -25,9 +21,5 @@ export {
|
|
|
25
21
|
Repeat,
|
|
26
22
|
ParseError,
|
|
27
23
|
Pattern,
|
|
28
|
-
Recursive,
|
|
29
24
|
Reference,
|
|
30
|
-
TextSuggester,
|
|
31
|
-
Visitor,
|
|
32
|
-
LookAhead,
|
|
33
25
|
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { And } from "../patterns/And";
|
|
2
|
+
import { findPattern } from "../patterns/findPattern";
|
|
3
|
+
import { Literal } from "../patterns/Literal";
|
|
4
|
+
import { Or } from "../patterns/Or";
|
|
5
|
+
import { AutoComplete } from "./AutoComplete";
|
|
6
|
+
|
|
7
|
+
describe("AutoComplete", () => {
|
|
8
|
+
test("No Text", () => {
|
|
9
|
+
const name = new Literal("name", "Name");
|
|
10
|
+
const autoComplete = new AutoComplete(name);
|
|
11
|
+
let result = autoComplete.suggest("");
|
|
12
|
+
|
|
13
|
+
expect(result.options[0].text).toBe("Name");
|
|
14
|
+
expect(result.options[0].startIndex).toBe(0);
|
|
15
|
+
expect(result.nextPattern).toBe(name);
|
|
16
|
+
expect(result.isComplete).toBeFalsy();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test("Full Pattern Match", () => {
|
|
20
|
+
const john = new Literal("john", "John");
|
|
21
|
+
const space = new Literal("space", " ");
|
|
22
|
+
const doe = new Literal("doe", "Doe");
|
|
23
|
+
const smith = new Literal("smith", "Smith");
|
|
24
|
+
|
|
25
|
+
space.enableContextualTokenAggregation();
|
|
26
|
+
|
|
27
|
+
const name = new And("name", [john, space, new Or("last-name", [smith, doe])]);
|
|
28
|
+
|
|
29
|
+
const autoComplete = new AutoComplete(name);
|
|
30
|
+
let result = autoComplete.suggest("John");
|
|
31
|
+
|
|
32
|
+
expect(result.options.length).toBe(2);
|
|
33
|
+
expect(result.nextPattern).toBe(findPattern(name, p=>p.name === "space"));
|
|
34
|
+
expect(result.options[0].text).toBe(" Doe");
|
|
35
|
+
expect(result.options[0].startIndex).toBe(4);
|
|
36
|
+
expect(result.options[1].text).toBe(" Smith");
|
|
37
|
+
expect(result.options[1].startIndex).toBe(4);
|
|
38
|
+
expect(result.isComplete).toBeFalsy();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("Partial", () => {
|
|
42
|
+
const name = new Literal("name", "Name");
|
|
43
|
+
const autoComplete = new AutoComplete(name);
|
|
44
|
+
let result = autoComplete.suggest("Na");
|
|
45
|
+
|
|
46
|
+
expect(result.options[0].text).toBe("me");
|
|
47
|
+
expect(result.options[0].startIndex).toBe(2);
|
|
48
|
+
expect(result.nextPattern).toBe(name);
|
|
49
|
+
expect(result.isComplete).toBeFalsy();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("Partial Match With Bad Characters", () => {
|
|
53
|
+
const name = new Literal("name", "Name");
|
|
54
|
+
const autoComplete = new AutoComplete(name);
|
|
55
|
+
let result = autoComplete.suggest("Ni");
|
|
56
|
+
|
|
57
|
+
expect(result.options[0].text).toBe("ame");
|
|
58
|
+
expect(result.options[0].startIndex).toBe(1);
|
|
59
|
+
expect(result.nextPattern).toBe(name);
|
|
60
|
+
expect(result.isComplete).toBeFalsy();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("Complete", () => {
|
|
64
|
+
const name = new Literal("name", "Name");
|
|
65
|
+
const autoComplete = new AutoComplete(name);
|
|
66
|
+
let result = autoComplete.suggest("Name");
|
|
67
|
+
|
|
68
|
+
expect(result.options.length).toBe(0);
|
|
69
|
+
expect(result.nextPattern).toBe(null);
|
|
70
|
+
expect(result.isComplete).toBeTruthy();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { Cursor } from "../patterns/Cursor";
|
|
2
|
+
import { ParseError } from "../patterns/ParseError";
|
|
3
|
+
import { Pattern } from "../patterns/Pattern";
|
|
4
|
+
import { Suggestion } from "./Suggestion";
|
|
5
|
+
import { SuggestionOption } from "./SuggestionOption";
|
|
6
|
+
|
|
7
|
+
export class AutoComplete {
|
|
8
|
+
private _pattern: Pattern;
|
|
9
|
+
private _cursor!: Cursor;
|
|
10
|
+
private _text: string;
|
|
11
|
+
|
|
12
|
+
constructor(pattern: Pattern) {
|
|
13
|
+
this._pattern = pattern;
|
|
14
|
+
this._text = "";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
suggest(text: string): Suggestion {
|
|
18
|
+
if (text.length === 0) {
|
|
19
|
+
return {
|
|
20
|
+
isComplete: false,
|
|
21
|
+
options: this.createSuggestionsFromRoot(),
|
|
22
|
+
nextPattern: this._pattern,
|
|
23
|
+
cursor: null,
|
|
24
|
+
error: new ParseError(0, this._pattern),
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
this._text = text;
|
|
29
|
+
this._cursor = new Cursor(text);
|
|
30
|
+
this._pattern.parse(this._cursor);
|
|
31
|
+
|
|
32
|
+
const leafPattern = this._cursor.leafMatch.pattern;
|
|
33
|
+
const rootMatch = this._cursor.rootMatch.pattern;
|
|
34
|
+
const isComplete = this._cursor.isOnLast && rootMatch === this._pattern;
|
|
35
|
+
const options = this.createSuggestionsFromTokens();
|
|
36
|
+
const nextPattern = isComplete ? null : leafPattern?.getNextPattern() || this._pattern;
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
isComplete: isComplete,
|
|
40
|
+
options: options,
|
|
41
|
+
nextPattern,
|
|
42
|
+
cursor: this._cursor,
|
|
43
|
+
error: this._cursor.furthestError
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private createSuggestionsFromRoot(): SuggestionOption[] {
|
|
48
|
+
const suggestions: SuggestionOption[] = [];
|
|
49
|
+
const tokens = this._pattern.getTokens();
|
|
50
|
+
|
|
51
|
+
for (const token of tokens) {
|
|
52
|
+
suggestions.push(this.createSuggestion("", token));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return suggestions;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private createSuggestionsFromTokens(): SuggestionOption[] {
|
|
59
|
+
const leafMatch = this._cursor.leafMatch;
|
|
60
|
+
|
|
61
|
+
if (!leafMatch.pattern) {
|
|
62
|
+
return this.createSuggestions(-1, this._pattern.getTokens());
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const leafPattern = leafMatch.pattern;
|
|
66
|
+
const parent = leafMatch.pattern.parent;
|
|
67
|
+
|
|
68
|
+
if (parent !== null && leafMatch.node != null) {
|
|
69
|
+
const tokens = parent.getNextTokens(leafPattern);
|
|
70
|
+
return this.createSuggestions(leafMatch.node.lastIndex, tokens);
|
|
71
|
+
} else {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private createSuggestions(lastIndex: number, tokens: string[]): SuggestionOption[] {
|
|
77
|
+
let substring = lastIndex === -1 ? "" : this._cursor.getChars(0, lastIndex);
|
|
78
|
+
const suggestionStrings: string[] = [];
|
|
79
|
+
const options: SuggestionOption[] = [];
|
|
80
|
+
|
|
81
|
+
for (const token of tokens) {
|
|
82
|
+
const suggestion = substring + token;
|
|
83
|
+
const startsWith = suggestion.startsWith(substring);
|
|
84
|
+
const alreadyExist = suggestionStrings.includes(suggestion);
|
|
85
|
+
const isSameAsText = suggestion === this._text;
|
|
86
|
+
|
|
87
|
+
if (startsWith && !alreadyExist && !isSameAsText) {
|
|
88
|
+
suggestionStrings.push(suggestion);
|
|
89
|
+
options.push(this.createSuggestion(this._cursor.text, suggestion));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const reducedOptions = getFurthestOptions(options);
|
|
94
|
+
reducedOptions.sort((a, b) => a.text.localeCompare(b.text));
|
|
95
|
+
|
|
96
|
+
return reducedOptions;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private createSuggestion(fullText: string, suggestion: string): SuggestionOption {
|
|
100
|
+
const furthestMatch = findMatchIndex(suggestion, fullText);
|
|
101
|
+
const text = suggestion.slice(furthestMatch);
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
text: text,
|
|
105
|
+
startIndex: furthestMatch,
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function findMatchIndex(str1: string, str2: string): number {
|
|
111
|
+
let matchCount = 0;
|
|
112
|
+
let minLength = str1.length;
|
|
113
|
+
|
|
114
|
+
if (str2.length < minLength) {
|
|
115
|
+
minLength = str2.length;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
for (let i = 0; i < minLength; i++) {
|
|
119
|
+
if (str1[i] === str2[i]) {
|
|
120
|
+
matchCount++;
|
|
121
|
+
} else {
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return matchCount;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function getFurthestOptions(options: SuggestionOption[]): SuggestionOption[] {
|
|
130
|
+
let furthestOptions: SuggestionOption[] = [];
|
|
131
|
+
let furthestIndex = -1;
|
|
132
|
+
|
|
133
|
+
for (const option of options) {
|
|
134
|
+
if (option.startIndex > furthestIndex) {
|
|
135
|
+
furthestIndex = option.startIndex;
|
|
136
|
+
furthestOptions = [];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (option.startIndex === furthestIndex) {
|
|
140
|
+
furthestOptions.push(option);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return furthestOptions;
|
|
145
|
+
}
|
|
146
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Cursor } from "../patterns/Cursor";
|
|
2
|
+
import { Match } from "../patterns/CursorHistory";
|
|
3
|
+
import { ParseError } from "../patterns/ParseError";
|
|
4
|
+
import { Pattern } from "../patterns/Pattern";
|
|
5
|
+
import { SuggestionOption } from "./SuggestionOption";
|
|
6
|
+
|
|
7
|
+
export interface Suggestion {
|
|
8
|
+
isComplete: boolean;
|
|
9
|
+
options: SuggestionOption[];
|
|
10
|
+
nextPattern: Pattern | null;
|
|
11
|
+
cursor: Cursor | null;
|
|
12
|
+
error: ParseError | null;
|
|
13
|
+
}
|
|
@@ -1,21 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Recursive,
|
|
6
|
-
} from "../../index";
|
|
7
|
-
|
|
1
|
+
import { Reference } from "../../patterns/Reference";
|
|
2
|
+
import { Literal } from "../../patterns/Literal";
|
|
3
|
+
import { Repeat } from "../../patterns/Repeat";
|
|
4
|
+
import { And } from "../../patterns/And";
|
|
8
5
|
import name from "./name";
|
|
9
6
|
import optionalSpaces from "./optionalSpaces";
|
|
10
7
|
import divider from "./divider";
|
|
11
8
|
|
|
12
9
|
const openParen = new Literal("open-paren", "(");
|
|
13
10
|
const closeParen = new Literal("close-paren", ")");
|
|
14
|
-
const values = new
|
|
11
|
+
const values = new Reference("values");
|
|
15
12
|
const args = new Repeat("arguments", values, divider, true);
|
|
13
|
+
const methodName = name.clone("method-name");
|
|
14
|
+
methodName.setTokens(["rgba", "radial-gradient", "linear-gradient"]);
|
|
16
15
|
|
|
17
16
|
const method = new And("method", [
|
|
18
|
-
|
|
17
|
+
methodName,
|
|
19
18
|
openParen,
|
|
20
19
|
optionalSpaces,
|
|
21
20
|
args,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { And } from "../../patterns/And";
|
|
2
|
+
import { Regex } from "../../patterns/Regex";
|
|
3
|
+
import number from "./number";
|
|
4
|
+
|
|
5
|
+
const unitType = new Regex("unit-type", "[a-zA-Z%]+");
|
|
6
|
+
unitType.setTokens(["px", "%", "em", "rem", "vh", "vw"]);
|
|
7
|
+
|
|
8
|
+
const unit = new And("unit", [number, unitType]);
|
|
9
|
+
|
|
10
|
+
export default unit;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Or } from "../../index";
|
|
2
1
|
import unit from "./unit";
|
|
3
2
|
import hex from "./hex";
|
|
4
3
|
import number from "./number";
|
|
5
4
|
import method from "./method";
|
|
6
5
|
import name from "./name"
|
|
6
|
+
import { Or } from "../../patterns/Or";
|
|
7
7
|
|
|
8
8
|
const value = new Or("value", [hex, method, unit, number, name]);
|
|
9
9
|
|