@weborigami/language 0.6.9 → 0.6.11
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/index.ts +19 -4
- package/main.js +5 -2
- package/package.json +2 -2
- package/src/compiler/compile.js +11 -3
- package/src/compiler/origami.pegjs +4 -2
- package/src/compiler/parse.js +77 -68
- package/src/compiler/parserHelpers.js +16 -17
- package/src/handlers/getPackedPath.js +17 -0
- package/src/handlers/jpeg_handler.js +5 -0
- package/src/handlers/js_handler.js +3 -3
- package/src/handlers/json_handler.js +3 -1
- package/src/handlers/tsv_handler.js +1 -1
- package/src/handlers/yaml_handler.js +9 -3
- package/src/project/jsGlobals.js +3 -12
- package/src/protocols/package.js +20 -11
- package/src/runtime/asyncStorage.js +7 -0
- package/src/runtime/codeFragment.js +4 -3
- package/src/runtime/errors.js +86 -128
- package/src/runtime/evaluate.js +8 -77
- package/src/runtime/execute.js +85 -0
- package/src/runtime/explainReferenceError.js +248 -0
- package/src/runtime/explainTraverseError.js +77 -0
- package/src/runtime/expressionFunction.js +8 -7
- package/src/runtime/expressionObject.js +4 -3
- package/src/runtime/handleExtension.js +22 -8
- package/src/runtime/internal.js +1 -1
- package/src/runtime/interop.js +15 -0
- package/src/runtime/ops.js +51 -21
- package/src/runtime/symbols.js +0 -1
- package/src/runtime/typos.js +22 -3
- package/test/compiler/compile.test.js +7 -103
- package/test/compiler/parse.test.js +42 -39
- package/test/project/fixtures/withPackageJson/subfolder/README.md +1 -0
- package/test/runtime/errors.test.js +296 -0
- package/test/runtime/evaluate.test.js +110 -34
- package/test/runtime/execute.test.js +41 -0
- package/test/runtime/expressionObject.test.js +3 -3
- package/test/runtime/ops.test.js +42 -35
- 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
|
|
|
@@ -569,8 +569,8 @@ describe("Origami parser", () => {
|
|
|
569
569
|
|
|
570
570
|
test("parentheses arguments with spreads", () => {
|
|
571
571
|
assertParse("callExpression", "fn(a, ...b, ...c)", [
|
|
572
|
-
|
|
573
|
-
|
|
572
|
+
ops.apply,
|
|
573
|
+
[markers.traverse, [markers.reference, "fn"]],
|
|
574
574
|
[
|
|
575
575
|
ops.flat,
|
|
576
576
|
[ops.array, [markers.traverse, [markers.reference, "a"]]],
|
|
@@ -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.
|
|
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.
|
|
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"]],
|
|
@@ -1121,19 +1126,15 @@ Body`,
|
|
|
1121
1126
|
"implicitParenthesesCallExpression",
|
|
1122
1127
|
"concat a.json, ...b.json, c.json",
|
|
1123
1128
|
[
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
[markers.traverse, [markers.reference, "concat"]],
|
|
1127
|
-
"apply",
|
|
1128
|
-
],
|
|
1129
|
-
null,
|
|
1129
|
+
ops.apply,
|
|
1130
|
+
[markers.traverse, [markers.reference, "concat"]],
|
|
1130
1131
|
[
|
|
1131
1132
|
ops.flat,
|
|
1132
1133
|
[ops.array, [markers.traverse, [markers.reference, "a.json"]]],
|
|
1133
1134
|
[markers.traverse, [markers.reference, "b.json"]],
|
|
1134
1135
|
[ops.array, [markers.traverse, [markers.reference, "c.json"]]],
|
|
1135
1136
|
],
|
|
1136
|
-
]
|
|
1137
|
+
],
|
|
1137
1138
|
);
|
|
1138
1139
|
});
|
|
1139
1140
|
|
|
@@ -1183,7 +1184,7 @@ Body`,
|
|
|
1183
1184
|
"/*\nHello, world!\n*/",
|
|
1184
1185
|
null,
|
|
1185
1186
|
"program",
|
|
1186
|
-
false
|
|
1187
|
+
false,
|
|
1187
1188
|
);
|
|
1188
1189
|
});
|
|
1189
1190
|
|
|
@@ -1286,7 +1287,7 @@ Body`,
|
|
|
1286
1287
|
ops.object,
|
|
1287
1288
|
["a", [ops.getter, [markers.traverse, [markers.reference, "b"]]]],
|
|
1288
1289
|
["b", [ops.literal, 2]],
|
|
1289
|
-
]
|
|
1290
|
+
],
|
|
1290
1291
|
);
|
|
1291
1292
|
assertParse("objectLiteral", "{ a: { b: 1 } }", [
|
|
1292
1293
|
ops.object,
|
|
@@ -1544,7 +1545,7 @@ Body`,
|
|
|
1544
1545
|
"tree/",
|
|
1545
1546
|
[[ops.literal, "tree/"]],
|
|
1546
1547
|
undefined,
|
|
1547
|
-
false
|
|
1548
|
+
false,
|
|
1548
1549
|
);
|
|
1549
1550
|
assertParse(
|
|
1550
1551
|
"pathKeys",
|
|
@@ -1554,7 +1555,7 @@ Body`,
|
|
|
1554
1555
|
[ops.literal, "12"],
|
|
1555
1556
|
],
|
|
1556
1557
|
undefined,
|
|
1557
|
-
false
|
|
1558
|
+
false,
|
|
1558
1559
|
);
|
|
1559
1560
|
assertParse(
|
|
1560
1561
|
"pathKeys",
|
|
@@ -1565,7 +1566,7 @@ Body`,
|
|
|
1565
1566
|
[ops.literal, "bar"],
|
|
1566
1567
|
],
|
|
1567
1568
|
undefined,
|
|
1568
|
-
false
|
|
1569
|
+
false,
|
|
1569
1570
|
);
|
|
1570
1571
|
assertParse(
|
|
1571
1572
|
"pathKeys",
|
|
@@ -1577,7 +1578,7 @@ Body`,
|
|
|
1577
1578
|
[ops.literal, "b"],
|
|
1578
1579
|
],
|
|
1579
1580
|
undefined,
|
|
1580
|
-
false
|
|
1581
|
+
false,
|
|
1581
1582
|
);
|
|
1582
1583
|
});
|
|
1583
1584
|
|
|
@@ -1674,12 +1675,14 @@ Body`,
|
|
|
1674
1675
|
`,
|
|
1675
1676
|
[ops.literal, "Hello"],
|
|
1676
1677
|
"program",
|
|
1677
|
-
false
|
|
1678
|
+
false,
|
|
1678
1679
|
);
|
|
1679
1680
|
});
|
|
1680
1681
|
|
|
1681
1682
|
test("regexLiteral", () => {
|
|
1682
1683
|
assertParse("regexLiteral", "/abc+/g", [ops.literal, /abc+/g]);
|
|
1684
|
+
assertParse("regexLiteral", String.raw`/\//`, [ops.literal, /\//]);
|
|
1685
|
+
assertParse("regexLiteral", String.raw`/\d+/`, [ops.literal, /\d+/]);
|
|
1683
1686
|
});
|
|
1684
1687
|
|
|
1685
1688
|
test("relationalExpression", () => {
|
|
@@ -1757,7 +1760,7 @@ Body`,
|
|
|
1757
1760
|
"// Hello, world!",
|
|
1758
1761
|
null,
|
|
1759
1762
|
"program",
|
|
1760
|
-
false
|
|
1763
|
+
false,
|
|
1761
1764
|
);
|
|
1762
1765
|
});
|
|
1763
1766
|
|
|
@@ -1815,7 +1818,7 @@ Body text`,
|
|
|
1815
1818
|
ops.object,
|
|
1816
1819
|
["title", [ops.literal, "Title goes here"]],
|
|
1817
1820
|
["_body", [ops.templateIndent, [ops.literal, ["Body text"]]]],
|
|
1818
|
-
]
|
|
1821
|
+
],
|
|
1819
1822
|
);
|
|
1820
1823
|
});
|
|
1821
1824
|
|
|
@@ -1842,7 +1845,7 @@ Body text`,
|
|
|
1842
1845
|
],
|
|
1843
1846
|
],
|
|
1844
1847
|
],
|
|
1845
|
-
"shell"
|
|
1848
|
+
"shell",
|
|
1846
1849
|
);
|
|
1847
1850
|
});
|
|
1848
1851
|
|
|
@@ -1891,7 +1894,7 @@ Body text`,
|
|
|
1891
1894
|
"${foo}",
|
|
1892
1895
|
[markers.traverse, [markers.reference, "foo"]],
|
|
1893
1896
|
"shell",
|
|
1894
|
-
false
|
|
1897
|
+
false,
|
|
1895
1898
|
);
|
|
1896
1899
|
});
|
|
1897
1900
|
|
|
@@ -1965,7 +1968,7 @@ Body text`,
|
|
|
1965
1968
|
`,
|
|
1966
1969
|
null,
|
|
1967
1970
|
"program",
|
|
1968
|
-
false
|
|
1971
|
+
false,
|
|
1969
1972
|
);
|
|
1970
1973
|
});
|
|
1971
1974
|
});
|
|
@@ -1975,7 +1978,7 @@ function assertParse(
|
|
|
1975
1978
|
source,
|
|
1976
1979
|
expected,
|
|
1977
1980
|
mode = "shell",
|
|
1978
|
-
checkLocation = true
|
|
1981
|
+
checkLocation = true,
|
|
1979
1982
|
) {
|
|
1980
1983
|
const code = parse(source, {
|
|
1981
1984
|
grammarSource: { text: source },
|
|
@@ -1990,7 +1993,7 @@ function assertParse(
|
|
|
1990
1993
|
assertCodeLocations(code);
|
|
1991
1994
|
const resultSource = code.location.source.text.slice(
|
|
1992
1995
|
code.location.start.offset,
|
|
1993
|
-
code.location.end.offset
|
|
1996
|
+
code.location.end.offset,
|
|
1994
1997
|
);
|
|
1995
1998
|
assert.equal(resultSource, source);
|
|
1996
1999
|
}
|
|
@@ -2010,7 +2013,7 @@ function assertThrows(startRule, source, message, position, mode = "program") {
|
|
|
2010
2013
|
} catch (/** @type {any} */ error) {
|
|
2011
2014
|
assert(
|
|
2012
2015
|
error.message.includes(message),
|
|
2013
|
-
`Error message incorrect:\n expected: "${message}"\n actual: "${error.message}"
|
|
2016
|
+
`Error message incorrect:\n expected: "${message}"\n actual: "${error.message}"`,
|
|
2014
2017
|
);
|
|
2015
2018
|
if (position) {
|
|
2016
2019
|
assert.equal(error.location.start.line, position.line);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
This file exists to force creation of the containing folder.
|