@weborigami/language 0.7.0-beta.1 → 0.7.0-beta.3
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/main.js +1 -0
- package/package.json +3 -2
- package/src/compiler/compile.js +0 -3
- package/src/compiler/optimize.js +56 -23
- package/src/compiler/parserHelpers.js +11 -8
- package/src/handlers/addExtensionKeyFn.js +18 -0
- package/src/handlers/epub_handler.js +54 -0
- package/src/handlers/getSource.js +1 -0
- package/src/handlers/handlers.js +2 -0
- package/src/handlers/ori_handler.js +2 -2
- package/src/handlers/oridocument_handler.js +5 -21
- package/src/handlers/{processOriExport.js → processOrigamiExport.js} +1 -1
- package/src/handlers/zip_handler.js +112 -0
- package/src/runtime/AsyncCacheTransform.d.ts +5 -1
- package/src/runtime/AsyncCacheTransform.js +22 -25
- package/src/runtime/OrigamiFileMap.js +3 -3
- package/src/runtime/SyncCacheTransform.d.ts +2 -1
- package/src/runtime/SyncCacheTransform.js +31 -34
- package/src/runtime/SystemCacheMap.js +28 -17
- package/src/runtime/counters.js +3 -0
- package/src/runtime/enableValueCaching.js +8 -7
- package/src/runtime/errors.js +33 -1
- package/src/runtime/execute.js +3 -0
- package/src/runtime/explainReferenceError.js +11 -24
- package/src/runtime/explainTraverseError.js +15 -6
- package/src/runtime/expressionObject.js +53 -34
- package/src/runtime/handleExtension.js +18 -9
- package/src/runtime/ops.js +4 -3
- package/test/compiler/compile.test.js +0 -1
- package/test/compiler/optimize.test.js +60 -15
- package/test/compiler/parse.test.js +38 -9
- package/test/handlers/epub_handler.test.js +27 -0
- package/test/handlers/fixtures/test.zip +0 -0
- package/test/handlers/zip_handler.test.js +45 -0
- package/test/runtime/AsyncCacheTransform.test.js +9 -4
- package/test/runtime/SyncCacheTransform.test.js +4 -0
- package/test/runtime/asyncCalcs.js +26 -4
- package/test/runtime/errors.test.js +4 -4
- package/test/runtime/expressionObject.test.js +23 -12
- package/test/runtime/handleExtension.test.js +0 -2
- package/test/runtime/ops.test.js +5 -3
- package/test/runtime/syncCalcs.js +26 -3
- package/test/runtime/systemCache.test.js +4 -0
|
@@ -15,6 +15,16 @@ import {
|
|
|
15
15
|
} from "./codeHelpers.js";
|
|
16
16
|
|
|
17
17
|
describe("optimize", () => {
|
|
18
|
+
test("define cache path based on source", () => {
|
|
19
|
+
const expression = "{ a = { b: 1 } }";
|
|
20
|
+
const expected = [
|
|
21
|
+
ops.object,
|
|
22
|
+
"/folder/test.ori/",
|
|
23
|
+
["a", [ops.getter, [ops.object, "/folder/test.ori/a/", ["b", 1]]]],
|
|
24
|
+
];
|
|
25
|
+
assertCompile(expression, expected);
|
|
26
|
+
});
|
|
27
|
+
|
|
18
28
|
test("change local references to context references", () => {
|
|
19
29
|
const expression = `(name) => {
|
|
20
30
|
a: name,
|
|
@@ -26,6 +36,7 @@ describe("optimize", () => {
|
|
|
26
36
|
[["name", [[ops.params, 0], 0]]],
|
|
27
37
|
[
|
|
28
38
|
ops.object,
|
|
39
|
+
"/folder/test.ori/_objects/",
|
|
29
40
|
[
|
|
30
41
|
"a",
|
|
31
42
|
[
|
|
@@ -49,11 +60,13 @@ describe("optimize", () => {
|
|
|
49
60
|
const expression = `{ a: 1, more: { a } }`;
|
|
50
61
|
const expected = [
|
|
51
62
|
ops.object,
|
|
63
|
+
"/folder/test.ori/",
|
|
52
64
|
["a", 1],
|
|
53
65
|
[
|
|
54
66
|
"more",
|
|
55
67
|
[
|
|
56
68
|
ops.object,
|
|
69
|
+
"/folder/test.ori/more/",
|
|
57
70
|
[
|
|
58
71
|
"a",
|
|
59
72
|
[
|
|
@@ -76,11 +89,13 @@ describe("optimize", () => {
|
|
|
76
89
|
}`;
|
|
77
90
|
const expected = [
|
|
78
91
|
ops.object,
|
|
92
|
+
"/folder/test.ori/",
|
|
79
93
|
["name", "Alice"],
|
|
80
94
|
[
|
|
81
95
|
"user",
|
|
82
96
|
[
|
|
83
97
|
ops.object,
|
|
98
|
+
"/folder/test.ori/user/",
|
|
84
99
|
[
|
|
85
100
|
"name",
|
|
86
101
|
[
|
|
@@ -95,7 +110,7 @@ describe("optimize", () => {
|
|
|
95
110
|
assertCompile(expression, expected, "shell");
|
|
96
111
|
});
|
|
97
112
|
|
|
98
|
-
describe
|
|
113
|
+
describe("resolve reference", () => {
|
|
99
114
|
test("external reference", () => {
|
|
100
115
|
// Compilation of `folder` where folder isn't a variable
|
|
101
116
|
const code = createCode([
|
|
@@ -115,6 +130,31 @@ describe("optimize", () => {
|
|
|
115
130
|
);
|
|
116
131
|
});
|
|
117
132
|
|
|
133
|
+
test("external reference with path", () => {
|
|
134
|
+
// Compilation of `src/templates/page.ori` where src isn't a variable
|
|
135
|
+
const code = createCode([
|
|
136
|
+
markers.traverse,
|
|
137
|
+
[markers.reference, "src/"],
|
|
138
|
+
[ops.literal, "templates/"],
|
|
139
|
+
[ops.literal, "page.ori"],
|
|
140
|
+
]);
|
|
141
|
+
const parent = {};
|
|
142
|
+
const expected = [
|
|
143
|
+
[
|
|
144
|
+
ops.cache,
|
|
145
|
+
"test.ori/_refs/src/",
|
|
146
|
+
[[ops.scope], [ops.literal, "src/"]],
|
|
147
|
+
],
|
|
148
|
+
[ops.literal, "templates/"],
|
|
149
|
+
[ops.literal, "page.ori"],
|
|
150
|
+
];
|
|
151
|
+
const globals = {};
|
|
152
|
+
assertCodeEqual(
|
|
153
|
+
optimize(code, { cachePath: "test.ori", globals, parent }),
|
|
154
|
+
expected,
|
|
155
|
+
);
|
|
156
|
+
});
|
|
157
|
+
|
|
118
158
|
test("external reference with implied unpack", () => {
|
|
119
159
|
// Compilation of `greet.ori("world")`
|
|
120
160
|
const code = createCode([
|
|
@@ -141,6 +181,7 @@ describe("optimize", () => {
|
|
|
141
181
|
// Compilation of `{ (posts) = posts.txt }`
|
|
142
182
|
const code = createCode([
|
|
143
183
|
ops.object,
|
|
184
|
+
null,
|
|
144
185
|
[
|
|
145
186
|
"(posts)",
|
|
146
187
|
[ops.getter, [markers.traverse, [markers.reference, "posts.txt"]]],
|
|
@@ -149,13 +190,14 @@ describe("optimize", () => {
|
|
|
149
190
|
const parent = {};
|
|
150
191
|
const expected = [
|
|
151
192
|
ops.object,
|
|
193
|
+
"/folder/test.ori/",
|
|
152
194
|
[
|
|
153
195
|
"(posts)",
|
|
154
196
|
[
|
|
155
197
|
ops.getter,
|
|
156
198
|
[
|
|
157
199
|
ops.cache,
|
|
158
|
-
"test.ori/_refs/posts.txt",
|
|
200
|
+
"/folder/test.ori/_refs/posts.txt",
|
|
159
201
|
[[ops.scope], [ops.literal, "posts.txt"]],
|
|
160
202
|
],
|
|
161
203
|
],
|
|
@@ -163,7 +205,7 @@ describe("optimize", () => {
|
|
|
163
205
|
];
|
|
164
206
|
const globals = {};
|
|
165
207
|
assertCodeEqual(
|
|
166
|
-
optimize(code, { cachePath: "test.ori", globals, parent }),
|
|
208
|
+
optimize(code, { cachePath: "/folder/test.ori", globals, parent }),
|
|
167
209
|
expected,
|
|
168
210
|
);
|
|
169
211
|
});
|
|
@@ -233,9 +275,9 @@ describe("optimize", () => {
|
|
|
233
275
|
[ops.literal, "passwd"],
|
|
234
276
|
]);
|
|
235
277
|
const expected = [
|
|
236
|
-
ops.cache,
|
|
237
|
-
"
|
|
238
|
-
[
|
|
278
|
+
[ops.cache, "test.ori/_refs//", [ops.rootDirectory]],
|
|
279
|
+
[ops.literal, "etc/"],
|
|
280
|
+
[ops.literal, "passwd"],
|
|
239
281
|
];
|
|
240
282
|
assertCodeEqual(optimize(code, { cachePath: "test.ori" }), expected);
|
|
241
283
|
});
|
|
@@ -259,14 +301,13 @@ describe("optimize", () => {
|
|
|
259
301
|
]);
|
|
260
302
|
const parent = {};
|
|
261
303
|
const expected = [
|
|
262
|
-
ops.cache,
|
|
263
|
-
"test.ori/_refs/path/to/file",
|
|
264
304
|
[
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
[ops.literal, "
|
|
268
|
-
[ops.literal, "file"],
|
|
305
|
+
ops.cache,
|
|
306
|
+
"test.ori/_refs/path/",
|
|
307
|
+
[[ops.scope], [ops.literal, "path/"]],
|
|
269
308
|
],
|
|
309
|
+
[ops.literal, "to/"],
|
|
310
|
+
[ops.literal, "file"],
|
|
270
311
|
];
|
|
271
312
|
assertCodeEqual(
|
|
272
313
|
optimize(code, { cachePath: "test.ori", parent }),
|
|
@@ -284,9 +325,12 @@ describe("optimize", () => {
|
|
|
284
325
|
const globals = {};
|
|
285
326
|
const parent = {};
|
|
286
327
|
const expected = [
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
328
|
+
[
|
|
329
|
+
ops.cache,
|
|
330
|
+
"test.ori/_refs/package.json/",
|
|
331
|
+
[[ops.scope], [ops.literal, "package.json/"]],
|
|
332
|
+
],
|
|
333
|
+
[ops.literal, "name"],
|
|
290
334
|
];
|
|
291
335
|
assertCodeEqual(
|
|
292
336
|
optimize(code, { cachePath: "test.ori", globals, parent }),
|
|
@@ -319,6 +363,7 @@ function assertCompile(expression, expected, mode = "shell") {
|
|
|
319
363
|
typeof expression !== "string"
|
|
320
364
|
? expression
|
|
321
365
|
: {
|
|
366
|
+
cachePath: "/folder/test.ori",
|
|
322
367
|
text: expression,
|
|
323
368
|
relativePath: "test.ori",
|
|
324
369
|
};
|
|
@@ -604,7 +604,7 @@ describe("Origami parser", () => {
|
|
|
604
604
|
[ops.literal, "key"],
|
|
605
605
|
]);
|
|
606
606
|
assertParse("callExpression", "{ a: 1, b: 2}/b", [
|
|
607
|
-
[ops.object, ["a", [ops.literal, 1]], ["b", [ops.literal, 2]]],
|
|
607
|
+
[ops.object, null, ["a", [ops.literal, 1]], ["b", [ops.literal, 2]]],
|
|
608
608
|
[ops.literal, "b"],
|
|
609
609
|
]);
|
|
610
610
|
assertParse("callExpression", "files:foo/bar", [
|
|
@@ -897,12 +897,13 @@ Body`,
|
|
|
897
897
|
assertParse("expression", "1", [ops.literal, 1]);
|
|
898
898
|
assertParse("expression", "{ a: 1, b: 2 }", [
|
|
899
899
|
ops.object,
|
|
900
|
+
null,
|
|
900
901
|
["a", [ops.literal, 1]],
|
|
901
902
|
["b", [ops.literal, 2]],
|
|
902
903
|
]);
|
|
903
904
|
assertParse("expression", "serve { index.html: 'hello' }", [
|
|
904
905
|
[markers.traverse, [markers.reference, "serve"]],
|
|
905
|
-
[ops.object, ["index.html", [ops.literal, "hello"]]],
|
|
906
|
+
[ops.object, null, ["index.html", [ops.literal, "hello"]]],
|
|
906
907
|
]);
|
|
907
908
|
assertParse("expression", "fn =`x`", [
|
|
908
909
|
[markers.traverse, [markers.reference, "fn"]],
|
|
@@ -991,6 +992,7 @@ Body`,
|
|
|
991
992
|
}`,
|
|
992
993
|
[
|
|
993
994
|
ops.object,
|
|
995
|
+
null,
|
|
994
996
|
[
|
|
995
997
|
"index.html",
|
|
996
998
|
[
|
|
@@ -1010,6 +1012,7 @@ Body`,
|
|
|
1010
1012
|
[markers.traverse, [markers.reference, "images"]],
|
|
1011
1013
|
[
|
|
1012
1014
|
ops.object,
|
|
1015
|
+
null,
|
|
1013
1016
|
[
|
|
1014
1017
|
"value",
|
|
1015
1018
|
[markers.traverse, [markers.reference, "thumbnail.js"]],
|
|
@@ -1253,27 +1256,32 @@ Body`,
|
|
|
1253
1256
|
|
|
1254
1257
|
describe("objectLiteral", () => {
|
|
1255
1258
|
test("basic objects", () => {
|
|
1256
|
-
assertParse("objectLiteral", "{}", [ops.object]);
|
|
1259
|
+
assertParse("objectLiteral", "{}", [ops.object, null]);
|
|
1257
1260
|
assertParse("objectLiteral", "{ a: 1, b }", [
|
|
1258
1261
|
ops.object,
|
|
1262
|
+
null,
|
|
1259
1263
|
["a", [ops.literal, 1]],
|
|
1260
1264
|
["b", [markers.traverse, [markers.reference, "b"]]],
|
|
1261
1265
|
]);
|
|
1262
1266
|
assertParse("objectLiteral", "{ sub: { a: 1 } }", [
|
|
1263
1267
|
ops.object,
|
|
1264
|
-
|
|
1268
|
+
null,
|
|
1269
|
+
["sub", [ops.object, null, ["a", [ops.literal, 1]]]],
|
|
1265
1270
|
]);
|
|
1266
1271
|
assertParse("objectLiteral", "{ sub: { a/: 1 } }", [
|
|
1267
1272
|
ops.object,
|
|
1268
|
-
|
|
1273
|
+
null,
|
|
1274
|
+
["sub", [ops.object, null, ["a/", [ops.literal, 1]]]],
|
|
1269
1275
|
]);
|
|
1270
1276
|
assertParse("objectLiteral", `{ "a": 1, "b": 2 }`, [
|
|
1271
1277
|
ops.object,
|
|
1278
|
+
null,
|
|
1272
1279
|
["a", [ops.literal, 1]],
|
|
1273
1280
|
["b", [ops.literal, 2]],
|
|
1274
1281
|
]);
|
|
1275
1282
|
assertParse("objectLiteral", "{ a = b, b = 2 }", [
|
|
1276
1283
|
ops.object,
|
|
1284
|
+
null,
|
|
1277
1285
|
["a", [ops.getter, [markers.traverse, [markers.reference, "b"]]]],
|
|
1278
1286
|
["b", [ops.literal, 2]],
|
|
1279
1287
|
]);
|
|
@@ -1285,24 +1293,29 @@ Body`,
|
|
|
1285
1293
|
}`,
|
|
1286
1294
|
[
|
|
1287
1295
|
ops.object,
|
|
1296
|
+
null,
|
|
1288
1297
|
["a", [ops.getter, [markers.traverse, [markers.reference, "b"]]]],
|
|
1289
1298
|
["b", [ops.literal, 2]],
|
|
1290
1299
|
],
|
|
1291
1300
|
);
|
|
1292
1301
|
assertParse("objectLiteral", "{ a: { b: 1 } }", [
|
|
1293
1302
|
ops.object,
|
|
1294
|
-
|
|
1303
|
+
null,
|
|
1304
|
+
["a", [ops.object, null, ["b", [ops.literal, 1]]]],
|
|
1295
1305
|
]);
|
|
1296
1306
|
assertParse("objectLiteral", "{ a: { b = 1 } }", [
|
|
1297
1307
|
ops.object,
|
|
1298
|
-
|
|
1308
|
+
null,
|
|
1309
|
+
["a", [ops.object, null, ["b", [ops.literal, 1]]]],
|
|
1299
1310
|
]);
|
|
1300
1311
|
assertParse("objectLiteral", "{ a: { b = fn() } }", [
|
|
1301
1312
|
ops.object,
|
|
1313
|
+
null,
|
|
1302
1314
|
[
|
|
1303
1315
|
"a",
|
|
1304
1316
|
[
|
|
1305
1317
|
ops.object,
|
|
1318
|
+
null,
|
|
1306
1319
|
[
|
|
1307
1320
|
"b",
|
|
1308
1321
|
[ops.getter, [[markers.traverse, [markers.reference, "fn"]]]],
|
|
@@ -1312,6 +1325,7 @@ Body`,
|
|
|
1312
1325
|
]);
|
|
1313
1326
|
assertParse("objectLiteral", "{ x = fn.js('a') }", [
|
|
1314
1327
|
ops.object,
|
|
1328
|
+
null,
|
|
1315
1329
|
[
|
|
1316
1330
|
"x",
|
|
1317
1331
|
[
|
|
@@ -1326,10 +1340,12 @@ Body`,
|
|
|
1326
1340
|
|
|
1327
1341
|
assertParse("objectLiteral", "{ (a): 1 }", [
|
|
1328
1342
|
ops.object,
|
|
1343
|
+
null,
|
|
1329
1344
|
["(a)", [ops.literal, 1]],
|
|
1330
1345
|
]);
|
|
1331
1346
|
assertParse("objectLiteral", "{ <path/to/file.txt> }", [
|
|
1332
1347
|
ops.object,
|
|
1348
|
+
null,
|
|
1333
1349
|
[
|
|
1334
1350
|
"file.txt",
|
|
1335
1351
|
[
|
|
@@ -1350,15 +1366,24 @@ Body`,
|
|
|
1350
1366
|
assertParse("objectLiteral", "{ a: 1, ...more, c: a }", [
|
|
1351
1367
|
[
|
|
1352
1368
|
ops.object,
|
|
1369
|
+
null,
|
|
1353
1370
|
["a", [ops.literal, 1]],
|
|
1354
1371
|
["c", [markers.traverse, [markers.reference, "a"]]],
|
|
1355
1372
|
[
|
|
1356
1373
|
"_result",
|
|
1357
1374
|
[
|
|
1358
1375
|
ops.merge,
|
|
1359
|
-
[
|
|
1376
|
+
[
|
|
1377
|
+
ops.object,
|
|
1378
|
+
null,
|
|
1379
|
+
["a", [ops.getter, [[ops.inherited, 1], "a"]]],
|
|
1380
|
+
],
|
|
1360
1381
|
[markers.traverse, [markers.reference, "more"]],
|
|
1361
|
-
[
|
|
1382
|
+
[
|
|
1383
|
+
ops.object,
|
|
1384
|
+
null,
|
|
1385
|
+
["c", [ops.getter, [[ops.inherited, 1], "c"]]],
|
|
1386
|
+
],
|
|
1362
1387
|
],
|
|
1363
1388
|
],
|
|
1364
1389
|
],
|
|
@@ -1366,6 +1391,7 @@ Body`,
|
|
|
1366
1391
|
]);
|
|
1367
1392
|
assertParse("objectLiteral", "{ a: 1, ...{ b: 2 } }", [
|
|
1368
1393
|
ops.object,
|
|
1394
|
+
null,
|
|
1369
1395
|
["a", [ops.literal, 1]],
|
|
1370
1396
|
["b", [ops.literal, 2]],
|
|
1371
1397
|
]);
|
|
@@ -1374,6 +1400,7 @@ Body`,
|
|
|
1374
1400
|
test("computed property keys", () => {
|
|
1375
1401
|
assertParse("objectLiteral", "{ [key]: value }", [
|
|
1376
1402
|
ops.object,
|
|
1403
|
+
null,
|
|
1377
1404
|
[
|
|
1378
1405
|
[markers.traverse, [markers.reference, "key"]],
|
|
1379
1406
|
[markers.traverse, [markers.reference, "value"]],
|
|
@@ -1816,6 +1843,7 @@ title: Title goes here
|
|
|
1816
1843
|
Body text`,
|
|
1817
1844
|
[
|
|
1818
1845
|
ops.object,
|
|
1846
|
+
null,
|
|
1819
1847
|
["title", [ops.literal, "Title goes here"]],
|
|
1820
1848
|
["_body", [ops.templateIndent, [ops.literal, ["Body text"]]]],
|
|
1821
1849
|
],
|
|
@@ -1835,6 +1863,7 @@ Body text`,
|
|
|
1835
1863
|
`,
|
|
1836
1864
|
[
|
|
1837
1865
|
ops.object,
|
|
1866
|
+
null,
|
|
1838
1867
|
["title", [ops.literal, "Title"]],
|
|
1839
1868
|
[
|
|
1840
1869
|
"_body",
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import Zip from "adm-zip";
|
|
2
|
+
import assert from "node:assert";
|
|
3
|
+
import { describe, test } from "node:test";
|
|
4
|
+
import epub_handler from "../../src/handlers/epub_handler.js";
|
|
5
|
+
|
|
6
|
+
describe("EPUB handler", () => {
|
|
7
|
+
test("ensures mimetype file comes first", async () => {
|
|
8
|
+
const tree = {
|
|
9
|
+
EPUB: {
|
|
10
|
+
"index.xhtml": "This is where the book content goes",
|
|
11
|
+
},
|
|
12
|
+
"META-INF": {
|
|
13
|
+
"container.xml": "This is where the metadata goes",
|
|
14
|
+
},
|
|
15
|
+
mimetype: "application/epub+zip",
|
|
16
|
+
};
|
|
17
|
+
const buffer = await epub_handler.pack(tree);
|
|
18
|
+
const unzipped = new Zip(buffer);
|
|
19
|
+
const entries = unzipped.getEntries();
|
|
20
|
+
const entryNames = entries.map((entry) => entry.entryName);
|
|
21
|
+
assert.deepEqual(entryNames, [
|
|
22
|
+
"mimetype",
|
|
23
|
+
"EPUB/index.xhtml",
|
|
24
|
+
"META-INF/container.xml",
|
|
25
|
+
]);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
Binary file
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Tree } from "@weborigami/async-tree";
|
|
2
|
+
import Zip from "adm-zip";
|
|
3
|
+
import assert from "node:assert";
|
|
4
|
+
import fs from "node:fs/promises";
|
|
5
|
+
import { describe, test } from "node:test";
|
|
6
|
+
import zip_handler from "../../src/handlers/zip_handler.js";
|
|
7
|
+
|
|
8
|
+
describe("ZIP handler", () => {
|
|
9
|
+
test("creates a ZIP file as Buffer", async () => {
|
|
10
|
+
const tree = {
|
|
11
|
+
"ReadMe.md": "This is a ReadMe file.",
|
|
12
|
+
sub: {
|
|
13
|
+
"file.txt": "This is a text file in a subfolder.",
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
const buffer = await zip_handler.pack(tree);
|
|
17
|
+
const unzipped = new Zip(buffer);
|
|
18
|
+
const entries = unzipped.getEntries();
|
|
19
|
+
assert.equal(entries.length, 2);
|
|
20
|
+
assert.equal(entries[0].entryName, "ReadMe.md");
|
|
21
|
+
assert.equal(
|
|
22
|
+
entries[0].getData().toString("utf8"),
|
|
23
|
+
"This is a ReadMe file.",
|
|
24
|
+
);
|
|
25
|
+
assert.equal(entries[1].entryName, "sub/file.txt");
|
|
26
|
+
assert.equal(
|
|
27
|
+
entries[1].getData().toString("utf8"),
|
|
28
|
+
"This is a text file in a subfolder.",
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("reads a ZIP file", async () => {
|
|
33
|
+
const fixturePath = new URL("fixtures/test.zip", import.meta.url);
|
|
34
|
+
const buffer = await fs.readFile(fixturePath);
|
|
35
|
+
const tree = await zip_handler.unpack(buffer);
|
|
36
|
+
const plain = await Tree.plain(tree);
|
|
37
|
+
assert.deepEqual(Object.keys(plain), ["ReadMe.md", "sub"]);
|
|
38
|
+
assert.deepEqual(Object.keys(plain.sub), ["file.txt"]);
|
|
39
|
+
assert.equal(String(plain["ReadMe.md"]), "This is a ReadMe file.\n");
|
|
40
|
+
assert.equal(
|
|
41
|
+
String(plain.sub["file.txt"]),
|
|
42
|
+
"This is a text file in a subfolder.\n",
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
@@ -41,7 +41,8 @@ describe("AsyncCacheTransform", () => {
|
|
|
41
41
|
],
|
|
42
42
|
]);
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
const entries = await Tree.entries(calcs);
|
|
45
|
+
assert.deepEqual(entries, [
|
|
45
46
|
["a", 8],
|
|
46
47
|
["b", 4],
|
|
47
48
|
["c", 3],
|
|
@@ -55,11 +56,13 @@ describe("AsyncCacheTransform", () => {
|
|
|
55
56
|
|
|
56
57
|
// Replace formula for a
|
|
57
58
|
// { a = 3 * b, b = c + 1, c = 3 }
|
|
58
|
-
data.set("a", async () => {
|
|
59
|
+
await data.set("a", async () => {
|
|
59
60
|
log.push("a");
|
|
60
61
|
const b = await calcs.get("b");
|
|
61
62
|
return 3 * b;
|
|
62
63
|
});
|
|
64
|
+
// Manually trigger cache invalidation
|
|
65
|
+
data.onValueChange("a");
|
|
63
66
|
log = [];
|
|
64
67
|
const a2 = await calcs.get("a");
|
|
65
68
|
assert.strictEqual(a2, 12);
|
|
@@ -67,11 +70,12 @@ describe("AsyncCacheTransform", () => {
|
|
|
67
70
|
|
|
68
71
|
// Replace formula for b
|
|
69
72
|
// { a = 3 * b, b = c + 10, c = 3 }
|
|
70
|
-
data.set("b", async () => {
|
|
73
|
+
await data.set("b", async () => {
|
|
71
74
|
log.push("b");
|
|
72
75
|
const c = await calcs.get("c");
|
|
73
76
|
return c + 10;
|
|
74
77
|
});
|
|
78
|
+
data.onValueChange("b");
|
|
75
79
|
log = [];
|
|
76
80
|
const a3 = await calcs.get("a");
|
|
77
81
|
assert.strictEqual(a3, 39);
|
|
@@ -79,10 +83,11 @@ describe("AsyncCacheTransform", () => {
|
|
|
79
83
|
|
|
80
84
|
// Replace value of c
|
|
81
85
|
// { a = 3 * b, b = c + 10, c = 100 }
|
|
82
|
-
data.set("c", async () => {
|
|
86
|
+
await data.set("c", async () => {
|
|
83
87
|
log.push("c");
|
|
84
88
|
return 100;
|
|
85
89
|
});
|
|
90
|
+
data.onValueChange("c");
|
|
86
91
|
log = [];
|
|
87
92
|
const a4 = await calcs.get("a");
|
|
88
93
|
assert.strictEqual(a4, 330);
|
|
@@ -62,6 +62,8 @@ describe("SyncCacheTransform", () => {
|
|
|
62
62
|
const b = calcs.get("b");
|
|
63
63
|
return 3 * b;
|
|
64
64
|
});
|
|
65
|
+
// Manually trigger cache invalidation
|
|
66
|
+
data.onValueChange("a");
|
|
65
67
|
log = [];
|
|
66
68
|
const a2 = calcs.get("a");
|
|
67
69
|
assert.strictEqual(a2, 12);
|
|
@@ -74,6 +76,7 @@ describe("SyncCacheTransform", () => {
|
|
|
74
76
|
const c = calcs.get("c");
|
|
75
77
|
return c + 10;
|
|
76
78
|
});
|
|
79
|
+
data.onValueChange("b");
|
|
77
80
|
log = [];
|
|
78
81
|
const a3 = calcs.get("a");
|
|
79
82
|
assert.strictEqual(a3, 39);
|
|
@@ -85,6 +88,7 @@ describe("SyncCacheTransform", () => {
|
|
|
85
88
|
log.push("c");
|
|
86
89
|
return 100;
|
|
87
90
|
});
|
|
91
|
+
data.onValueChange("c");
|
|
88
92
|
log = [];
|
|
89
93
|
const a4 = calcs.get("a");
|
|
90
94
|
assert.strictEqual(a4, 330);
|
|
@@ -1,13 +1,35 @@
|
|
|
1
|
-
import { AsyncMap
|
|
1
|
+
import { AsyncMap } from "@weborigami/async-tree";
|
|
2
2
|
import AsyncCacheTransform from "../../src/runtime/AsyncCacheTransform.js";
|
|
3
|
-
import SyncCacheTransform from "../../src/runtime/SyncCacheTransform.js";
|
|
4
3
|
|
|
5
4
|
export default function asyncCalcs(iterable) {
|
|
6
|
-
const data = new (
|
|
5
|
+
const data = new (AsyncCacheTransform(AsyncDataMap))(new Map(iterable));
|
|
7
6
|
const calcs = new (AsyncCacheTransform(AsyncResultsMap))(data);
|
|
8
7
|
return { calcs, data };
|
|
9
8
|
}
|
|
10
9
|
|
|
10
|
+
class AsyncDataMap extends AsyncMap {
|
|
11
|
+
constructor(source) {
|
|
12
|
+
super();
|
|
13
|
+
this.source = source;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async delete(key) {
|
|
17
|
+
return this.source.delete(key);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async get(key) {
|
|
21
|
+
return this.source.get(key);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async *keys() {
|
|
25
|
+
yield* this.source.keys();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async set(key, value) {
|
|
29
|
+
return this.source.set(key, value);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
11
33
|
class AsyncResultsMap extends AsyncMap {
|
|
12
34
|
constructor(source) {
|
|
13
35
|
super();
|
|
@@ -15,7 +37,7 @@ class AsyncResultsMap extends AsyncMap {
|
|
|
15
37
|
}
|
|
16
38
|
|
|
17
39
|
async get(key) {
|
|
18
|
-
let value = this.source.get(key);
|
|
40
|
+
let value = await this.source.get(key);
|
|
19
41
|
if (typeof value === "function") {
|
|
20
42
|
value = await value();
|
|
21
43
|
}
|
|
@@ -188,7 +188,7 @@ evaluating: \x1B[31mposts.md\x1B[0m
|
|
|
188
188
|
`(post1/totle).toUpperCase()`,
|
|
189
189
|
`ReferenceError: Tried to get a property of something that doesn't exist.
|
|
190
190
|
This path returned undefined: post1/totle
|
|
191
|
-
evaluating: \x1B[
|
|
191
|
+
evaluating: \x1B[31m(post1/totle)\x1B[0m`,
|
|
192
192
|
{ parent },
|
|
193
193
|
);
|
|
194
194
|
});
|
|
@@ -238,7 +238,7 @@ evaluating: \x1B[31msup/\x1B[0m`,
|
|
|
238
238
|
Tried to traverse path: map/1/a
|
|
239
239
|
Stopped unexpectedly at: 1/
|
|
240
240
|
Slash-separated keys are searched as strings. Here there's no string "1" key, but there is a number 1 key.
|
|
241
|
-
To get the value for that number key, use parentheses: map/(1)
|
|
241
|
+
To get the value for that number key, use parentheses: map/(1)/a
|
|
242
242
|
evaluating: \x1B[31m1/\x1B[0m`,
|
|
243
243
|
{ parent },
|
|
244
244
|
);
|
|
@@ -250,8 +250,8 @@ evaluating: \x1B[31m1/\x1B[0m`,
|
|
|
250
250
|
});
|
|
251
251
|
await assertError(
|
|
252
252
|
`file.foo/bar`,
|
|
253
|
-
`TraverseError: A path
|
|
254
|
-
Tried to traverse path: file.foo/
|
|
253
|
+
`TraverseError: A path tried to unpack data but there's no unpack function.
|
|
254
|
+
Tried to traverse path: file.foo/
|
|
255
255
|
Stopped unexpectedly at: file.foo/
|
|
256
256
|
The value couldn't be unpacked because no file extension handler is registered for ".foo".
|
|
257
257
|
evaluating: \x1B[31mfile.foo/\x1B[0m`,
|