clarity-pattern-parser 8.4.10 → 8.4.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/TODO.md +17 -3
- package/dist/grammar/patterns/statement.d.ts +2 -2
- package/dist/index.browser.js +46 -16
- package/dist/index.browser.js.map +1 -1
- package/dist/index.esm.js +46 -16
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +46 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/grammar/Grammar.test.ts +76 -10
- package/src/grammar/Grammar.ts +49 -12
- package/src/grammar/patterns/import.ts +8 -4
- package/src/grammar/patterns/statement.ts +4 -2
|
@@ -271,9 +271,9 @@ describe("Grammar", () => {
|
|
|
271
271
|
test("Bad Grammar At Beginning", () => {
|
|
272
272
|
|
|
273
273
|
expect(() => {
|
|
274
|
-
const expression =
|
|
274
|
+
const expression = `//`;
|
|
275
275
|
Grammar.parseString(expression);
|
|
276
|
-
}).
|
|
276
|
+
}).toThrow();
|
|
277
277
|
|
|
278
278
|
});
|
|
279
279
|
|
|
@@ -339,18 +339,18 @@ describe("Grammar", () => {
|
|
|
339
339
|
use params { custom-space }
|
|
340
340
|
space = custom-space
|
|
341
341
|
`
|
|
342
|
-
|
|
343
|
-
const pathMap: Record<string, string> = {
|
|
344
|
-
"space.cpat": spaceExpression,
|
|
345
|
-
"first-name.cpat": importExpression
|
|
346
|
-
};
|
|
347
|
-
|
|
348
342
|
const expression = `
|
|
349
343
|
import { first-name } from "first-name.cpat"
|
|
350
344
|
import { space } from "space.cpat" with params { custom-space = " " }
|
|
351
345
|
last-name = "Doe"
|
|
352
346
|
full-name = first-name & space & last-name
|
|
353
347
|
`
|
|
348
|
+
|
|
349
|
+
const pathMap: Record<string, string> = {
|
|
350
|
+
"space.cpat": spaceExpression,
|
|
351
|
+
"first-name.cpat": importExpression
|
|
352
|
+
};
|
|
353
|
+
|
|
354
354
|
function resolveImport(resource: string) {
|
|
355
355
|
return Promise.resolve({ expression: pathMap[resource], resource });
|
|
356
356
|
}
|
|
@@ -361,9 +361,75 @@ describe("Grammar", () => {
|
|
|
361
361
|
expect(result?.ast?.value).toBe("John Doe");
|
|
362
362
|
});
|
|
363
363
|
|
|
364
|
-
test("
|
|
364
|
+
test("Export Name", async () => {
|
|
365
|
+
const expression = `
|
|
366
|
+
import { use-this } from "resource1"
|
|
367
|
+
import {name} from "resource2" with params {
|
|
368
|
+
use-this
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
name
|
|
372
|
+
`
|
|
373
|
+
|
|
374
|
+
const resource1 = `
|
|
375
|
+
use-this = "Use This"
|
|
376
|
+
`;
|
|
377
|
+
|
|
378
|
+
const resource2 = `
|
|
379
|
+
use params {
|
|
380
|
+
use-this
|
|
381
|
+
}
|
|
382
|
+
name = use-this
|
|
383
|
+
`;
|
|
384
|
+
|
|
385
|
+
const pathMap: Record<string, string> = {
|
|
386
|
+
"resource1": resource1,
|
|
387
|
+
"resource2": resource2
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
function resolveImport(resource: string) {
|
|
391
|
+
return Promise.resolve({ expression: pathMap[resource], resource });
|
|
392
|
+
}
|
|
393
|
+
const patterns = await Grammar.parse(expression, { resolveImport });
|
|
394
|
+
const pattern = patterns.get("name") as Literal;
|
|
395
|
+
|
|
396
|
+
const result = pattern.exec("Use This");
|
|
397
|
+
|
|
398
|
+
expect(result.ast?.value).toBe("Use This");
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
test("Import Alias", async () => {
|
|
365
402
|
const expression = `
|
|
366
|
-
|
|
403
|
+
import { value as alias } from "resource1"
|
|
404
|
+
import { export-value } from "resource2" with params {
|
|
405
|
+
param = alias
|
|
406
|
+
}
|
|
407
|
+
name = export-value
|
|
408
|
+
`
|
|
409
|
+
|
|
410
|
+
const resource1 = `
|
|
411
|
+
value = "Value"
|
|
412
|
+
`;
|
|
413
|
+
|
|
414
|
+
const resource2 = `
|
|
415
|
+
use params {
|
|
416
|
+
param
|
|
417
|
+
}
|
|
418
|
+
export-value = param
|
|
367
419
|
`
|
|
420
|
+
|
|
421
|
+
const pathMap: Record<string, string> = {
|
|
422
|
+
"resource1": resource1,
|
|
423
|
+
"resource2": resource2
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
function resolveImport(resource: string) {
|
|
427
|
+
return Promise.resolve({ expression: pathMap[resource], resource });
|
|
428
|
+
}
|
|
429
|
+
const patterns = await Grammar.parse(expression, { resolveImport });
|
|
430
|
+
const pattern = patterns.get("name") as Literal;
|
|
431
|
+
|
|
432
|
+
const result = pattern.exec("Value");
|
|
433
|
+
expect(result.ast?.value).toBe("Value");
|
|
368
434
|
});
|
|
369
435
|
});
|
package/src/grammar/Grammar.ts
CHANGED
|
@@ -119,9 +119,15 @@ export class Grammar {
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
private _buildPatterns(ast: Node) {
|
|
122
|
-
ast.
|
|
122
|
+
const body = ast.find(n => n.name === "body");
|
|
123
|
+
|
|
124
|
+
if (body == null) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
body.findAll(n => n.name === "assign-statement" || n.name === "export-name").forEach((n) => {
|
|
123
129
|
const typeNode = n.find(n => n.name.includes("literal"));
|
|
124
|
-
const type = typeNode?.name || "unknown";
|
|
130
|
+
const type = n.name === "export-name" ? "export-name" : typeNode?.name || "unknown";
|
|
125
131
|
|
|
126
132
|
switch (type) {
|
|
127
133
|
case "literal": {
|
|
@@ -148,6 +154,11 @@ export class Grammar {
|
|
|
148
154
|
this._buildAlias(n)
|
|
149
155
|
break;
|
|
150
156
|
}
|
|
157
|
+
case "export-name": {
|
|
158
|
+
const pattern = this._getPattern(n.value);
|
|
159
|
+
this._parseContext.patternsByName.set(n.value, pattern);
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
151
162
|
default: {
|
|
152
163
|
break;
|
|
153
164
|
}
|
|
@@ -172,20 +183,46 @@ export class Grammar {
|
|
|
172
183
|
|
|
173
184
|
try {
|
|
174
185
|
const patterns = await grammar.parse(grammarFile.expression);
|
|
175
|
-
const
|
|
186
|
+
const importStatements = importStatement.findAll(n => n.name === "import-name" || n.name === "import-alias");
|
|
176
187
|
|
|
177
|
-
|
|
178
|
-
if (
|
|
179
|
-
|
|
188
|
+
importStatements.forEach((node) => {
|
|
189
|
+
if (node.name === "import-name" && node.parent?.name === "import-alias"){
|
|
190
|
+
return;
|
|
180
191
|
}
|
|
181
192
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
193
|
+
if (node.name === "import-name" && node.parent?.name !== "import-alias") {
|
|
194
|
+
const importName = node.value;
|
|
195
|
+
|
|
196
|
+
if (parseContext.importedPatternsByName.has(importName)) {
|
|
197
|
+
throw new Error(`'${importName}' was already used within another import.`);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const pattern = patterns.get(importName);
|
|
201
|
+
if (pattern == null) {
|
|
202
|
+
throw new Error(`Couldn't find pattern with name: ${importName}, from import: ${resource}.`);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
parseContext.importedPatternsByName.set(importName, pattern);
|
|
206
|
+
} else {
|
|
207
|
+
const importNameNode = node.find(n => n.name === "import-name") as Node;
|
|
208
|
+
const importName = importNameNode.value;
|
|
209
|
+
const aliasNode = node.find(n => n.name === "import-name-alias") as Node;
|
|
210
|
+
const alias = aliasNode.value;
|
|
211
|
+
|
|
212
|
+
if (parseContext.importedPatternsByName.has(alias)) {
|
|
213
|
+
throw new Error(`'${alias}' was already used within another import.`);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const pattern = patterns.get(importName);
|
|
217
|
+
if (pattern == null) {
|
|
218
|
+
throw new Error(`Couldn't find pattern with name: ${importName}, from import: ${resource}.`);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
parseContext.importedPatternsByName.set(alias, pattern.clone(alias));
|
|
185
222
|
}
|
|
223
|
+
});
|
|
224
|
+
|
|
186
225
|
|
|
187
|
-
parseContext.importedPatternsByName.set(importName, pattern);
|
|
188
|
-
})
|
|
189
226
|
|
|
190
227
|
} catch (e: any) {
|
|
191
228
|
throw new Error(`Failed loading expression from: "${resource}". Error details: "${e.message}"`);
|
|
@@ -199,7 +236,7 @@ export class Grammar {
|
|
|
199
236
|
const paramsStatement = importStatement.find(n => n.name === "with-params-statement");
|
|
200
237
|
|
|
201
238
|
if (paramsStatement != null) {
|
|
202
|
-
const statements = paramsStatement.find(n => n.name === "body");
|
|
239
|
+
const statements = paramsStatement.find(n => n.name === "with-params-body");
|
|
203
240
|
|
|
204
241
|
if (statements != null) {
|
|
205
242
|
const expression = statements.toString();
|
|
@@ -7,18 +7,22 @@ import { Or } from "../../patterns/Or";
|
|
|
7
7
|
import { body } from "./body";
|
|
8
8
|
import { allSpaces, lineSpaces } from "./spaces";
|
|
9
9
|
|
|
10
|
+
const optionalSpaces = allSpaces.clone("optional-spaces", true);
|
|
11
|
+
const optionalLineSpaces = lineSpaces.clone("options-line-spaces", true);
|
|
12
|
+
|
|
10
13
|
const importNameDivider = new Regex("import-name-divider", "(\\s+)?,(\\s+)?");
|
|
11
14
|
const importKeyword = new Literal("import", "import");
|
|
12
15
|
const useParamsKeyword = new Literal("use-params", "use params");
|
|
16
|
+
const asKeyword = new Literal("as", "as");
|
|
13
17
|
const fromKeyword = new Literal("from", "from");
|
|
14
18
|
const openBracket = new Literal("open-bracket", "{");
|
|
15
19
|
const closeBracket = new Literal("close-bracket", "}");
|
|
16
20
|
const name = new Regex("import-name", "[^}\\s,]+");
|
|
17
|
-
const
|
|
21
|
+
const importNameAlias = name.clone("import-name-alias");
|
|
22
|
+
const importAlias = new And("import-alias", [name, lineSpaces, asKeyword, lineSpaces, importNameAlias]);
|
|
23
|
+
const importedNames = new Repeat("imported-names", new Or("import-names", [importAlias, name]), { divider: importNameDivider });
|
|
18
24
|
const paramName = name.clone("param-name");
|
|
19
25
|
const paramNames = new Repeat("param-names", paramName, { divider: importNameDivider });
|
|
20
|
-
const optionalSpaces = allSpaces.clone("optional-spaces", true);
|
|
21
|
-
const optionalLineSpaces = lineSpaces.clone("options-line-spaces", true);
|
|
22
26
|
const resource = literal.clone("resource");
|
|
23
27
|
|
|
24
28
|
const useParams = new And("import-params", [
|
|
@@ -37,7 +41,7 @@ const withParamsStatement = new And("with-params-statement", [
|
|
|
37
41
|
optionalLineSpaces,
|
|
38
42
|
openBracket,
|
|
39
43
|
optionalSpaces,
|
|
40
|
-
body,
|
|
44
|
+
body.clone("with-params-body"),
|
|
41
45
|
optionalSpaces,
|
|
42
46
|
closeBracket
|
|
43
47
|
], true);
|
|
@@ -21,11 +21,13 @@ const statements = new Or("statements", [
|
|
|
21
21
|
name.clone("alias-literal"),
|
|
22
22
|
]);
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
const assignStatement = new And("assign-statement", [
|
|
25
25
|
optionalSpaces,
|
|
26
26
|
name,
|
|
27
27
|
optionalSpaces,
|
|
28
28
|
assignOperator,
|
|
29
29
|
optionalSpaces,
|
|
30
30
|
statements
|
|
31
|
-
]);
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
export const statement = new Or("statement", [assignStatement, name.clone("export-name")]);
|