@weborigami/language 0.6.9 → 0.6.10

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 (39) hide show
  1. package/index.ts +19 -4
  2. package/main.js +5 -2
  3. package/package.json +2 -2
  4. package/src/compiler/compile.js +11 -3
  5. package/src/compiler/origami.pegjs +4 -2
  6. package/src/compiler/parse.js +77 -68
  7. package/src/compiler/parserHelpers.js +13 -13
  8. package/src/handlers/getPackedPath.js +17 -0
  9. package/src/handlers/jpeg_handler.js +5 -0
  10. package/src/handlers/js_handler.js +3 -3
  11. package/src/handlers/json_handler.js +3 -1
  12. package/src/handlers/tsv_handler.js +1 -1
  13. package/src/handlers/yaml_handler.js +1 -1
  14. package/src/project/jsGlobals.js +3 -3
  15. package/src/protocols/package.js +3 -3
  16. package/src/runtime/asyncStorage.js +7 -0
  17. package/src/runtime/codeFragment.js +4 -3
  18. package/src/runtime/errors.js +82 -129
  19. package/src/runtime/evaluate.js +8 -77
  20. package/src/runtime/execute.js +82 -0
  21. package/src/runtime/explainReferenceError.js +248 -0
  22. package/src/runtime/explainTraverseError.js +77 -0
  23. package/src/runtime/expressionFunction.js +8 -7
  24. package/src/runtime/expressionObject.js +4 -3
  25. package/src/runtime/handleExtension.js +22 -8
  26. package/src/runtime/internal.js +1 -1
  27. package/src/runtime/interop.js +15 -0
  28. package/src/runtime/ops.js +24 -19
  29. package/src/runtime/symbols.js +0 -1
  30. package/src/runtime/typos.js +22 -3
  31. package/test/compiler/compile.test.js +7 -103
  32. package/test/compiler/parse.test.js +38 -31
  33. package/test/project/fixtures/withPackageJson/subfolder/README.md +1 -0
  34. package/test/runtime/errors.test.js +296 -0
  35. package/test/runtime/evaluate.test.js +110 -34
  36. package/test/runtime/execute.test.js +41 -0
  37. package/test/runtime/expressionObject.test.js +3 -3
  38. package/test/runtime/ops.test.js +36 -35
  39. package/test/runtime/typos.test.js +2 -0
@@ -1,4 +1,3 @@
1
- import { Tree } from "@weborigami/async-tree";
2
1
  import assert from "node:assert";
3
2
  import { describe, test } from "node:test";
4
3
  import * as compile from "../../src/compiler/compile.js";
@@ -10,89 +9,13 @@ const globals = {
10
9
  name: "Alice",
11
10
  };
12
11
 
