clarity-pattern-parser 3.0.15 → 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.
Files changed (168) hide show
  1. package/README.md +0 -191
  2. package/dist/ast/Node.d.ts +4 -5
  3. package/dist/index.browser.js +476 -731
  4. package/dist/index.browser.js.map +1 -1
  5. package/dist/index.d.ts +10 -18
  6. package/dist/index.esm.js +469 -716
  7. package/dist/index.esm.js.map +1 -1
  8. package/dist/index.js +476 -731
  9. package/dist/index.js.map +1 -1
  10. package/dist/patterns/And.d.ts +24 -0
  11. package/dist/patterns/Literal.d.ts +19 -0
  12. package/dist/patterns/LookAhead.d.ts +8 -0
  13. package/dist/patterns/Not.d.ts +11 -0
  14. package/dist/patterns/Or.d.ts +22 -0
  15. package/dist/patterns/Pattern.d.ts +6 -7
  16. package/dist/patterns/{RecursivePattern.d.ts → Recursive.d.ts} +4 -4
  17. package/dist/patterns/Reference.d.ts +14 -0
  18. package/dist/patterns/Regex.d.ts +21 -0
  19. package/dist/patterns/Repeat.d.ts +20 -0
  20. package/package.json +1 -1
  21. package/src/CursorHistory.ts +1 -1
  22. package/src/ast/Node.ts +20 -17
  23. package/src/ast/Visitor.ts +14 -18
  24. package/src/index.ts +17 -33
  25. package/src/patterns/And.ts +178 -0
  26. package/src/patterns/Literal.ts +91 -0
  27. package/src/patterns/LookAhead.ts +32 -0
  28. package/src/patterns/Not.ts +50 -0
  29. package/src/patterns/Or.ts +132 -0
  30. package/src/patterns/Pattern.ts +31 -47
  31. package/src/patterns/Recursive.ts +92 -0
  32. package/src/patterns/Reference.ts +127 -0
  33. package/src/patterns/Regex.ts +123 -0
  34. package/src/patterns/Repeat.ts +155 -0
  35. package/src/tests/{AndValue.test.ts → And.test.ts} +31 -41
  36. package/src/tests/CursorHistory.test.ts +6 -6
  37. package/src/tests/Cusor.test.ts +7 -10
  38. package/src/tests/Literal.test.ts +3 -5
  39. package/src/tests/LookAhead.test.ts +44 -0
  40. package/src/tests/Not.test.ts +51 -0
  41. package/src/tests/Or.test.ts +113 -0
  42. package/src/tests/Pattern.test.ts +41 -141
  43. package/src/tests/{RecursivePattern.test.ts → Recursive.test.ts} +10 -8
  44. package/src/tests/Reference.test.ts +16 -0
  45. package/src/tests/{RepeatValue.test.ts → Repeat.test.ts} +10 -42
  46. package/src/tests/TextSuggester.test.ts +20 -28
  47. package/src/tests/{NodeVisitor.test.ts → Visitor.test.ts} +42 -21
  48. package/src/tests/cssPatterns/cssValue.ts +2 -2
  49. package/src/tests/cssPatterns/divider.ts +2 -2
  50. package/src/tests/cssPatterns/hex.ts +2 -2
  51. package/src/tests/cssPatterns/method.ts +7 -9
  52. package/src/tests/cssPatterns/name.ts +2 -2
  53. package/src/tests/cssPatterns/number.ts +2 -2
  54. package/src/tests/cssPatterns/optionalSpaces.ts +1 -2
  55. package/src/tests/cssPatterns/spaces.ts +2 -2
  56. package/src/tests/cssPatterns/unit.ts +3 -3
  57. package/src/tests/cssPatterns/value.ts +2 -2
  58. package/src/tests/cssPatterns/values.ts +2 -2
  59. package/src/tests/htmlPatterns/element.ts +18 -33
  60. package/src/tests/javascriptPatterns/boolean.ts +2 -3
  61. package/src/tests/javascriptPatterns/json.ts +14 -24
  62. package/src/tests/javascriptPatterns/name.ts +3 -20
  63. package/src/tests/javascriptPatterns/number.ts +2 -2
  64. package/src/tests/javascriptPatterns/objectLiteral.ts +9 -16
  65. package/src/tests/javascriptPatterns/string.ts +26 -24
  66. package/src/tests/javascriptPatterns/unit.ts +3 -6
  67. package/src/tests/javascriptPatterns/whitespace.ts +8 -12
  68. package/src/tests/naturalLanguage/filter.ts +16 -33
  69. package/src/tests/patterns/sentence.ts +8 -8
  70. package/dist/Cursor.js +0 -105
  71. package/dist/Cursor.js.map +0 -1
  72. package/dist/CursorHistory.js +0 -104
  73. package/dist/CursorHistory.js.map +0 -1
  74. package/dist/Permutor.d.ts +0 -13
  75. package/dist/Permutor.js +0 -52
  76. package/dist/Permutor.js.map +0 -1
  77. package/dist/TextSuggester.js +0 -244
  78. package/dist/TextSuggester.js.map +0 -1
  79. package/dist/ast/CompositeNode.d.ts +0 -6
  80. package/dist/ast/CompositeNode.js +0 -17
  81. package/dist/ast/CompositeNode.js.map +0 -1
  82. package/dist/ast/Node.js +0 -16
  83. package/dist/ast/Node.js.map +0 -1
  84. package/dist/ast/NodeVisitor.d.ts +0 -31
  85. package/dist/ast/ValueNode.d.ts +0 -6
  86. package/dist/ast/ValueNode.js +0 -14
  87. package/dist/ast/ValueNode.js.map +0 -1
  88. package/dist/ast/Visitor.js +0 -209
  89. package/dist/ast/Visitor.js.map +0 -1
  90. package/dist/patterns/ParseError.js +0 -9
  91. package/dist/patterns/ParseError.js.map +0 -1
  92. package/dist/patterns/Pattern.js +0 -127
  93. package/dist/patterns/Pattern.js.map +0 -1
  94. package/dist/patterns/RecursivePattern.js +0 -65
  95. package/dist/patterns/RecursivePattern.js.map +0 -1
  96. package/dist/patterns/composite/AndComposite.d.ts +0 -22
  97. package/dist/patterns/composite/AndComposite.js +0 -117
  98. package/dist/patterns/composite/AndComposite.js.map +0 -1
  99. package/dist/patterns/composite/CompositePattern.d.ts +0 -4
  100. package/dist/patterns/composite/CompositePattern.js +0 -7
  101. package/dist/patterns/composite/CompositePattern.js.map +0 -1
  102. package/dist/patterns/composite/OptionalComposite.d.ts +0 -10
  103. package/dist/patterns/composite/OptionalComposite.js +0 -29
  104. package/dist/patterns/composite/OptionalComposite.js.map +0 -1
  105. package/dist/patterns/composite/OrComposite.d.ts +0 -16
  106. package/dist/patterns/composite/OrComposite.js +0 -69
  107. package/dist/patterns/composite/OrComposite.js.map +0 -1
  108. package/dist/patterns/composite/RepeatComposite.d.ts +0 -21
  109. package/dist/patterns/composite/RepeatComposite.js +0 -88
  110. package/dist/patterns/composite/RepeatComposite.js.map +0 -1
  111. package/dist/patterns/value/AndValue.d.ts +0 -21
  112. package/dist/patterns/value/AndValue.js +0 -118
  113. package/dist/patterns/value/AndValue.js.map +0 -1
  114. package/dist/patterns/value/AnyOfThese.d.ts +0 -18
  115. package/dist/patterns/value/AnyOfThese.js +0 -59
  116. package/dist/patterns/value/AnyOfThese.js.map +0 -1
  117. package/dist/patterns/value/Literal.d.ts +0 -20
  118. package/dist/patterns/value/Literal.js +0 -63
  119. package/dist/patterns/value/Literal.js.map +0 -1
  120. package/dist/patterns/value/NotValue.d.ts +0 -17
  121. package/dist/patterns/value/NotValue.js +0 -70
  122. package/dist/patterns/value/NotValue.js.map +0 -1
  123. package/dist/patterns/value/OptionalValue.d.ts +0 -9
  124. package/dist/patterns/value/OptionalValue.js +0 -32
  125. package/dist/patterns/value/OptionalValue.js.map +0 -1
  126. package/dist/patterns/value/OrValue.d.ts +0 -19
  127. package/dist/patterns/value/OrValue.js +0 -73
  128. package/dist/patterns/value/OrValue.js.map +0 -1
  129. package/dist/patterns/value/RegexValue.d.ts +0 -19
  130. package/dist/patterns/value/RegexValue.js +0 -69
  131. package/dist/patterns/value/RegexValue.js.map +0 -1
  132. package/dist/patterns/value/RepeatValue.d.ts +0 -19
  133. package/dist/patterns/value/RepeatValue.js +0 -89
  134. package/dist/patterns/value/RepeatValue.js.map +0 -1
  135. package/dist/patterns/value/ValuePattern.d.ts +0 -5
  136. package/dist/patterns/value/ValuePattern.js +0 -7
  137. package/dist/patterns/value/ValuePattern.js.map +0 -1
  138. package/src/Permutor.ts +0 -64
  139. package/src/ast/CompositeNode.ts +0 -26
  140. package/src/ast/ValueNode.ts +0 -28
  141. package/src/patterns/RecursivePattern.ts +0 -86
  142. package/src/patterns/composite/AndComposite.ts +0 -159
  143. package/src/patterns/composite/CompositePattern.ts +0 -7
  144. package/src/patterns/composite/OptionalComposite.ts +0 -37
  145. package/src/patterns/composite/OrComposite.ts +0 -96
  146. package/src/patterns/composite/RepeatComposite.ts +0 -130
  147. package/src/patterns/value/AndValue.ts +0 -153
  148. package/src/patterns/value/AnyOfThese.ts +0 -81
  149. package/src/patterns/value/Literal.ts +0 -92
  150. package/src/patterns/value/NotValue.ts +0 -95
  151. package/src/patterns/value/OptionalValue.ts +0 -39
  152. package/src/patterns/value/OrValue.ts +0 -103
  153. package/src/patterns/value/RegexValue.ts +0 -103
  154. package/src/patterns/value/RepeatValue.ts +0 -131
  155. package/src/patterns/value/ValuePattern.ts +0 -8
  156. package/src/tests/AndComposite.test.ts +0 -102
  157. package/src/tests/AnyOfThese.test.ts +0 -74
  158. package/src/tests/CompositeNode.test.ts +0 -33
  159. package/src/tests/NotValue.test.ts +0 -69
  160. package/src/tests/OptionalValue.test.ts +0 -50
  161. package/src/tests/OrComposite.test.ts +0 -75
  162. package/src/tests/OrValue.test.ts +0 -171
  163. package/src/tests/Permutor.test.ts +0 -30
  164. package/src/tests/RegexValue.test.ts +0 -22
  165. package/src/tests/RepeatComposite.test.ts +0 -58
  166. package/src/tests/ValueNode.test.ts +0 -24
  167. package/src/tests/javascriptPatterns/varStatement.ts +0 -0
  168. 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 AndValue from "../patterns/value/AndValue";
