clarity-pattern-parser 3.0.16 → 4.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 +0 -191
- package/dist/ast/Node.d.ts +4 -5
- package/dist/index.browser.js +476 -731
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +10 -18
- package/dist/index.esm.js +469 -716
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +476 -731
- package/dist/index.js.map +1 -1
- package/dist/patterns/And.d.ts +24 -0
- package/dist/patterns/Literal.d.ts +19 -0
- package/dist/patterns/LookAhead.d.ts +8 -0
- package/dist/patterns/Not.d.ts +11 -0
- package/dist/patterns/Or.d.ts +22 -0
- package/dist/patterns/Pattern.d.ts +6 -7
- package/dist/patterns/{RecursivePattern.d.ts → Recursive.d.ts} +4 -4
- package/dist/patterns/Reference.d.ts +14 -0
- package/dist/patterns/Regex.d.ts +21 -0
- package/dist/patterns/Repeat.d.ts +20 -0
- package/package.json +1 -1
- package/src/CursorHistory.ts +1 -1
- package/src/ast/Node.ts +20 -17
- package/src/ast/Visitor.ts +14 -18
- package/src/index.ts +17 -33
- package/src/patterns/And.ts +178 -0
- package/src/patterns/Literal.ts +91 -0
- package/src/patterns/Not.ts +50 -0
- package/src/patterns/Or.ts +132 -0
- package/src/patterns/Pattern.ts +31 -47
- package/src/patterns/Recursive.ts +92 -0
- package/src/patterns/{ReferencePattern.ts → Reference.ts} +32 -28
- package/src/patterns/Regex.ts +123 -0
- package/src/patterns/Repeat.ts +155 -0
- package/src/tests/{AndValue.test.ts → And.test.ts} +31 -41
- package/src/tests/CursorHistory.test.ts +6 -6
- package/src/tests/Cusor.test.ts +7 -10
- package/src/tests/Literal.test.ts +3 -5
- package/src/tests/LookAhead.test.ts +2 -51
- package/src/tests/Not.test.ts +51 -0
- package/src/tests/Or.test.ts +113 -0
- package/src/tests/Pattern.test.ts +40 -139
- package/src/tests/{RecursivePattern.test.ts → Recursive.test.ts} +10 -8
- package/src/tests/Reference.test.ts +16 -0
- package/src/tests/{RepeatValue.test.ts → Repeat.test.ts} +10 -42
- package/src/tests/TextSuggester.test.ts +20 -28
- package/src/tests/{NodeVisitor.test.ts → Visitor.test.ts} +42 -21
- package/src/tests/cssPatterns/cssValue.ts +2 -2
- package/src/tests/cssPatterns/divider.ts +2 -2
- package/src/tests/cssPatterns/hex.ts +2 -2
- package/src/tests/cssPatterns/method.ts +7 -9
- package/src/tests/cssPatterns/name.ts +2 -2
- package/src/tests/cssPatterns/number.ts +2 -2
- package/src/tests/cssPatterns/optionalSpaces.ts +1 -2
- package/src/tests/cssPatterns/spaces.ts +2 -2
- package/src/tests/cssPatterns/unit.ts +3 -3
- package/src/tests/cssPatterns/value.ts +2 -2
- package/src/tests/cssPatterns/values.ts +2 -2
- package/src/tests/htmlPatterns/element.ts +18 -33
- package/src/tests/javascriptPatterns/boolean.ts +2 -3
- package/src/tests/javascriptPatterns/json.ts +14 -26
- package/src/tests/javascriptPatterns/name.ts +3 -20
- package/src/tests/javascriptPatterns/number.ts +2 -2
- package/src/tests/javascriptPatterns/objectLiteral.ts +9 -16
- package/src/tests/javascriptPatterns/string.ts +26 -24
- package/src/tests/javascriptPatterns/unit.ts +3 -6
- package/src/tests/javascriptPatterns/whitespace.ts +8 -12
- package/src/tests/naturalLanguage/filter.ts +16 -33
- package/src/tests/patterns/sentence.ts +8 -8
- package/dist/Cursor.js +0 -105
- package/dist/Cursor.js.map +0 -1
- package/dist/CursorHistory.js +0 -104
- package/dist/CursorHistory.js.map +0 -1
- package/dist/Permutor.d.ts +0 -13
- package/dist/Permutor.js +0 -52
- package/dist/Permutor.js.map +0 -1
- package/dist/TextSuggester.js +0 -244
- package/dist/TextSuggester.js.map +0 -1
- package/dist/ast/CompositeNode.d.ts +0 -6
- package/dist/ast/CompositeNode.js +0 -17
- package/dist/ast/CompositeNode.js.map +0 -1
- package/dist/ast/Node.js +0 -16
- package/dist/ast/Node.js.map +0 -1
- package/dist/ast/NodeVisitor.d.ts +0 -31
- package/dist/ast/ValueNode.d.ts +0 -6
- package/dist/ast/ValueNode.js +0 -14
- package/dist/ast/ValueNode.js.map +0 -1
- package/dist/ast/Visitor.js +0 -209
- package/dist/ast/Visitor.js.map +0 -1
- package/dist/patterns/ParseError.js +0 -9
- package/dist/patterns/ParseError.js.map +0 -1
- package/dist/patterns/Pattern.js +0 -127
- package/dist/patterns/Pattern.js.map +0 -1
- package/dist/patterns/RecursivePattern.js +0 -65
- package/dist/patterns/RecursivePattern.js.map +0 -1
- package/dist/patterns/composite/AndComposite.d.ts +0 -22
- package/dist/patterns/composite/AndComposite.js +0 -117
- package/dist/patterns/composite/AndComposite.js.map +0 -1
- package/dist/patterns/composite/CompositePattern.d.ts +0 -4
- package/dist/patterns/composite/CompositePattern.js +0 -7
- package/dist/patterns/composite/CompositePattern.js.map +0 -1
- package/dist/patterns/composite/OptionalComposite.d.ts +0 -10
- package/dist/patterns/composite/OptionalComposite.js +0 -29
- package/dist/patterns/composite/OptionalComposite.js.map +0 -1
- package/dist/patterns/composite/OrComposite.d.ts +0 -16
- package/dist/patterns/composite/OrComposite.js +0 -69
- package/dist/patterns/composite/OrComposite.js.map +0 -1
- package/dist/patterns/composite/RepeatComposite.d.ts +0 -21
- package/dist/patterns/composite/RepeatComposite.js +0 -88
- package/dist/patterns/composite/RepeatComposite.js.map +0 -1
- package/dist/patterns/value/AndValue.d.ts +0 -21
- package/dist/patterns/value/AndValue.js +0 -118
- package/dist/patterns/value/AndValue.js.map +0 -1
- package/dist/patterns/value/AnyOfThese.d.ts +0 -18
- package/dist/patterns/value/AnyOfThese.js +0 -59
- package/dist/patterns/value/AnyOfThese.js.map +0 -1
- package/dist/patterns/value/Literal.d.ts +0 -20
- package/dist/patterns/value/Literal.js +0 -63
- package/dist/patterns/value/Literal.js.map +0 -1
- package/dist/patterns/value/NotValue.d.ts +0 -17
- package/dist/patterns/value/NotValue.js +0 -70
- package/dist/patterns/value/NotValue.js.map +0 -1
- package/dist/patterns/value/OptionalValue.d.ts +0 -9
- package/dist/patterns/value/OptionalValue.js +0 -32
- package/dist/patterns/value/OptionalValue.js.map +0 -1
- package/dist/patterns/value/OrValue.d.ts +0 -19
- package/dist/patterns/value/OrValue.js +0 -73
- package/dist/patterns/value/OrValue.js.map +0 -1
- package/dist/patterns/value/RegexValue.d.ts +0 -19
- package/dist/patterns/value/RegexValue.js +0 -69
- package/dist/patterns/value/RegexValue.js.map +0 -1
- package/dist/patterns/value/RepeatValue.d.ts +0 -19
- package/dist/patterns/value/RepeatValue.js +0 -89
- package/dist/patterns/value/RepeatValue.js.map +0 -1
- package/dist/patterns/value/ValuePattern.d.ts +0 -5
- package/dist/patterns/value/ValuePattern.js +0 -7
- package/dist/patterns/value/ValuePattern.js.map +0 -1
- package/src/Permutor.ts +0 -64
- package/src/ast/CompositeNode.ts +0 -26
- package/src/ast/ValueNode.ts +0 -28
- package/src/patterns/RecursivePattern.ts +0 -86
- package/src/patterns/composite/AndComposite.ts +0 -159
- package/src/patterns/composite/CompositePattern.ts +0 -7
- package/src/patterns/composite/OptionalComposite.ts +0 -37
- package/src/patterns/composite/OrComposite.ts +0 -96
- package/src/patterns/composite/RepeatComposite.ts +0 -130
- package/src/patterns/value/AndValue.ts +0 -152
- package/src/patterns/value/AnyOfThese.ts +0 -81
- package/src/patterns/value/Literal.ts +0 -92
- package/src/patterns/value/NotValue.ts +0 -95
- package/src/patterns/value/OptionalValue.ts +0 -39
- package/src/patterns/value/OrValue.ts +0 -103
- package/src/patterns/value/RegexValue.ts +0 -103
- package/src/patterns/value/RepeatValue.ts +0 -131
- package/src/patterns/value/ValuePattern.ts +0 -8
- package/src/tests/AndComposite.test.ts +0 -102
- package/src/tests/AnyOfThese.test.ts +0 -74
- package/src/tests/CompositeNode.test.ts +0 -33
- package/src/tests/NotValue.test.ts +0 -76
- package/src/tests/OptionalValue.test.ts +0 -50
- package/src/tests/OrComposite.test.ts +0 -75
- package/src/tests/OrValue.test.ts +0 -171
- package/src/tests/Permutor.test.ts +0 -30
- package/src/tests/ReferencePattern.test.ts +0 -24
- package/src/tests/RegexValue.test.ts +0 -22
- package/src/tests/RepeatComposite.test.ts +0 -58
- package/src/tests/ValueNode.test.ts +0 -24
- package/src/tests/javascriptPatterns/varStatement.ts +0 -0
- package/src/tests/readmeDemo.test.ts +0 -124
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import Pattern from "./Pattern";
|
|
2
|
+
import Node from "../ast/Node";
|
|
3
|
+
import ParseError from "./ParseError";
|
|
4
|
+
import Cursor from "../Cursor";
|
|
5
|
+
|
|
6
|
+
export default class Repeat extends Pattern {
|
|
7
|
+
public _pattern: Pattern;
|
|
8
|
+
public _divider: Pattern;
|
|
9
|
+
public nodes: Node[] = [];
|
|
10
|
+
public cursor!: Cursor;
|
|
11
|
+
public mark: number = 0;
|
|
12
|
+
public node: Node | null = null;
|
|
13
|
+
|
|
14
|
+
constructor(
|
|
15
|
+
name: string,
|
|
16
|
+
pattern: Pattern,
|
|
17
|
+
divider?: Pattern,
|
|
18
|
+
isOptional = false
|
|
19
|
+
) {
|
|
20
|
+
super(
|
|
21
|
+
"repeat",
|
|
22
|
+
name,
|
|
23
|
+
divider != null ? [pattern, divider] : [pattern],
|
|
24
|
+
isOptional
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
this._pattern = this.children[0];
|
|
28
|
+
this._divider = this.children[1];
|
|
29
|
+
this.assertArguments();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private assertArguments() {
|
|
33
|
+
if (this._pattern.isOptional) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
"Invalid Arguments: The pattern cannot be a optional pattern."
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private _reset(cursor: Cursor) {
|
|
41
|
+
this.nodes = [];
|
|
42
|
+
this.cursor = cursor;
|
|
43
|
+
this.mark = this.cursor.mark();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
parse(cursor: Cursor) {
|
|
47
|
+
this._reset(cursor);
|
|
48
|
+
this.tryToParse();
|
|
49
|
+
|
|
50
|
+
return this.node;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private tryToParse() {
|
|
54
|
+
const cursor = this.safelyGetCursor();
|
|
55
|
+
|
|
56
|
+
while (true) {
|
|
57
|
+
const node = this._pattern.parse(cursor);
|
|
58
|
+
|
|
59
|
+
if (cursor.hasUnresolvedError()) {
|
|
60
|
+
this.processResult();
|
|
61
|
+
break;
|
|
62
|
+
} else if (node != null) {
|
|
63
|
+
this.nodes.push(node);
|
|
64
|
+
|
|
65
|
+
if (node.endIndex === cursor.lastIndex()) {
|
|
66
|
+
this.processResult();
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
cursor.next();
|
|
71
|
+
|
|
72
|
+
if (this._divider != null) {
|
|
73
|
+
const mark = cursor.mark();
|
|
74
|
+
const node = this._divider.parse(cursor);
|
|
75
|
+
|
|
76
|
+
if (cursor.hasUnresolvedError()) {
|
|
77
|
+
cursor.moveToMark(mark);
|
|
78
|
+
this.processResult();
|
|
79
|
+
break;
|
|
80
|
+
} else if (node != null) {
|
|
81
|
+
this.nodes.push(node);
|
|
82
|
+
|
|
83
|
+
if (node.endIndex === cursor.lastIndex()) {
|
|
84
|
+
this.processResult();
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
cursor.next();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private processResult() {
|
|
96
|
+
const endsOnDivider = this.nodes.length % 2 === 0;
|
|
97
|
+
const noMatch = this.nodes.length === 0;
|
|
98
|
+
const hasDivider = this._divider != null;
|
|
99
|
+
|
|
100
|
+
this.cursor.resolveError();
|
|
101
|
+
|
|
102
|
+
if ((hasDivider && endsOnDivider) || noMatch) {
|
|
103
|
+
if (this._isOptional) {
|
|
104
|
+
this.cursor.moveToMark(this.mark);
|
|
105
|
+
} else {
|
|
106
|
+
const parseError = new ParseError(
|
|
107
|
+
`Did not find a repeating match of ${this.name}.`,
|
|
108
|
+
this.mark,
|
|
109
|
+
this
|
|
110
|
+
);
|
|
111
|
+
this.cursor.throwError(parseError);
|
|
112
|
+
}
|
|
113
|
+
this.node = null;
|
|
114
|
+
} else {
|
|
115
|
+
const value = this.nodes.map((node) => node.value).join("");
|
|
116
|
+
|
|
117
|
+
this.node = new Node(
|
|
118
|
+
"repeat",
|
|
119
|
+
this.name,
|
|
120
|
+
this.nodes[0].startIndex,
|
|
121
|
+
this.nodes[this.nodes.length - 1].endIndex,
|
|
122
|
+
this.nodes,
|
|
123
|
+
value
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
this.cursor.index = this.node.endIndex;
|
|
127
|
+
this.cursor.addMatch(this, this.node);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private safelyGetCursor() {
|
|
132
|
+
const cursor = this.cursor;
|
|
133
|
+
|
|
134
|
+
if (cursor == null) {
|
|
135
|
+
throw new Error("Couldn't find cursor.");
|
|
136
|
+
}
|
|
137
|
+
return cursor;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
clone(name?: string, isOptional?: boolean) {
|
|
141
|
+
if (name == null) {
|
|
142
|
+
name = this.name;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (isOptional == null) {
|
|
146
|
+
isOptional = this._isOptional;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return new Repeat(name, this._pattern, this._divider, isOptional);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
getTokens() {
|
|
153
|
+
return this._pattern.getTokens();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
/** @jest-environment node */
|
|
2
|
-
import
|
|
3
|
-
import Literal from "../patterns/
|
|
4
|
-
import OptionalValue from "../patterns/value/OptionalValue";
|
|
2
|
+
import And from "../patterns/And";
|
|
3
|
+
import Literal from "../patterns/Literal";
|
|
5
4
|
import Cursor from "../Cursor";
|
|
6
5
|
|
|
7
|
-
describe("
|
|
8
|
-
test("One Pattern", () => {
|
|
9
|
-
expect(() => {
|
|
10
|
-
new AndValue("and-value", [new Literal("literal", "LITERAL")]);
|
|
11
|
-
}).toThrow();
|
|
12
|
-
});
|
|
13
|
-
|
|
6
|
+
describe("And", () => {
|
|
14
7
|
test("Success", () => {
|
|
15
8
|
const firstName = new Literal("first-name", "John");
|
|
16
9
|
const lastName = new Literal("last-name", "Doe");
|
|
17
|
-
const fullName = new
|
|
10
|
+
const fullName = new And("full-name", [firstName, lastName]);
|
|
18
11
|
const cursor = new Cursor("JohnDoe");
|
|
19
12
|
const node = fullName.parse(cursor);
|
|
20
13
|
|
|
@@ -26,11 +19,8 @@ describe("AndValue", () => {
|
|
|
26
19
|
|
|
27
20
|
test("First Part Match with optional Second part.", () => {
|
|
28
21
|
const firstName = new Literal("first-name", "John");
|
|
29
|
-
const lastName = new Literal("last-name", "Doe");
|
|
30
|
-
const fullName = new
|
|
31
|
-
firstName,
|
|
32
|
-
new OptionalValue(lastName),
|
|
33
|
-
]);
|
|
22
|
+
const lastName = new Literal("last-name", "Doe", true);
|
|
23
|
+
const fullName = new And("full-name", [firstName, lastName]);
|
|
34
24
|
const cursor = new Cursor("John");
|
|
35
25
|
const node = fullName.parse(cursor);
|
|
36
26
|
|
|
@@ -43,7 +33,7 @@ describe("AndValue", () => {
|
|
|
43
33
|
test("First Part Match, but run out for second part.", () => {
|
|
44
34
|
const firstName = new Literal("first-name", "John");
|
|
45
35
|
const lastName = new Literal("last-name", "Doe");
|
|
46
|
-
const fullName = new
|
|
36
|
+
const fullName = new And("full-name", [firstName, lastName]);
|
|
47
37
|
const cursor = new Cursor("John");
|
|
48
38
|
const node = fullName.parse(cursor);
|
|
49
39
|
|
|
@@ -53,7 +43,7 @@ describe("AndValue", () => {
|
|
|
53
43
|
test("No Match", () => {
|
|
54
44
|
const firstName = new Literal("first-name", "John");
|
|
55
45
|
const lastName = new Literal("last-name", "Doe");
|
|
56
|
-
const fullName = new
|
|
46
|
+
const fullName = new And("full-name", [firstName, lastName]);
|
|
57
47
|
const cursor = new Cursor("JaneDoe");
|
|
58
48
|
const node = fullName.parse(cursor);
|
|
59
49
|
|
|
@@ -63,7 +53,7 @@ describe("AndValue", () => {
|
|
|
63
53
|
test("Partial Match without optional siblings.", () => {
|
|
64
54
|
const firstName = new Literal("first-name", "John");
|
|
65
55
|
const lastName = new Literal("last-name", "Doe");
|
|
66
|
-
const fullName = new
|
|
56
|
+
const fullName = new And("full-name", [firstName, lastName]);
|
|
67
57
|
const cursor = new Cursor("JohnSmith");
|
|
68
58
|
const node = fullName.parse(cursor);
|
|
69
59
|
|
|
@@ -73,7 +63,7 @@ describe("AndValue", () => {
|
|
|
73
63
|
test("Success with more to parse", () => {
|
|
74
64
|
const firstName = new Literal("first-name", "John");
|
|
75
65
|
const lastName = new Literal("last-name", "Doe");
|
|
76
|
-
const fullName = new
|
|
66
|
+
const fullName = new And("full-name", [firstName, lastName]);
|
|
77
67
|
const cursor = new Cursor("JohnDoe JaneDoe");
|
|
78
68
|
const node = fullName.parse(cursor);
|
|
79
69
|
|
|
@@ -86,7 +76,7 @@ describe("AndValue", () => {
|
|
|
86
76
|
test("Clone.", () => {
|
|
87
77
|
const firstName = new Literal("first-name", "John");
|
|
88
78
|
const lastName = new Literal("last-name", "Doe");
|
|
89
|
-
const fullName = new
|
|
79
|
+
const fullName = new And("full-name", [firstName, lastName]);
|
|
90
80
|
const clone = fullName.clone();
|
|
91
81
|
|
|
92
82
|
const fullNamePatterns = fullName.children;
|
|
@@ -100,7 +90,7 @@ describe("AndValue", () => {
|
|
|
100
90
|
test("Clone with custom name.", () => {
|
|
101
91
|
const firstName = new Literal("first-name", "John");
|
|
102
92
|
const lastName = new Literal("last-name", "Doe");
|
|
103
|
-
const fullName = new
|
|
93
|
+
const fullName = new And("full-name", [firstName, lastName]);
|
|
104
94
|
const clone = fullName.clone("full-name-2");
|
|
105
95
|
|
|
106
96
|
const fullNamePatterns = fullName.children;
|
|
@@ -113,57 +103,57 @@ describe("AndValue", () => {
|
|
|
113
103
|
|
|
114
104
|
test("Partial Match.", () => {
|
|
115
105
|
const firstName = new Literal("first-name", "John");
|
|
116
|
-
const lastName = new Literal("last-name", "Doe");
|
|
117
|
-
const fullName = new
|
|
106
|
+
const lastName = new Literal("last-name", "Doe", true);
|
|
107
|
+
const fullName = new And("full-name", [
|
|
118
108
|
firstName,
|
|
119
|
-
|
|
109
|
+
lastName,
|
|
120
110
|
]);
|
|
121
111
|
const result = fullName.parse(new Cursor("JohnBo"));
|
|
122
112
|
|
|
123
|
-
expect(result?.type).toBe("and
|
|
113
|
+
expect(result?.type).toBe("and");
|
|
124
114
|
expect(result?.name).toBe("full-name");
|
|
125
115
|
expect(result?.value).toBe("John");
|
|
126
116
|
});
|
|
127
117
|
|
|
128
118
|
test("Partial Match with string running out, and optional last name.", () => {
|
|
129
119
|
const firstName = new Literal("first-name", "John");
|
|
130
|
-
const lastName = new Literal("last-name", "Doe");
|
|
131
|
-
const fullName = new
|
|
120
|
+
const lastName = new Literal("last-name", "Doe", true);
|
|
121
|
+
const fullName = new And("full-name", [
|
|
132
122
|
firstName,
|
|
133
|
-
|
|
123
|
+
lastName,
|
|
134
124
|
]);
|
|
135
125
|
const result = fullName.parse(new Cursor("JohnDo"));
|
|
136
126
|
|
|
137
|
-
expect(result?.type).toBe("and
|
|
127
|
+
expect(result?.type).toBe("and");
|
|
138
128
|
expect(result?.name).toBe("full-name");
|
|
139
129
|
expect(result?.value).toBe("John");
|
|
140
130
|
});
|
|
141
131
|
|
|
142
132
|
test("Three parts first optional.", () => {
|
|
143
|
-
const firstName = new Literal("first-name", "John");
|
|
133
|
+
const firstName = new Literal("first-name", "John", true);
|
|
144
134
|
const middle = new Literal("middle", "Smith");
|
|
145
135
|
const lastName = new Literal("last-name", "Doe");
|
|
146
136
|
|
|
147
|
-
const fullName = new
|
|
148
|
-
|
|
137
|
+
const fullName = new And("full-name", [
|
|
138
|
+
firstName,
|
|
149
139
|
middle,
|
|
150
140
|
lastName,
|
|
151
141
|
]);
|
|
152
142
|
const result = fullName.parse(new Cursor("SmithDoe"));
|
|
153
143
|
|
|
154
144
|
expect(result?.value).toBe("SmithDoe");
|
|
155
|
-
expect(result?.type).toBe("and
|
|
145
|
+
expect(result?.type).toBe("and");
|
|
156
146
|
expect(result?.name).toBe("full-name");
|
|
157
147
|
});
|
|
158
148
|
|
|
159
149
|
test("Three parts middle optional.", () => {
|
|
160
150
|
const firstName = new Literal("first-name", "John");
|
|
161
|
-
const middle = new Literal("middle", "Smith");
|
|
151
|
+
const middle = new Literal("middle", "Smith", true);
|
|
162
152
|
const lastName = new Literal("last-name", "Doe");
|
|
163
153
|
|
|
164
|
-
const fullName = new
|
|
154
|
+
const fullName = new And("full-name", [
|
|
165
155
|
firstName,
|
|
166
|
-
|
|
156
|
+
middle,
|
|
167
157
|
lastName,
|
|
168
158
|
]);
|
|
169
159
|
const result = fullName.parse(new Cursor("JohnDo"));
|
|
@@ -174,17 +164,17 @@ describe("AndValue", () => {
|
|
|
174
164
|
test("Three parts third optional.", () => {
|
|
175
165
|
const firstName = new Literal("first-name", "John");
|
|
176
166
|
const middle = new Literal("middle", "Smith");
|
|
177
|
-
const lastName = new Literal("last-name", "Doe");
|
|
167
|
+
const lastName = new Literal("last-name", "Doe", true);
|
|
178
168
|
|
|
179
|
-
const fullName = new
|
|
169
|
+
const fullName = new And("full-name", [
|
|
180
170
|
firstName,
|
|
181
171
|
middle,
|
|
182
|
-
|
|
172
|
+
lastName,
|
|
183
173
|
]);
|
|
184
174
|
const result = fullName.parse(new Cursor("JohnSmith"));
|
|
185
175
|
|
|
186
176
|
expect(result?.value).toBe("JohnSmith");
|
|
187
|
-
expect(result?.type).toBe("and
|
|
177
|
+
expect(result?.type).toBe("and");
|
|
188
178
|
expect(result?.name).toBe("full-name");
|
|
189
179
|
});
|
|
190
180
|
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/** @jest-environment node */
|
|
2
2
|
import CursorHistory from "../CursorHistory";
|
|
3
|
-
import { Literal,
|
|
3
|
+
import { Literal, Node, Cursor, ParseError } from "../index";
|
|
4
4
|
import sentence from "./patterns/sentence";
|
|
5
5
|
describe("CursorHistory", () => {
|
|
6
6
|
test("addMatch", () => {
|
|
7
7
|
const cursorHistory = new CursorHistory();
|
|
8
8
|
const pattern = new Literal("T", "T");
|
|
9
|
-
const node = new
|
|
9
|
+
const node = new Node("T", "T", 0, 1, [], "T");
|
|
10
10
|
|
|
11
11
|
cursorHistory.addMatch(pattern, node);
|
|
12
12
|
expect(cursorHistory.getFurthestMatch().pattern).toBe(pattern);
|
|
@@ -16,7 +16,7 @@ describe("CursorHistory", () => {
|
|
|
16
16
|
test("addMatch with Recording", () => {
|
|
17
17
|
const cursorHistory = new CursorHistory();
|
|
18
18
|
const pattern = new Literal("T", "T");
|
|
19
|
-
const node = new
|
|
19
|
+
const node = new Node("T", "T", 0, 1, [], "T");
|
|
20
20
|
|
|
21
21
|
cursorHistory.startRecording();
|
|
22
22
|
cursorHistory.addMatch(pattern, node);
|
|
@@ -98,10 +98,10 @@ describe("CursorHistory", () => {
|
|
|
98
98
|
const stack = cursor.history.getLastParseStack();
|
|
99
99
|
|
|
100
100
|
expect(stack.length).toBe(5);
|
|
101
|
-
expect(stack[0].name).toBe("
|
|
101
|
+
expect(stack[0].name).toBe("noun");
|
|
102
102
|
expect(stack[1].name).toBe("space");
|
|
103
|
-
expect(stack[2].name).toBe("
|
|
103
|
+
expect(stack[2].name).toBe("verb");
|
|
104
104
|
expect(stack[3].name).toBe("space");
|
|
105
|
-
expect(stack[4].name).toBe("
|
|
105
|
+
expect(stack[4].name).toBe("article");
|
|
106
106
|
});
|
|
107
107
|
});
|
package/src/tests/Cusor.test.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
/** @jest-environment node */
|
|
2
|
-
import Cursor from "../
|
|
3
|
-
import ValueNode from "../ast/ValueNode";
|
|
4
|
-
import Literal from "../patterns/value/Literal";
|
|
5
|
-
import ParseError from "../patterns/ParseError";
|
|
2
|
+
import { Cursor, Literal, ParseError, Node } from "../index";
|
|
6
3
|
|
|
7
4
|
describe("Cursor", () => {
|
|
8
5
|
test("addMatch.", () => {
|
|
9
6
|
const cursor = new Cursor("Text");
|
|
10
|
-
const node = new
|
|
7
|
+
const node = new Node("text-node", "Text", 0, 3, [], "Text");
|
|
11
8
|
const pattern = new Literal("text", "Text");
|
|
12
9
|
|
|
13
10
|
cursor.setIndex(3);
|
|
@@ -19,10 +16,10 @@ describe("Cursor", () => {
|
|
|
19
16
|
|
|
20
17
|
test("addMatch that isn't as far.", () => {
|
|
21
18
|
const cursor = new Cursor("Text");
|
|
22
|
-
const node = new
|
|
19
|
+
const node = new Node("text-node", "Text", 0, 3, [], "Text");
|
|
23
20
|
const pattern = new Literal("text", "Text Node");
|
|
24
21
|
|
|
25
|
-
const shorterNode = new
|
|
22
|
+
const shorterNode = new Node("tex-node", "Tex", 0, 2, [], "Tex2");
|
|
26
23
|
const shorterPattern = new Literal("tex", "Tex");
|
|
27
24
|
|
|
28
25
|
cursor.setIndex(3);
|
|
@@ -80,13 +77,13 @@ describe("Cursor", () => {
|
|
|
80
77
|
|
|
81
78
|
test("recording history.", () => {
|
|
82
79
|
const cursor = new Cursor("Text");
|
|
83
|
-
const tNode = new
|
|
80
|
+
const tNode = new Node("T", "T", 0, 0, [], "T");
|
|
84
81
|
const tPattern = new Literal("T", "T");
|
|
85
82
|
|
|
86
|
-
const eNode = new
|
|
83
|
+
const eNode = new Node("e", "e", 1, 1, [], "e");
|
|
87
84
|
const ePattern = new Literal("e", "e");
|
|
88
85
|
|
|
89
|
-
const xNode = new
|
|
86
|
+
const xNode = new Node("x", "x", 2, 2, [], "x");
|
|
90
87
|
const xPattern = new Literal("x", "x");
|
|
91
88
|
|
|
92
89
|
cursor.startRecording();
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/** @jest-environment node */
|
|
2
|
-
import Literal from "../
|
|
3
|
-
import Cursor from "../Cursor";
|
|
2
|
+
import { Literal, Cursor } from "../index";
|
|
4
3
|
|
|
5
4
|
describe("Literal", () => {
|
|
6
5
|
test("Empty literal.", () => {
|
|
@@ -16,13 +15,12 @@ describe("Literal", () => {
|
|
|
16
15
|
const result2 = john.exec("Jane");
|
|
17
16
|
|
|
18
17
|
const expectedValue = {
|
|
19
|
-
children: [],
|
|
20
|
-
value: "John",
|
|
21
18
|
type: "literal",
|
|
22
19
|
name: "john",
|
|
23
20
|
startIndex: 0,
|
|
24
21
|
endIndex: 3,
|
|
25
|
-
|
|
22
|
+
children: [],
|
|
23
|
+
value: "John",
|
|
26
24
|
};
|
|
27
25
|
|
|
28
26
|
expect(JSON.stringify(result)).toBe(JSON.stringify(expectedValue));
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
/** @jest-environment node */
|
|
2
|
-
import Literal from "../
|
|
3
|
-
import Cursor from "../Cursor";
|
|
4
|
-
import LookAhead from "../patterns/LookAhead";
|
|
5
|
-
import NotValue from "../patterns/value/NotValue";
|
|
6
|
-
import OrValue from "../patterns/value/OrValue";
|
|
7
|
-
import RegexValue from "../patterns/value/RegexValue";
|
|
8
|
-
import AndValue from "../patterns/value/AndValue";
|
|
2
|
+
import { Literal, Cursor, LookAhead, Not } from "../index";
|
|
9
3
|
|
|
10
4
|
describe("LookAheadValue", () => {
|
|
11
5
|
test("Look for pattern.", () => {
|
|
@@ -20,7 +14,7 @@ describe("LookAheadValue", () => {
|
|
|
20
14
|
|
|
21
15
|
test("Look for a not pattern.", () => {
|
|
22
16
|
const john = new Literal("john", "John");
|
|
23
|
-
const lookAheadValue = new
|
|
17
|
+
const lookAheadValue = new Not(new LookAhead(john));
|
|
24
18
|
const cursor = new Cursor("Joel");
|
|
25
19
|
const node = lookAheadValue.parse(cursor);
|
|
26
20
|
|
|
@@ -47,47 +41,4 @@ describe("LookAheadValue", () => {
|
|
|
47
41
|
expect(node).toBe(null);
|
|
48
42
|
expect(cursor.hasUnresolvedError()).toBe(true);
|
|
49
43
|
});
|
|
50
|
-
|
|
51
|
-
test("Negate pattern with literal.", () => {
|
|
52
|
-
const greaterThan = new Literal("greater-than", ">");
|
|
53
|
-
const lessThan = new Literal("less-than", "<");
|
|
54
|
-
const from = new Literal("from", "FROM");
|
|
55
|
-
const table = new Literal("table", "Table");
|
|
56
|
-
const operator = new OrValue("operator", [lessThan, greaterThan]);
|
|
57
|
-
const keywords = new AndValue("keywords-with-space", [
|
|
58
|
-
new OrValue("keywords", [from, table]),
|
|
59
|
-
new Literal("space", " "),
|
|
60
|
-
]);
|
|
61
|
-
const identFirstPart = new RegexValue(
|
|
62
|
-
"ident-first-part",
|
|
63
|
-
"[a-zA-Z_$][a-zA-Z0-9_]*"
|
|
64
|
-
);
|
|
65
|
-
const identity = new AndValue("identity", [
|
|
66
|
-
new LookAhead(new NotValue("not-keywords", keywords)),
|
|
67
|
-
new LookAhead(new NotValue("not-operator", operator)),
|
|
68
|
-
identFirstPart,
|
|
69
|
-
]);
|
|
70
|
-
|
|
71
|
-
const result = identity.parse(new Cursor("_goodName"));
|
|
72
|
-
|
|
73
|
-
expect(result).not.toBeNull();
|
|
74
|
-
|
|
75
|
-
const cursor1 = new Cursor("<badName");
|
|
76
|
-
const result1 = identity.parse(cursor1);
|
|
77
|
-
|
|
78
|
-
expect(result1).toBe(null);
|
|
79
|
-
expect(cursor1.hasUnresolvedError()).toBe(true);
|
|
80
|
-
|
|
81
|
-
const cursor2 = new Cursor("FROM_IS_OKAY");
|
|
82
|
-
const result2 = identity.parse(cursor2);
|
|
83
|
-
|
|
84
|
-
expect(result2).not.toBe(null);
|
|
85
|
-
expect(cursor2.hasUnresolvedError()).toBe(false);
|
|
86
|
-
|
|
87
|
-
const cursor3 = new Cursor("FROM ISBAD");
|
|
88
|
-
const result3 = identity.parse(cursor3);
|
|
89
|
-
|
|
90
|
-
expect(result3).toBe(null);
|
|
91
|
-
expect(cursor3.hasUnresolvedError()).toBe(true);
|
|
92
|
-
});
|
|
93
44
|
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import Cursor from "../Cursor";
|
|
2
|
+
import And from "../patterns/And";
|
|
3
|
+
import Literal from "../patterns/Literal";
|
|
4
|
+
import Not from "../patterns/Not";
|
|
5
|
+
import Or from "../patterns/Or";
|
|
6
|
+
import Regex from "../patterns/Regex";
|
|
7
|
+
|
|
8
|
+
describe("Not", () => {
|
|
9
|
+
test("Negate pattern with literal.", () => {
|
|
10
|
+
const greaterThan = new Literal("greater-than", ">");
|
|
11
|
+
const lessThan = new Literal("less-than", "<");
|
|
12
|
+
const from = new Literal("from", "FROM");
|
|
13
|
+
const table = new Literal("table", "Table");
|
|
14
|
+
const operator = new Or("operator", [lessThan, greaterThan]);
|
|
15
|
+
const keywords = new And("keywords-with-space", [
|
|
16
|
+
new Or("keywords", [from, table]),
|
|
17
|
+
new Literal("space", " "),
|
|
18
|
+
]);
|
|
19
|
+
const identFirstPart = new Regex(
|
|
20
|
+
"ident-first-part",
|
|
21
|
+
"[a-zA-Z_$][a-zA-Z0-9_]*"
|
|
22
|
+
);
|
|
23
|
+
const identity = new And("identity", [
|
|
24
|
+
new Not(keywords),
|
|
25
|
+
new Not(operator),
|
|
26
|
+
identFirstPart,
|
|
27
|
+
]);
|
|
28
|
+
|
|
29
|
+
const result = identity.parse(new Cursor("_goodName"));
|
|
30
|
+
|
|
31
|
+
expect(result).not.toBeNull();
|
|
32
|
+
|
|
33
|
+
const cursor1 = new Cursor("<badName");
|
|
34
|
+
const result1 = identity.parse(cursor1);
|
|
35
|
+
|
|
36
|
+
expect(result1).toBe(null);
|
|
37
|
+
expect(cursor1.hasUnresolvedError()).toBe(true);
|
|
38
|
+
|
|
39
|
+
const cursor2 = new Cursor("FROM_IS_OKAY");
|
|
40
|
+
const result2 = identity.parse(cursor2);
|
|
41
|
+
|
|
42
|
+
expect(result2).not.toBe(null);
|
|
43
|
+
expect(cursor2.hasUnresolvedError()).toBe(false);
|
|
44
|
+
|
|
45
|
+
const cursor3 = new Cursor("FROM ISBAD");
|
|
46
|
+
const result3 = identity.parse(cursor3);
|
|
47
|
+
|
|
48
|
+
expect(result3).toBe(null);
|
|
49
|
+
expect(cursor3.hasUnresolvedError()).toBe(true);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/** @jest-environment node */
|
|
2
|
+
import Or from "../patterns/Or";
|
|
3
|
+
import Literal from "../patterns/Literal";
|
|
4
|
+
import Cursor from "../Cursor";
|
|
5
|
+
|
|
6
|
+
describe("Or", () => {
|
|
7
|
+
test("Or: Empty array parser.", () => {
|
|
8
|
+
expect(() => {
|
|
9
|
+
new Or("name", []);
|
|
10
|
+
}).toThrow();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test("Or: One Pattern.", () => {
|
|
14
|
+
expect(() => {
|
|
15
|
+
new Or("name", [new Literal("some-value", "")]);
|
|
16
|
+
}).toThrow();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test("Or: Name and patterns.", () => {
|
|
20
|
+
const letter = new Literal("a", "a");
|
|
21
|
+
const number = new Literal("1", "1");
|
|
22
|
+
const alphaNumeric = new Or("alpha-numeric", [letter, number]);
|
|
23
|
+
|
|
24
|
+
const letterCursor = new Cursor("a");
|
|
25
|
+
const numberCursor = new Cursor("1");
|
|
26
|
+
|
|
27
|
+
const letterNode = alphaNumeric.parse(letterCursor);
|
|
28
|
+
const numberNode = alphaNumeric.parse(numberCursor);
|
|
29
|
+
|
|
30
|
+
expect(letterNode?.name).toBe("alpha-numeric");
|
|
31
|
+
expect(letterNode?.value).toBe("a");
|
|
32
|
+
|
|
33
|
+
expect(numberNode?.name).toBe("alpha-numeric");
|
|
34
|
+
expect(numberNode?.value).toBe("1");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("Or: Fail.", () => {
|
|
38
|
+
const letter = new Literal("a", "a");
|
|
39
|
+
const number = new Literal("1", "1");
|
|
40
|
+
const alphaNumeric = new Or("alpha-numeric", [letter, number]);
|
|
41
|
+
|
|
42
|
+
const letterCursor = new Cursor("b");
|
|
43
|
+
const numberCursor = new Cursor("2");
|
|
44
|
+
|
|
45
|
+
const letterNode = alphaNumeric.parse(letterCursor);
|
|
46
|
+
const numberNode = alphaNumeric.parse(numberCursor);
|
|
47
|
+
|
|
48
|
+
expect(letterNode).toBe(null);
|
|
49
|
+
expect(numberNode).toBe(null);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("Or: Clone.", () => {
|
|
53
|
+
const letter = new Literal("a", "a");
|
|
54
|
+
const number = new Literal("1", "1");
|
|
55
|
+
const alphaNumeric = new Or("alpha-numeric", [letter, number]);
|
|
56
|
+
|
|
57
|
+
const clone = alphaNumeric.clone();
|
|
58
|
+
|
|
59
|
+
expect(alphaNumeric.children.length).toBe(clone.children.length);
|
|
60
|
+
expect(alphaNumeric.name).toBe(clone.name);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("Or: Invalid patterns.", () => {
|
|
64
|
+
expect(() => {
|
|
65
|
+
new (Or as any)("some-alpha-numeric", [{}, null]);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("Or: Not enough patterns.", () => {
|
|
70
|
+
expect(() => {
|
|
71
|
+
new (Or as any)("some-alpha-numeric", [{}]);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("Or: Bad name.", () => {
|
|
76
|
+
expect(() => {
|
|
77
|
+
new (Or as any)({}, [new Literal("a", "a"), new Literal("a", "a")]);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("Or: Bad cursor.", () => {
|
|
82
|
+
expect(() => {
|
|
83
|
+
new (Or as any)("A", [
|
|
84
|
+
new Literal("a", "a"),
|
|
85
|
+
new Literal("a", "a"),
|
|
86
|
+
]).parse();
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("Or: Furthest Parse Error.", () => {
|
|
91
|
+
const longer = new Literal("longer", "Longer");
|
|
92
|
+
const bang = new Literal("bang", "Bang");
|
|
93
|
+
const orValue = new (Or as any)("test", [longer, bang]);
|
|
94
|
+
const cursor = new Cursor("Longed");
|
|
95
|
+
|
|
96
|
+
orValue.parse(cursor);
|
|
97
|
+
|
|
98
|
+
expect(cursor.getIndex()).toBe(0);
|
|
99
|
+
expect(cursor.hasUnresolvedError()).toBe(true);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("Or: Last pattern matches.", () => {
|
|
103
|
+
const longer = new Literal("longer", "Longer");
|
|
104
|
+
const bang = new Literal("bang", "Bang");
|
|
105
|
+
const orValue = new (Or as any)("test", [longer, bang]);
|
|
106
|
+
const cursor = new Cursor("Bang");
|
|
107
|
+
|
|
108
|
+
const node = orValue.parse(cursor);
|
|
109
|
+
|
|
110
|
+
expect(node.name).toBe("test");
|
|
111
|
+
expect(node.value).toBe("Bang");
|
|
112
|
+
});
|
|
113
|
+
});
|