12
+ /**
13
+ * More complex tests for the compile() function
14
+ *
15
+ * The evaluate2.test.js file contains more basic tests, covering more language
16
+ * features, which compare the output of evaluate2() against an expected result.
17
+ */
13
18
  describe("compile", () => {
14
- test("array", async () => {
15
- await assertCompile("[]", []);
16
- await assertCompile("[ 1, 2, 3, ]", [1, 2, 3]);
17
- await assertCompile("[\n'a'\n'b'\n'c'\n]", ["a", "b", "c"]);
18
- });
19
-
20
- test("functionComposition", async () => {
21
- await assertCompile("greet()", "Hello, undefined!");
22
- await assertCompile("greet(name)", "Hello, Alice!");
23
- await assertCompile("greet 'world'", "Hello, world!", { mode: "shell" });
24
- });
25
-
26
- test("function call with spread", async () => {
27
- await assertCompile(
28
- `concat("Hello", ...[", ", name], "!")`,
29
- "Hello, Alice!"
30
- );
31
- });
32
-
33
- test("angle bracket path", async () => {
34
- await assertCompile("<data>", "Bob", {
35
- target: {
36
- data: "Bob",
37
- },
38
- });
39
- });
40
-
41
- test("object literal", async () => {
42
- await assertCompile("{ message = greet(name) }", {
43
- message: "Hello, Alice!",
44
- });
45
- await assertCompile(
46
- "{ message = greet(name) }",
47
- {
48
- message: "Hello, Alice!",
49
- },
50
- { mode: "shell" }
51
- );
52
- });
53
-
54
- test("object with computed property key", async () => {
55
- await assertCompile("{ [name] = greet(name) }", {
56
- Alice: "Hello, Alice!",
57
- });
58
- });
59
-
60
- test("merge", async () => {
61
- {
62
- const globals = {
63
- more: {
64
- b: 2,
65
- },
66
- };
67
- const fn = compile.expression(
68
- `
69
- {
70
- a: 1
71
- ...more
72
- c: a
73
- }
74
- `,
75
- { globals }
76
- );
77
- const result = await fn();
78
- assert.deepEqual(await Tree.plain(result), {
79
- a: 1,
80
- b: 2,
81
- c: 1,
82
- });
83
- }
84
- });
85
-
86
- test("number", async () => {
87
- await assertCompile("1", 1);
88
- await assertCompile("3.14159", 3.14159);
89
- await assertCompile("-1", -1);
90
- });
91
-
92
- test("sync object", async () => {
93
- await assertCompile("{a:1, b:2}", { a: 1, b: 2 });
94
- await assertCompile("{ a: { b: { c: 0 } } }", { a: { b: { c: 0 } } });
95
- });
96
19
 
97
20
  test("async object", async () => {
98
21
  const fn = compile.expression("{ a: { b = name }}", { globals });
@@ -141,21 +64,13 @@ describe("compile", () => {
141
64
 
142
65
  test("templateDocument", async () => {
143
66
  const defineTemplateFn = compile.templateDocument(
144
- "Documents can contain ` backticks"
67
+ "Documents can contain ` backticks",
145
68
  );
146
69
  const templateFn = await defineTemplateFn();
147
70
  const value = await templateFn();
148
71
  assert.deepEqual(value, "Documents can contain ` backticks");
149
72
  });
150
73
 
151
- test("templateLiteral", async () => {
152
- await assertCompile("`Hello, ${name}!`", "Hello, Alice!");
153
- await assertCompile(
154
- "`escape characters with \\`backslash\\``",
155
- "escape characters with `backslash`"
156
- );
157
- });
158
-
159
74
  test("tagged template string array is identical across calls", async () => {
160
75
  let saved;
161
76
  const globals = {
@@ -177,14 +92,3 @@ describe("compile", () => {
177
92
  assert.equal(bob, "Hello, Bob!");
178
93
  });
179
94
  });
180
-
181
- async function assertCompile(text, expected, options = {}) {
182
- const mode = options.mode ?? "program";
183
- const parent = options.target ?? null;
184
- const fn = compile.expression(text, { globals, mode, parent });
185
- let result = await fn();
186
- if (Tree.isMaplike(result)) {
187
- result = await Tree.plain(result);
188
- }
189
- assert.deepEqual(result, expected);
190
- }
@@ -31,7 +31,7 @@ describe("Origami parser", () => {
31
31
  [
32
32
  markers.traverse,
33
33
  [markers.external, "Path with spaces (and parens).html"],
34
- ]
34
+ ],
35
35
  );
36
36
  assertParse("angleBracketLiteral", "<foo/bar/baz>", [
37
37
  markers.traverse,
@@ -113,7 +113,7 @@ describe("Origami parser", () => {
113
113
  2
114
114
  3
115
115
  ]`,
116
- [ops.array, [ops.literal, 1], [ops.literal, 2], [ops.literal, 3]]
116
+ [ops.array, [ops.literal, 1], [ops.literal, 2], [ops.literal, 3]],
117
117
  );
118
118
  });
119
119
 
@@ -270,7 +270,7 @@ describe("Origami parser", () => {
270
270
  assertThrows(
271
271
  "arrowFunction",
272
272
  "([a, a]) => a",
273
- `Duplicate parameter name "a"`
273
+ `Duplicate parameter name "a"`,
274
274
  );
275
275
  });
276
276
 
@@ -321,7 +321,7 @@ describe("Origami parser", () => {
321
321
  assertThrows(
322
322
  "arrowFunction",
323
323
  "({ a: c, b: c }) => c",
324
- `Duplicate parameter name "c"`
324
+ `Duplicate parameter name "c"`,
325
325
  );
326
326
  });
327
327
 
@@ -739,7 +739,7 @@ describe("Origami parser", () => {
739
739
  ---
740
740
  Body`,
741
741
  'Expected "---"',
742
- { line: 2, column: 14 }
742
+ { line: 2, column: 14 },
743
743
  );
744
744
  });
745
745
 
@@ -752,10 +752,15 @@ a : 1
752
752
  ---
753
753
  Body`,
754
754
  "Unexpected flow-map-end token",
755
- { line: 3, column: 1 }
755
+ { line: 3, column: 1 },
756
756
  );
757
757
  });
758
758
 
759
+ test("escapedChar", () => {
760
+ assertParse("escapedChar", String.raw`\n`, "\n");
761
+ assertParse("escapedChar", String.raw`\\`, `\\`);
762
+ });
763
+
759
764
  test("exponentiationExpression", () => {
760
765
  assertParse("exponentiationExpression", "2 ** 2 ** 3", [
761
766
  ops.exponentiation,
@@ -848,7 +853,7 @@ Body`,
848
853
  "x //comment",
849
854
  [markers.traverse, [markers.reference, "x"]],
850
855
  "program",
851
- false
856
+ false,
852
857
  );
853
858
  });
854
859
 
@@ -940,7 +945,7 @@ Body`,
940
945
  assertParse("expression", "tag`Hello, ${name}!`", [
941
946
  [markers.traverse, [markers.reference, "tag"]],
942
947
  [ops.literal, ["Hello, ", "!"]],
943
- [ops.concat, [markers.traverse, [markers.reference, "name"]]],
948
+ [ops.deepText, [markers.traverse, [markers.reference, "name"]]],
944
949
  ]);
945
950
  assertParse("expression", "=tag`Hello, ${_}!`", [
946
951
  ops.lambda,
@@ -949,7 +954,7 @@ Body`,
949
954
  [
950
955
  [markers.traverse, [markers.reference, "tag"]],
951
956
  [ops.literal, ["Hello, ", "!"]],
952
- [ops.concat, [markers.traverse, [markers.reference, "_"]]],
957
+ [ops.deepText, [markers.traverse, [markers.reference, "_"]]],
953
958
  ],
954
959
  ]);
955
960
  assertParse("expression", "(post, slug) => fn.js(post, slug)", [
@@ -1013,7 +1018,7 @@ Body`,
1013
1018
  ],
1014
1019
  ],
1015
1020
  ],
1016
- ]
1021
+ ],
1017
1022
  );
1018
1023
  });
1019
1024
  });
@@ -1032,7 +1037,7 @@ Body`,
1032
1037
  [[markers.traverse, [markers.reference, "_template"]]],
1033
1038
  ],
1034
1039
  "program",
1035
- false
1040
+ false,
1036
1041
  );
1037
1042
  });
