clarity-pattern-parser 4.0.3 → 6.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 (133) hide show
  1. package/README.md +466 -1
  2. package/TODO.md +76 -2
  3. package/dist/ast/Node.d.ts +49 -11
  4. package/dist/ast/Visitor.d.ts +31 -31
  5. package/dist/index.browser.js +1513 -1495
  6. package/dist/index.browser.js.map +1 -1
  7. package/dist/index.d.ts +17 -17
  8. package/dist/index.esm.js +1480 -1459
  9. package/dist/index.esm.js.map +1 -1
  10. package/dist/index.js +1481 -1463
  11. package/dist/index.js.map +1 -1
  12. package/dist/intellisense/AutoComplete.d.ts +28 -0
  13. package/dist/intellisense/Suggestion.d.ts +11 -0
  14. package/dist/intellisense/SuggestionOption.d.ts +4 -0
  15. package/dist/patterns/And.d.ts +37 -24
  16. package/dist/patterns/Cursor.d.ts +37 -0
  17. package/dist/patterns/CursorHistory.d.ts +30 -0
  18. package/dist/patterns/Literal.d.ts +35 -19
  19. package/dist/patterns/Not.d.ts +29 -11
  20. package/dist/patterns/Or.d.ts +33 -22
  21. package/dist/patterns/ParseError.d.ts +6 -8
  22. package/dist/patterns/ParseResult.d.ts +6 -0
  23. package/dist/patterns/Pattern.d.ts +20 -26
  24. package/dist/patterns/Reference.d.ts +34 -12
  25. package/dist/patterns/Regex.d.ts +41 -21
  26. package/dist/patterns/Repeat.d.ts +38 -20
  27. package/dist/patterns/clonePatterns.d.ts +2 -0
  28. package/dist/patterns/filterOutNull.d.ts +2 -0
  29. package/dist/patterns/findPattern.d.ts +2 -0
  30. package/dist/patterns/getNextPattern.d.ts +2 -0
  31. package/jest.config.js +2 -1
  32. package/package.json +4 -5
  33. package/rollup.config.js +1 -1
  34. package/src/ast/Node.test.ts +364 -0
  35. package/src/ast/Node.ts +237 -23
  36. package/src/index.ts +25 -27
  37. package/src/intellisense/AutoComplete.test.ts +150 -0
  38. package/src/intellisense/AutoComplete.ts +200 -0
  39. package/src/intellisense/Suggestion.ts +12 -0
  40. package/src/intellisense/SuggestionOption.ts +4 -0
  41. package/src/{tests/cssPatterns → intellisense/css}/cssValue.ts +1 -1
  42. package/src/{tests/cssPatterns → intellisense/css}/divider.ts +2 -1
  43. package/src/intellisense/css/hex.ts +6 -0
  44. package/src/{tests/cssPatterns → intellisense/css}/method.ts +8 -9
  45. package/src/intellisense/css/name.ts +5 -0
  46. package/src/{tests/javascriptPatterns → intellisense/css}/number.ts +3 -3
  47. package/src/intellisense/css/spaces.ts +6 -0
  48. package/src/intellisense/css/unit.ts +10 -0
  49. package/src/{tests/cssPatterns → intellisense/css}/value.ts +1 -1
  50. package/src/{tests/cssPatterns → intellisense/css}/values.ts +1 -1
  51. package/src/intellisense/javascript/Javascript.test.ts +203 -0
  52. package/src/intellisense/javascript/arrayLiteral.ts +25 -0
  53. package/src/intellisense/javascript/deleteStatement.ts +14 -0
  54. package/src/intellisense/javascript/escapedCharacter.ts +49 -0
  55. package/src/intellisense/javascript/exponent.ts +24 -0
  56. package/src/intellisense/javascript/expression.ts +87 -0
  57. package/src/intellisense/javascript/expressionStatement.ts +29 -0
  58. package/src/intellisense/javascript/fraction.ts +11 -0
  59. package/src/intellisense/javascript/infixOperator.ts +36 -0
  60. package/src/intellisense/javascript/integer.ts +7 -0
  61. package/src/intellisense/javascript/invocation.ts +28 -0
  62. package/src/intellisense/javascript/literal.ts +14 -0
  63. package/src/intellisense/javascript/name.ts +3 -0
  64. package/src/intellisense/javascript/numberLiteral.ts +10 -0
  65. package/src/intellisense/javascript/objectLiteral.ts +30 -0
  66. package/src/intellisense/javascript/optionalSpaces.ts +3 -0
  67. package/src/intellisense/javascript/parameters.ts +20 -0
  68. package/src/intellisense/javascript/prefixOperator.ts +13 -0
  69. package/src/intellisense/javascript/propertyAccess.ts +23 -0
  70. package/src/intellisense/javascript/stringLiteral.ts +28 -0
  71. package/src/patterns/And.test.ts +310 -0
  72. package/src/patterns/And.ts +244 -119
  73. package/src/patterns/Cursor.test.ts +93 -0
  74. package/src/patterns/Cursor.ts +133 -0
  75. package/src/patterns/CursorHistory.test.ts +54 -0
  76. package/src/patterns/CursorHistory.ts +95 -0
  77. package/src/patterns/Literal.test.ts +166 -0
  78. package/src/patterns/Literal.ts +141 -62
  79. package/src/patterns/Not.test.ts +168 -0
  80. package/src/patterns/Not.ts +113 -32
  81. package/src/patterns/Or.test.ts +209 -0
  82. package/src/patterns/Or.ts +128 -97
  83. package/src/patterns/ParseError.ts +3 -7
  84. package/src/patterns/ParseResult.ts +7 -0
  85. package/src/patterns/Pattern.ts +21 -150
  86. package/src/patterns/Reference.test.ts +193 -0
  87. package/src/patterns/Reference.ts +114 -88
  88. package/src/patterns/Regex.test.ts +133 -0
  89. package/src/patterns/Regex.ts +117 -60
  90. package/src/patterns/Repeat.test.ts +218 -0
  91. package/src/patterns/Repeat.ts +220 -103
  92. package/src/patterns/clonePatterns.ts +5 -0
  93. package/src/patterns/filterOutNull.ts +13 -0
  94. package/src/patterns/findPattern.ts +25 -0
  95. package/src/Cursor.ts +0 -141
  96. package/src/CursorHistory.ts +0 -146
  97. package/src/TextSuggester.ts +0 -317
  98. package/src/ast/Visitor.ts +0 -271
  99. package/src/patterns/LookAhead.ts +0 -32
  100. package/src/patterns/Recursive.ts +0 -92
  101. package/src/tests/And.test.ts +0 -180
  102. package/src/tests/ComplexExamples.test.ts +0 -86
  103. package/src/tests/CssPatterns.test.ts +0 -90
  104. package/src/tests/CursorHistory.test.ts +0 -107
  105. package/src/tests/Cusor.test.ts +0 -174
  106. package/src/tests/HtmlPatterns.test.ts +0 -34
  107. package/src/tests/Literal.test.ts +0 -79
  108. package/src/tests/LookAhead.test.ts +0 -44
  109. package/src/tests/Not.test.ts +0 -51
  110. package/src/tests/Or.test.ts +0 -113
  111. package/src/tests/Pattern.test.ts +0 -290
  112. package/src/tests/Recursive.test.ts +0 -64
  113. package/src/tests/Reference.test.ts +0 -16
  114. package/src/tests/Repeat.test.ts +0 -75
  115. package/src/tests/SpeedTest.test.ts +0 -31
  116. package/src/tests/TextSuggester.test.ts +0 -297
  117. package/src/tests/Visitor.test.ts +0 -331
  118. package/src/tests/cssPatterns/hex.ts +0 -5
  119. package/src/tests/cssPatterns/name.ts +0 -5
  120. package/src/tests/cssPatterns/number.ts +0 -8
  121. package/src/tests/cssPatterns/spaces.ts +0 -5
  122. package/src/tests/cssPatterns/unit.ts +0 -8
  123. package/src/tests/htmlPatterns/element.ts +0 -49
  124. package/src/tests/javascriptPatterns/boolean.ts +0 -10
  125. package/src/tests/javascriptPatterns/json.ts +0 -67
  126. package/src/tests/javascriptPatterns/name.ts +0 -5
  127. package/src/tests/javascriptPatterns/objectLiteral.ts +0 -40
  128. package/src/tests/javascriptPatterns/string.ts +0 -84
  129. package/src/tests/javascriptPatterns/unit.ts +0 -8
  130. package/src/tests/javascriptPatterns/whitespace.ts +0 -44
  131. package/src/tests/naturalLanguage/filter.ts +0 -37
  132. package/src/tests/patterns/sentence.ts +0 -37
  133. /package/src/{tests/cssPatterns → intellisense/css}/optionalSpaces.ts +0 -0