3
- import Literal from "../patterns/value/Literal";
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("AndValue", () => {
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 AndValue("full-name", [firstName, lastName]);
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 AndValue("full-name", [
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 AndValue("full-name", [firstName, lastName]);
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 AndValue("full-name", [firstName, lastName]);
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 AndValue("full-name", [firstName, lastName]);
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 AndValue("full-name", [firstName, lastName]);
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 AndValue("full-name", [firstName, lastName]);
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 AndValue("full-name", [firstName, lastName]);
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 AndValue("full-name", [
106
+ const lastName = new Literal("last-name", "Doe", true);
107
+ const fullName = new And("full-name", [
118
108
  firstName,
119
- new OptionalValue(lastName),
109
+ lastName,
120
110
  ]);
121
111
  const result = fullName.parse(new Cursor("JohnBo"));
122
112
 
123
- expect(result?.type).toBe("and-value");
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 AndValue("full-name", [
120
+ const lastName = new Literal("last-name", "Doe", true);
121
+ const fullName = new And("full-name", [
132
122
  firstName,
133
- new OptionalValue(lastName),
123
+ lastName,
134
124
  ]);
135
125
  const result = fullName.parse(new Cursor("JohnDo"));
136
126
 
137
- expect(result?.type).toBe("and-value");
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 AndValue("full-name", [
148
- new OptionalValue(firstName),
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-value");
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 AndValue("full-name", [
154
+ const fullName = new And("full-name", [
165
155
  firstName,
166
- new OptionalValue(middle),
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 AndValue("full-name", [
169
+ const fullName = new And("full-name", [
180
170
  firstName,
181
171
  middle,
182
- new OptionalValue(lastName),
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-value");
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, ValueNode, Cursor, ParseError } from "../index";
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 ValueNode("T", "T", "T", 0, 1);
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 ValueNode("T", "T", "T", 0, 1);
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("pat");
101
+ expect(stack[0].name).toBe("noun");
102
102
  expect(stack[1].name).toBe("space");
103
- expect(stack[2].name).toBe("went-to");
103
+ expect(stack[2].name).toBe("verb");
104
104
  expect(stack[3].name).toBe("space");
105
- expect(stack[4].name).toBe("the");
105
+ expect(stack[4].name).toBe("article");
106
106
  });
107
107
  });
@@ -1,13 +1,10 @@
1
1
  /** @jest-environment node */
2
- import Cursor from "../Cursor";
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 ValueNode("text-node", "Text", "Text", 0, 3);
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 ValueNode("text-node", "Text", "Text", 0, 3);
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 ValueNode("tex-node", "Tex", "Tex", 0, 2);
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 ValueNode("T", "T", "T", 0, 0);
80
+ const tNode = new Node("T", "T", 0, 0, [], "T");
84
81
  const tPattern = new Literal("T", "T");
85
82
 
86
- const eNode = new ValueNode("e", "e", "e", 1, 1);
83
+ const eNode = new Node("e", "e", 1, 1, [], "e");
87
84
  const ePattern = new Literal("e", "e");
88
85
 
89
- const xNode = new ValueNode("x", "x", "x", 2, 2);
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 "../patterns/value/Literal";
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
- isComposite: false,
22
+ children: [],
23
+ value: "John",
26
24
  };
27
25
 
28
26
  expect(JSON.stringify(result)).toBe(JSON.stringify(expectedValue));
@@ -0,0 +1,44 @@
1
+ /** @jest-environment node */
2
+ import { Literal, Cursor, LookAhead, Not } from "../index";
3
+
4
+ describe("LookAheadValue", () => {
5
+ test("Look for pattern.", () => {
6
+ const john = new Literal("john", "John");
7
+ const lookAheadValue = new LookAhead(john);
8
+ const cursor = new Cursor("John");
9
+ const node = lookAheadValue.parse(cursor);
10
+
11
+ expect(node).toBe(null);
12
+ expect(cursor.hasUnresolvedError()).toBe(false);
13
+ });
14
+
15
+ test("Look for a not pattern.", () => {
16
+ const john = new Literal("john", "John");
17
+ const lookAheadValue = new Not(new LookAhead(john));
18
+ const cursor = new Cursor("Joel");
19
+ const node = lookAheadValue.parse(cursor);
20
+
21
+ expect(node).toBe(null);
22
+ expect(cursor.hasUnresolvedError()).toBe(false);
23
+ });
24
+
25
+ test("Fail looking for a pattern.", () => {
26
+ const john = new Literal("john", "John");
27
+ const lookAheadValue = new LookAhead(john);
28
+ const cursor = new Cursor("Joel");
29
+ const node = lookAheadValue.parse(cursor);
30
+
31
+ expect(node).toBe(null);
32
+ expect(cursor.hasUnresolvedError()).toBe(true);
33
+ });
34
+
35
+ test("And a look ahead together.", () => {
36
+ const john = new Literal("john", "John");
37
+ const lookAheadValue = new LookAhead(john);
38
+ const cursor = new Cursor("Joel");
39
+ const node = lookAheadValue.parse(cursor);
40
+
41
+ expect(node).toBe(null);
42
+ expect(cursor.hasUnresolvedError()).toBe(true);
43
+ });
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
+ });