1038
1043
 
@@ -1065,17 +1070,17 @@ Body`,
1065
1070
  assertThrows(
1066
1071
  "identifier",
1067
1072
  "1stCharacterIsNumber",
1068
- "Expected JavaScript identifier start"
1073
+ "Expected JavaScript identifier start",
1069
1074
  );
1070
1075
  assertThrows(
1071
1076
  "identifier",
1072
1077
  "has space",
1073
- "Expected JavaScript identifier continuation"
1078
+ "Expected JavaScript identifier continuation",
1074
1079
  );
1075
1080
  assertThrows(
1076
1081
  "identifier",
1077
1082
  "foo.bar",
1078
- "Expected JavaScript identifier continuation"
1083
+ "Expected JavaScript identifier continuation",
1079
1084
  );
1080
1085
  });
1081
1086
 
@@ -1108,7 +1113,7 @@ Body`,
1108
1113
  [markers.traverse, [markers.reference, "tree/"], [ops.literal, "key"]],
1109
1114
  [markers.traverse, [markers.reference, "arg"]],
1110
1115
  ],
1111
- "shell"
1116
+ "shell",
1112
1117
  );
1113
1118
  assertParse("implicitParenthesesCallExpression", "foo.js bar.ori 'arg'", [
1114
1119
  [markers.traverse, [markers.reference, "foo.js"]],
@@ -1133,7 +1138,7 @@ Body`,
1133
1138
  [markers.traverse, [markers.reference, "b.json"]],
1134
1139
  [ops.array, [markers.traverse, [markers.reference, "c.json"]]],
1135
1140
  ],
1136
- ]
1141
+ ],
1137
1142
  );
1138
1143
  });
1139
1144
 
@@ -1183,7 +1188,7 @@ Body`,
1183
1188
  "/*\nHello, world!\n*/",
1184
1189
  null,
1185
1190
  "program",
1186
- false
1191
+ false,
1187
1192
  );
1188
1193
  });
1189
1194
 
@@ -1286,7 +1291,7 @@ Body`,
1286
1291
  ops.object,
1287
1292
  ["a", [ops.getter, [markers.traverse, [markers.reference, "b"]]]],
1288
1293
  ["b", [ops.literal, 2]],
1289
- ]
1294
+ ],
1290
1295
  );
1291
1296
  assertParse("objectLiteral", "{ a: { b: 1 } }", [
1292
1297
  ops.object,
@@ -1544,7 +1549,7 @@ Body`,
1544
1549
  "tree/",
