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.
@@ -271,9 +271,9 @@ describe("Grammar", () => {
271
271
  test("Bad Grammar At Beginning", () => {
272
272
 
273
273
  expect(() => {
274
- const expression = `Just Junk`;
274
+ const expression = `//`;
275
275
  Grammar.parseString(expression);
276
- }).toThrowError("[Parse Error] Found: 'Just Junk', expected: ' ='.");
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("Use Params", () => {
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
- use Params { first-name }
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
  });
@@ -119,9 +119,15 @@ export class Grammar {
119
119
  }
120
120
 
121
121
  private _buildPatterns(ast: Node) {
122
- ast.findAll(n => n.name === "statement").forEach((n) => {
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 importNames = importStatement.findAll(n => n.name === "import-name").map(n => n.value);
186
+ const importStatements = importStatement.findAll(n => n.name === "import-name" || n.name === "import-alias");
176
187
 
177
- importNames.forEach((importName) => {
178
- if (parseContext.importedPatternsByName.has(importName)) {
179
- throw new Error(`'${importName}' was already used within another import.`);
188
+ importStatements.forEach((node) => {
189
+ if (node.name === "import-name" && node.parent?.name === "import-alias"){
190
+ return;
180
191
  }
181
192
 
182
- const pattern = patterns.get(importName);
183
- if (pattern == null) {
184
- throw new Error(`Couldn't find pattern with name: ${importName}, from import: ${resource}.`);
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 importedNames = new Repeat("imported-names", name, { divider: importNameDivider });
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
- export const statement = new And("statement", [
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")]);