@@ -0,0 +1,150 @@
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 { Regex } from "../patterns/Regex";
6
+ import { Repeat } from "../patterns/Repeat";
7
+ import { AutoComplete, AutoCompleteOptions } from "./AutoComplete";
8
+
9
+ describe("AutoComplete", () => {
10
+ test("No Text", () => {
11
+ const name = new Literal("name", "Name");
12
+ const autoComplete = new AutoComplete(name);
13
+ let result = autoComplete.suggest("");
14
+
15
+ expect(result.options[0].text).toBe("Name");
16
+ expect(result.options[0].startIndex).toBe(0);
17
+ expect(result.nextPatterns[0]).toBe(name);
18
+ expect(result.isComplete).toBeFalsy();
19
+ });
20
+
21
+ test("Full Pattern Match", () => {
22
+ const john = new Literal("john", "John");
23
+ const space = new Literal("space", " ");
24
+ const doe = new Literal("doe", "Doe");
25
+ const smith = new Literal("smith", "Smith");
26
+ const name = new And("name", [john, space, new Or("last-name", [smith, doe])]);
27
+
28
+ const autoComplete = new AutoComplete(name);
29
+ const result = autoComplete.suggest("John Doe");
30
+
31
+ expect(result.ast?.value).toBe("John Doe");
32
+ expect(result.options.length).toBe(0);
33
+ expect(result.nextPatterns.length).toBe(0);
34
+ expect(result.isComplete).toBeTruthy();
35
+ expect(result.cursor).not.toBeNull();
36
+ });
37
+
38
+ test("More Than One Option", () => {
39
+ const john = new Literal("john", "John");
40
+ const space = new Literal("space", " ");
41
+ const doe = new Literal("doe", "Doe");
42
+ const smith = new Literal("smith", "Smith");
43
+ const name = new And("name", [john, space, new Or("last-name", [smith, doe])]);
44
+
45
+ const autoComplete = new AutoComplete(name);
46
+ const result = autoComplete.suggest("John ");
47
+
48
+ expect(result.ast).toBeNull();
49
+ expect(result.options.length).toBe(2);
50
+ expect(result.nextPatterns.length).toBe(1);
51
+ expect(result.nextPatterns[0].type).toBe("or");
52
+ expect(result.nextPatterns[0].name).toBe("last-name");
53
+ expect(result.isComplete).toBeFalsy();
54
+ expect(result.cursor).not.toBeNull();
55
+ });
56
+
57
+ test("Full Pattern Match With Root Repeat", () => {
58
+ const john = new Literal("john", "John");
59
+ const space = new Literal("space", " ");
60
+ const doe = new Literal("doe", "Doe");
61
+ const smith = new Literal("smith", "Smith");
62
+ const name = new And("name", [john, space, new Or("last-name", [smith, doe])]);
63
+ const divider = new Regex("divider", "\\s+,\\s+");
64
+
65
+ divider.setTokens([", "])
66
+
67
+ const autoComplete = new AutoComplete(new Repeat("last-names", name, divider));
68
+ const result = autoComplete.suggest("John Doe");
69
+
70
+ expect(result.ast?.value).toBe("John Doe");
71
+ expect(result.options.length).toBe(1);
72
+ expect(result.nextPatterns.length).toBe(result.options.length);
73
+ expect(result.isComplete).toBeTruthy();
74
+ expect(result.cursor).not.toBeNull();
75
+ });
76
+
77
+ test("Partial", () => {
78
+ const name = new Literal("name", "Name");
79
+ const autoComplete = new AutoComplete(name);
80
+ let result = autoComplete.suggest("Na");
81
+
82
+ expect(result.options[0].text).toBe("me");
83
+ expect(result.options[0].startIndex).toBe(2);
84
+ expect(result.nextPatterns[0]).toBe(name);
85
+ expect(result.isComplete).toBeFalsy();
86
+ });
87
+
88
+ test("Partial Match With Bad Characters", () => {
89
+ const name = new Literal("name", "Name");
90
+ const autoComplete = new AutoComplete(name);
91
+ let result = autoComplete.suggest("Ni");
92
+
93
+ expect(result.options[0].text).toBe("ame");
94
+ expect(result.options[0].startIndex).toBe(1);
95
+ //expect(result.nextPattern).toBe(name);
96
+ expect(result.isComplete).toBeFalsy();
97
+ });
98
+
99
+ test("Complete", () => {
100
+ const name = new Literal("name", "Name");
101
+ const autoComplete = new AutoComplete(name);
102
+ let result = autoComplete.suggest("Name");
103
+
104
+ expect(result.options.length).toBe(0);
105
+ expect(result.nextPatterns.length).toBe(0);
106
+ expect(result.isComplete).toBeTruthy();
107
+ });
108
+
109
+ test("Options", ()=>{
110
+ const autoCompleteOptions: AutoCompleteOptions = {
111
+ greedyPatternNames: ["space"],
112
+ customTokens: {
113
+ "last-name": ["Sparrow"]
114
+ }
115
+ };
116
+
117
+ const jack = new Literal("jack", "Jack");
118
+ const john = new Literal("john", "John");
119
+ const space = new Literal("space", " ");
120
+ const doe = new Literal("doe", "Doe");
121
+ const smith = new Literal("smith", "Smith");
122
+ const firstName = new Or("first-name", [jack, john]);
123
+ const lastName = new Or("last-name", [doe, smith]);
124
+ const fullName = new And("full-name", [firstName, space, lastName]);
125
+
126
+ const text = "John";
127
+ const autoComplete = new AutoComplete(fullName, autoCompleteOptions);
128
+ const { options, ast, nextPatterns } = autoComplete.suggest(text);
129
+ const expectedOptions = [
130
+ {text: " Doe", startIndex: 4},
131
+ {text: " Smith", startIndex: 4},
132
+ {text: " Sparrow", startIndex: 4},
133
+ ];
134
+
135
+ const results = expectedOptions.map(o=>text.slice(0, o.startIndex) + o.text);
136
+ const expectedResults = [
137
+ "John Doe",
138
+ "John Smith",
139
+ "John Sparrow",
140
+ ]
141
+
142
+ expect(options).toEqual(expectedOptions);
143
+ expect(ast).toBeNull();
144
+ expect(nextPatterns.length).toBe(1);
145
+ expect(nextPatterns[0].name).toBe("space");
146
+ expect(results).toEqual(expectedResults)
147
+
148
+ });
149
+
150
+ });
@@ -0,0 +1,200 @@
1
+ import { Cursor } from "../patterns/Cursor";
2
+ import { Pattern } from "../patterns/Pattern";
3
+ import { Suggestion } from "./Suggestion";
4
+ import { SuggestionOption } from "./SuggestionOption";
5
+
6
+ export interface AutoCompleteOptions {
7
+ /**
8
+ * Allows for certain patterns to combine their tokens with the next tokens.
9
+ * Be very careful, this can explode to infinity pretty quick. Usually useful
10
+ * for dividers and spaces.
11
+ */
12
+ greedyPatternNames: string[];
13
+ /**
14
+ * Allows for custom suggestions for patterns. The key is the name of the pattern
15
+ * and the string array are the tokens suggested for that pattern.
16
+ */
17
+ customTokens: Record<string, string[]>;
18
+ }
19
+
20
+ const defaultOptions = { greedyPatternNames: [], customTokens: {} };
21
+
22
+ export class AutoComplete {
23
+ private _pattern: Pattern;
24
+ private _options: AutoCompleteOptions;
25
+ private _cursor!: Cursor;
26
+ private _text: string;
27
+
28
+ constructor(pattern: Pattern, options: AutoCompleteOptions = defaultOptions) {
29
+ this._pattern = pattern;
30
+ this._options = options;
31
+ this._text = "";
32
+ }
33
+
34
+ suggest(text: string): Suggestion {
35
+ if (text.length === 0) {
36
+ return {
37
+ isComplete: false,
38
+ options: this.createSuggestionsFromRoot(),
39
+ nextPatterns: [this._pattern],
40
+ cursor: null,
41
+ ast: null
42
+ }
43
+ }
44
+
45
+ this._text = text;
46
+ this._cursor = new Cursor(text);
47
+ const ast = this._pattern.parse(this._cursor);
48
+
49
+ const leafPattern = this._cursor.leafMatch.pattern;
50
+ const isComplete = ast?.value === text;
51
+ const options = this.createSuggestionsFromTokens();
52
+
53
+ let nextPatterns = [this._pattern];
54
+
55
+ if (leafPattern != null) {
56
+ nextPatterns = leafPattern.getNextPatterns();
57
+ }
58
+
59
+ return {
60
+ isComplete: isComplete,
61
+ options: options,
62
+ nextPatterns,
63
+ cursor: this._cursor,
64
+ ast,
65
+ }
66
+ }
67
+
68
+ private createSuggestionsFromRoot(): SuggestionOption[] {
69
+ const suggestions: SuggestionOption[] = [];
70
+ const tokens = this._pattern.getTokens();
71
+
72
+ for (const token of tokens) {
73
+ suggestions.push(this.createSuggestion("", token));
74
+ }
75
+
76
+ return suggestions;
77
+ }
78
+
79
+ private createSuggestionsFromTokens(): SuggestionOption[] {
80
+ const leafMatch = this._cursor.leafMatch;
81
+
82
+ if (!leafMatch.pattern) {
83
+ return this.createSuggestions(-1, this._getTokensForPattern(this._pattern));
84
+ }
85
+
86
+ const leafPattern = leafMatch.pattern;
87
+ const leafNode = leafMatch.node;
88
+ const parent = leafMatch.pattern.parent;
89
+
90
+ if (parent !== null && leafMatch.node != null) {
91
+ const patterns = leafPattern.getNextPatterns();
92
+
93
+ const tokens = patterns.reduce((acc: string[], pattern) => {
94
+ acc.push(...this._getTokensForPattern(pattern));
95
+ return acc;
96
+ }, []);
97
+
98
+ return this.createSuggestions(leafMatch.node.lastIndex, tokens);
99
+ } else {
100
+ return [];
101
+ }
102
+ }
103
+
104
+ private _getTokensForPattern(pattern: Pattern) {
105
+ if (this._options.greedyPatternNames.includes(pattern.name)) {
106
+ const greedyTokens = pattern.getTokens();
107
+ const nextPatterns = pattern.getNextPatterns();
108
+ const tokens: string[] = [];
109
+
110
+ const nextPatternTokens = nextPatterns.reduce((acc: string[], pattern)=>{
111
+ acc.push(...this._getTokensForPattern(pattern));
112
+ return acc;
113
+ }, []);
114
+
115
+ for (let token of greedyTokens){
116
+ for (let nextPatternToken of nextPatternTokens){
117
+ tokens.push(token + nextPatternToken);
118
+ }
119
+ }
120
+
121
+ return tokens;
122
+ } else {
123
+ const tokens = pattern.getTokens();
124
+ const customTokens = this._options.customTokens[pattern.name] || [];
125
+ tokens.push(...customTokens);
126
+ return tokens;
127
+ }
128
+ }
129
+
130
+ private createSuggestions(lastIndex: number, tokens: string[]): SuggestionOption[] {
131
+ let substring = lastIndex === -1 ? "" : this._cursor.getChars(0, lastIndex);
132
+ const suggestionStrings: string[] = [];
133
+ const options: SuggestionOption[] = [];
134
+
135
+ for (const token of tokens) {
136
+ const suggestion = substring + token;
137
+ const startsWith = suggestion.startsWith(substring);
138
+ const alreadyExist = suggestionStrings.includes(suggestion);
139
+ const isSameAsText = suggestion === this._text;
140
+
141
+ if (startsWith && !alreadyExist && !isSameAsText) {
142
+ suggestionStrings.push(suggestion);
143
+ options.push(this.createSuggestion(this._cursor.text, suggestion));
144
+ }
145
+ }
146
+
147
+ const reducedOptions = getFurthestOptions(options);
148
+ reducedOptions.sort((a, b) => a.text.localeCompare(b.text));
149
+
150
+ return reducedOptions;
151
+ }
152
+
153
+ private createSuggestion(fullText: string, suggestion: string): SuggestionOption {
154
+ const furthestMatch = findMatchIndex(suggestion, fullText);
155
+ const text = suggestion.slice(furthestMatch);
156
+
157
+ return {
158
+ text: text,
159
+ startIndex: furthestMatch,
160
+ }
161
+ }
162
+ }
163
+
164
+ function findMatchIndex(str1: string, str2: string): number {
165
+ let matchCount = 0;
166
+ let minLength = str1.length;
167
+
168
+ if (str2.length < minLength) {
169
+ minLength = str2.length;
170
+ }
171
+
172
+ for (let i = 0; i < minLength; i++) {
173
+ if (str1[i] === str2[i]) {
174
+ matchCount++;
175
+ } else {
176
+ break;
177
+ }
178
+ }
179
+
180
+ return matchCount;
181
+ }
182
+
183
+ function getFurthestOptions(options: SuggestionOption[]): SuggestionOption[] {
184
+ let furthestOptions: SuggestionOption[] = [];
185
+ let furthestIndex = -1;
186
+
187
+ for (const option of options) {
188
+ if (option.startIndex > furthestIndex) {
189
+ furthestIndex = option.startIndex;
190
+ furthestOptions = [];
191
+ }
192
+
193
+ if (option.startIndex === furthestIndex) {
194
+ furthestOptions.push(option);
195
+ }
196
+ }
197
+
198
+ return furthestOptions;
199
+ }
200
+
@@ -0,0 +1,12 @@
1
+ import { Node } from "../ast/Node";
2
+ import { Cursor } from "../patterns/Cursor";
3
+ import { Pattern } from "../patterns/Pattern";
4
+ import { SuggestionOption } from "./SuggestionOption";
5
+
6
+ export interface Suggestion {
7
+ isComplete: boolean;
8
+ options: SuggestionOption[];
9
+ nextPatterns: Pattern[];
10
+ cursor: Cursor | null;
11
+ ast: Node | null;
12
+ }
@@ -0,0 +1,4 @@
1
+ export interface SuggestionOption {
2
+ text: string;
3
+ startIndex: number;
4
+ }
@@ -1,4 +1,4 @@
1
- import { Repeat } from "../../index";
1
+ import { Repeat } from "../../patterns/Repeat";
2
2
  import divider from "./divider";