1545
1550
  [[ops.literal, "tree/"]],
1546
1551
  undefined,
1547
- false
1552
+ false,
1548
1553
  );
1549
1554
  assertParse(
1550
1555
  "pathKeys",
@@ -1554,7 +1559,7 @@ Body`,
1554
1559
  [ops.literal, "12"],
1555
1560
  ],
1556
1561
  undefined,
1557
- false
1562
+ false,
1558
1563
  );
1559
1564
  assertParse(
1560
1565
  "pathKeys",
@@ -1565,7 +1570,7 @@ Body`,
1565
1570
  [ops.literal, "bar"],
1566
1571
  ],
1567
1572
  undefined,
1568
- false
1573
+ false,
1569
1574
  );
1570
1575
  assertParse(
1571
1576
  "pathKeys",
@@ -1577,7 +1582,7 @@ Body`,
1577
1582
  [ops.literal, "b"],
1578
1583
  ],
1579
1584
  undefined,
1580
- false
1585
+ false,
1581
1586
  );
1582
1587
  });
1583
1588
 
@@ -1674,12 +1679,14 @@ Body`,
1674
1679
  `,
1675
1680
  [ops.literal, "Hello"],
1676
1681
  "program",
1677
- false
1682
+ false,
1678
1683
  );
1679
1684
  });
1680
1685
 
1681
1686
  test("regexLiteral", () => {
1682
1687
  assertParse("regexLiteral", "/abc+/g", [ops.literal, /abc+/g]);
1688
+ assertParse("regexLiteral", String.raw`/\//`, [ops.literal, /\//]);
1689
+ assertParse("regexLiteral", String.raw`/\d+/`, [ops.literal, /\d+/]);
1683
1690
  });
1684
1691
 
1685
1692
  test("relationalExpression", () => {
@@ -1757,7 +1764,7 @@ Body`,
1757
1764
  "// Hello, world!",
1758
1765
  null,
1759
1766
  "program",
1760
- false
1767
+ false,
1761
1768
  );
1762
1769
  });
1763
1770
 
@@ -1815,7 +1822,7 @@ Body text`,
1815
1822
  ops.object,
1816
1823
  ["title", [ops.literal, "Title goes here"]],
1817
1824
  ["_body", [ops.templateIndent, [ops.literal, ["Body text"]]]],
1818
- ]
1825
+ ],
1819
1826
  );
1820
1827
  });
1821
1828
 
@@ -1842,7 +1849,7 @@ Body text`,
1842
1849
  ],
1843
1850
  ],
1844
1851
  ],
1845
- "shell"
1852
+ "shell",
1846
1853
  );
1847
1854
  });
1848
1855
 
@@ -1891,7 +1898,7 @@ Body text`,
1891
1898
  "${foo}",
1892
1899
  [markers.traverse, [markers.reference, "foo"]],
1893
1900
  "shell",
1894
- false
1901
+ false,
1895
1902
  );
1896
1903
  });
1897
1904
 
@@ -1965,7 +1972,7 @@ Body text`,
1965
1972
  `,
1966
1973
  null,
1967
1974
  "program",
1968
- false
1975
+ false,
1969
1976
  );
1970
1977
  });
1971
1978
  });
@@ -1975,7 +1982,7 @@ function assertParse(
1975
1982
  source,
1976
1983
  expected,
1977
1984
  mode = "shell",
1978
- checkLocation = true
1985
+ checkLocation = true,
1979
1986
  ) {
1980
1987
  const code = parse(source, {
1981
1988
  grammarSource: { text: source },
@@ -1990,7 +1997,7 @@ function assertParse(
1990
1997
  assertCodeLocations(code);
1991
1998
  const resultSource = code.location.source.text.slice(
1992
1999
  code.location.start.offset,
1993
- code.location.end.offset
2000
+ code.location.end.offset,
1994
2001
  );
1995
2002
  assert.equal(resultSource, source);
1996
2003
  }
@@ -2010,7 +2017,7 @@ function assertThrows(startRule, source, message, position, mode = "program") {
2010
2017
  } catch (/** @type {any} */ error) {
2011
2018
  assert(
2012
2019
  error.message.includes(message),
2013
- `Error message incorrect:\n expected: "${message}"\n actual: "${error.message}"`
2020
+ `Error message incorrect:\n expected: "${message}"\n actual: "${error.message}"`,
2014
2021
  );
2015
2022
  if (position) {
2016
2023
  assert.equal(error.location.start.line, position.line);
@@ -0,0 +1 @@
1
+ This file exists to force creation of the containing folder.