3
3
  import values from "./values";
4
4
 
@@ -1,5 +1,6 @@
1
- import { Regex } from "../../index";
1
+ import { Regex } from "../../patterns/Regex";
2
2
 
3
3
  const divider = new Regex(",", "\\s*[,]\\s*");
4
+ divider.setTokens([", "]);
4
5
 
5
6
  export default divider;
@@ -0,0 +1,6 @@
1
+ import { Regex } from "../../patterns/Regex";
2
+
3
+ const hex = new Regex("hex", "#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3}");
4
+ hex.setTokens(["#000", "#FFF"]);
5
+
6
+ export default hex;
@@ -1,21 +1,20 @@
1
- import {
2
- Literal,
3
- And,
4
- Repeat,
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 Recursive("values");
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
- name.clone("[Method Name]"),
17
+ methodName,
19
18
  openParen,
20
19
  optionalSpaces,
21
20
  args,
@@ -0,0 +1,5 @@
1
+ import { Regex } from "../../patterns/Regex";
2
+
3
+ const name = new Regex("name", "[a-zA-Z]+[a-zA-Z0-9_-]+");
4
+
5
+ export default name;
@@ -1,10 +1,10 @@
1
- import {
2
- Regex
3
- } from "../../index";
1
+ import { Regex } from "../../patterns/Regex";
4
2
 
5
3
  const number = new Regex(
6
4
  "number",
7
5
  "[-+]?[0-9]*[.]?[0-9]+([eE][-+]?[0-9]+)?"
8
6
  );
9
7
 
8
+ number.setTokens(["0"]);
9
+
10
10
  export default number;
@@ -0,0 +1,6 @@
1
+ import { Regex } from "../../patterns/Regex";
2
+
3
+ const spaces = new Regex("spaces", "\\s+");
4
+ spaces.setTokens([" "])
5
+
6
+ export default spaces;
@@ -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
 
@@ -1,4 +1,4 @@
1
- import { Repeat } from "../../index";
1
+ import { Repeat } from "../../patterns/Repeat";
2
2
  import value from "./value";
3
3
  import spaces from "./spaces";
4
4
 
@@ -0,0 +1,203 @@
1
+ import { escapedCharacter } from "./escapedCharacter";
2
+ import { exponent } from "./exponent";
3
+ import { expression } from "./expression";
4
+ import { expressionStatement } from "./expressionStatement";
5
+ import { infixOperator } from "./infixOperator";
6
+ import { integer } from "./integer";
7
+ import { name } from "./name";
8
+ import { parameters } from "./parameters";
9
+ import { prefixOperator } from "./prefixOperator";
10
+
11
+ describe("Ecmascript 3", () => {
12
+ test("Escaped Character", () => {
13
+ let result = escapedCharacter.exec(`\\"`);
14
+ expect(result.ast?.value).toBe(`\\"`)
15
+
16
+ result = escapedCharacter.exec(`\\'`)
17
+ expect(result.ast?.value).toBe(`\\'`)
18
+
19
+ result = escapedCharacter.exec(`\\\\`)
20
+ expect(result.ast?.value).toBe(`\\\\`)
21
+
22
+ result = escapedCharacter.exec(`\\/`)
23
+ expect(result.ast?.value).toBe(`\\/`)
24
+
25
+ result = escapedCharacter.exec(`\\f`)
26
+ expect(result.ast?.value).toBe(`\\f`)
27
+
28
+ result = escapedCharacter.exec(`\\t`)
29
+ expect(result.ast?.value).toBe(`\\t`)
30
+
31
+ result = escapedCharacter.exec(`\\u00E9`)
32
+ expect(result.ast?.value).toBe(`\\u00E9`)
33
+ });
34
+
35
+ test("Exponent", () => {
36
+ let result = exponent.exec("e+1");
37
+ expect(result.ast?.value).toBe("e+1")
38
+
39
+ result = exponent.exec("e-1");
40
+ expect(result.ast?.value).toBe("e-1")
41
+
42
+ result = exponent.exec("E+1");
43
+ expect(result.ast?.value).toBe("E+1")
44
+
45
+ result = exponent.exec("E-1");
46
+ expect(result.ast?.value).toBe("E-1")
47
+
48
+ result = exponent.exec("e+11");
49
+ expect(result.ast?.value).toBe("e+11")
50
+
51
+ result = exponent.exec("11");
52
+ expect(result.ast).toBeNull()
53
+ });
54
+
55
+ test("Integer", () => {
56
+ let result = integer.exec("0");
57
+ expect(result.ast?.value).toBe("0");
58
+
59
+ result = integer.exec("1");
60
+ expect(result.ast?.value).toBe("1");
61
+
62
+ result = integer.exec("100");
63
+ expect(result.ast?.value).toBe("100");
64
+
65
+ result = integer.exec(".1");
66
+ expect(result.ast).toBeNull();
67
+ });
68
+
69
+ test("Infix Operator", () => {
70
+ let result = infixOperator.exec("*");
71
+ expect(result.ast?.value).toBe("*");
72
+
73
+ result = infixOperator.exec("/");
74
+ expect(result.ast?.value).toBe("/");
75
+
76
+ result = infixOperator.exec("%");
77
+ expect(result.ast?.value).toBe("%");
78
+
79
+ result = infixOperator.exec("+");
80
+ expect(result.ast?.value).toBe("+");
81
+
82
+ result = infixOperator.exec("-");
83
+ expect(result.ast?.value).toBe("-");
84
+
85
+ result = infixOperator.exec(">=");
86
+ expect(result.ast?.value).toBe(">=");
87
+
88
+ result = infixOperator.exec("<=");
89
+ expect(result.ast?.value).toBe("<=");
90
+
91
+ result = infixOperator.exec(">");
92
+ expect(result.ast?.value).toBe(">");
93
+
94
+ result = infixOperator.exec("<");
95
+ expect(result.ast?.value).toBe("<");
96
+
97
+ result = infixOperator.exec("===");
98
+ expect(result.ast?.value).toBe("===");
99
+
100
+ result = infixOperator.exec("!==");
101
+ expect(result.ast?.value).toBe("!==");
102
+
103
+ result = infixOperator.exec("||");
104
+ expect(result.ast?.value).toBe("||");
105
+
106
+ result = infixOperator.exec("&&");
107
+ expect(result.ast?.value).toBe("&&");
108
+
109
+ result = infixOperator.exec("bad");
110
+ expect(result.ast).toBeNull();
111
+ });
112
+
113
+
114
+ test("Name", () => {
115
+ let result = name.exec("p_0");
116
+ expect(result.ast?.value).toBe("p_0");
117
+
118
+ result = name.exec("_0");
119
+ expect(result.ast?.value).toBe("_0");
120
+
121
+ result = name.exec("0");
122
+ expect(result.ast).toBeNull();
123
+
124
+ result = name.exec("_");
125
+ expect(result.ast?.value).toBe("_");
126
+ });
127
+
128
+ test("Parameters", () => {
129
+ let result = parameters.exec("(param1)");
130
+ expect(result.ast?.value).toBe("(param1)");
131
+
132
+ result = parameters.exec("(param1, param2)");
133
+ expect(result.ast?.value).toBe("(param1, param2)");
134
+
135
+ result = parameters.exec("(param1, param2,)");
136
+ expect(result.ast).toBeNull();
137
+ });
138
+
139
+ test("Prefix Operator", () => {
140
+ let result = prefixOperator.exec("typeof ");
141
+ expect(result.ast?.value).toBe("typeof ");
142
+
143
+ result = prefixOperator.exec("+");
144
+ expect(result.ast?.value).toBe("+");
145
+
146
+ result = prefixOperator.exec("-");
147
+ expect(result.ast?.value).toBe("-");
148
+
149
+ result = prefixOperator.exec("!");
150
+ expect(result.ast?.value).toBe("!");
151
+
152
+ result = prefixOperator.exec("a");
153
+ expect(result.ast).toBeNull();
154
+ });
155
+
156
+ test("Object Literal", () => {
157
+ let result = expression.exec(`{}`)
158
+ expect(result.ast?.value).toBe("{}");
159
+
160
+ result = expression.exec(`{prop:{}}`)
161
+ expect(result.ast?.value).toBe("{prop:{}}");
162
+
163
+ result = expression.exec(`{prop:"value"}`)
164
+ expect(result.ast?.value).toBe(`{prop:"value"}`);
165
+
166
+ result = expression.exec(`{prop:0.9}`)
167
+ expect(result.ast?.value).toBe(`{prop:0.9}`);
168
+
169
+ result = expression.exec(`{prop:1}`)
170
+ expect(result.ast?.value).toBe(`{prop:1}`);
171
+
172
+ result = expression.exec(`{"prop":1}`)
173
+ expect(result.ast?.value).toBe(`{"prop":1}`);
174
+ });
175
+
176
+ test("Array Literal", () => {
177
+ let result = expression.exec("[]")
178
+ expect(result.ast?.value).toBe("[]");
179
+
180
+ result = expression.exec("[{}, 9, 0.9e-10, [1, 2]]")
181
+ expect(result.ast?.value).toBe("[{}, 9, 0.9e-10, [1, 2]]");
182
+ });
183
+
184
+ test("Expression Statement", () => {
185
+ let result = expressionStatement.exec(`name = "John"`);
186
+ expect(result.ast?.value).toBe(`name = "John"`);
187
+
188
+ result = expressionStatement.exec(`name = othername = "John"`)
189
+ expect(result.ast?.value).toBe(`name = othername = "John"`);
190
+
191
+ result = expressionStatement.exec(`name = othername.prop = "John"`)
192
+ expect(result.ast?.value).toBe(`name = othername.prop = "John"`);
193
+
194
+ result = expressionStatement.exec(`name = othername.prop += 2`)
195
+ expect(result.ast?.value).toBe(`name = othername.prop += 2`);
196
+
197
+ result = expressionStatement.exec(`name.prop().method(blah) = blah.prop()`)
198
+ expect(result.ast?.value).toBe(`name.prop().method(blah) = blah.prop()`);
199
+
200
+ });
201
+
202
+
203
+ });