@weborigami/language 0.7.0-beta.2 → 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 +2 -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/getSource.js +1 -0
- package/src/handlers/ori_handler.js +2 -2
- package/src/handlers/oridocument_handler.js +2 -2
- package/src/handlers/{processOriExport.js → processOrigamiExport.js} +1 -1
- 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/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
|
@@ -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",
|
|
@@ -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`,
|
|
@@ -23,7 +23,7 @@ describe("expressionObject", () => {
|
|
|
23
23
|
];
|
|
24
24
|
const context = new SyncMap();
|
|
25
25
|
|
|
26
|
-
const object = await expressionObject(entries, {
|
|
26
|
+
const object = await expressionObject("test.ori/", entries, {
|
|
27
27
|
object: context,
|
|
28
28
|
parent,
|
|
29
29
|
});
|
|
@@ -36,7 +36,7 @@ describe("expressionObject", () => {
|
|
|
36
36
|
let count = 0;
|
|
37
37
|
const increment = () => count++;
|
|
38
38
|
const entries = [["count", [increment]]];
|
|
39
|
-
const object = await expressionObject(entries);
|
|
39
|
+
const object = await expressionObject("test.ori/", entries);
|
|
40
40
|
const propertyDescriptor = Object.getOwnPropertyDescriptor(object, "count");
|
|
41
41
|
assert.equal(propertyDescriptor?.value, 0);
|
|
42
42
|
assert.equal(object.count, 0);
|
|
@@ -47,7 +47,7 @@ describe("expressionObject", () => {
|
|
|
47
47
|
let count = 0;
|
|
48
48
|
const increment = () => count++;
|
|
49
49
|
const entries = [["count", [ops.getter, [increment]]]];
|
|
50
|
-
const object = await expressionObject(entries);
|
|
50
|
+
const object = await expressionObject("test.ori/", entries);
|
|
51
51
|
object[cachePathSymbol] = "foo.ori/"; // enable caching on this object tree
|
|
52
52
|
assert.equal(await object.count, 0);
|
|
53
53
|
const propertyDescriptor = Object.getOwnPropertyDescriptor(object, "count");
|
|
@@ -58,7 +58,7 @@ describe("expressionObject", () => {
|
|
|
58
58
|
|
|
59
59
|
test("treats a getter for a primitive value as a regular property", async () => {
|
|
60
60
|
const entries = [["name", [ops.getter, "world"]]];
|
|
61
|
-
const object = await expressionObject(entries);
|
|
61
|
+
const object = await expressionObject("test.ori/", entries);
|
|
62
62
|
assert.equal(object.name, "world");
|
|
63
63
|
});
|
|
64
64
|
|
|
@@ -68,7 +68,9 @@ describe("expressionObject", () => {
|
|
|
68
68
|
["message", [ops.deepText, "Hello, ", [[ops.inherited, 0], "name"], "!"]],
|
|
69
69
|
];
|
|
70
70
|
const context = new SyncMap();
|
|
71
|
-
const object = await expressionObject(entries, {
|
|
71
|
+
const object = await expressionObject("test.ori/", entries, {
|
|
72
|
+
object: context,
|
|
73
|
+
});
|
|
72
74
|
assert.deepEqual(await Tree.plain(object), {
|
|
73
75
|
name: "world",
|
|
74
76
|
message: "Hello, world!",
|
|
@@ -92,7 +94,9 @@ describe("expressionObject", () => {
|
|
|
92
94
|
["name", "data"],
|
|
93
95
|
];
|
|
94
96
|
const context = new SyncMap();
|
|
95
|
-
const object = await expressionObject(entries, {
|
|
97
|
+
const object = await expressionObject("test.ori/", entries, {
|
|
98
|
+
object: context,
|
|
99
|
+
});
|
|
96
100
|
assert.deepEqual(await Tree.plain(object), {
|
|
97
101
|
"data.json": 1,
|
|
98
102
|
name: "data",
|
|
@@ -105,7 +109,7 @@ describe("expressionObject", () => {
|
|
|
105
109
|
const globals = {
|
|
106
110
|
json_handler: { unpack: (data) => JSON.parse(data) },
|
|
107
111
|
};
|
|
108
|
-
const result = await expressionObject(entries, {
|
|
112
|
+
const result = await expressionObject("test.ori/", entries, {
|
|
109
113
|
object: context,
|
|
110
114
|
globals,
|
|
111
115
|
});
|
|
@@ -119,7 +123,7 @@ describe("expressionObject", () => {
|
|
|
119
123
|
["(hidden)", "shh"],
|
|
120
124
|
["visible", "hey"],
|
|
121
125
|
];
|
|
122
|
-
const object = await expressionObject(entries);
|
|
126
|
+
const object = await expressionObject("test.ori/", entries);
|
|
123
127
|
assert.deepEqual(Object.keys(object), ["visible"]);
|
|
124
128
|
assert.equal(object["hidden"], "shh");
|
|
125
129
|
});
|
|
@@ -127,15 +131,15 @@ describe("expressionObject", () => {
|
|
|
127
131
|
test("provides a symbols.keys method returning normalized keys", async () => {
|
|
128
132
|
const entries = [
|
|
129
133
|
// Will return a tree, should have a slash
|
|
130
|
-
["getter", [ops.getter, [ops.object, ["b", [ops.literal, 2]]]]],
|
|
134
|
+
["getter", [ops.getter, [ops.object, null, ["b", [ops.literal, 2]]]]],
|
|
131
135
|
["hasSlash/", "This isn't really a tree but says it is"],
|
|
132
136
|
["message", "Hello"],
|
|
133
137
|
// Immediate maplike value, should have a slash
|
|
134
|
-
["object", [ops.object, ["b", [ops.literal, 2]]]],
|
|
138
|
+
["object", [ops.object, null, ["b", [ops.literal, 2]]]],
|
|
135
139
|
// Computed key
|
|
136
140
|
[[ops.deepText, [ops.array, "data", ".json"]], 1],
|
|
137
141
|
];
|
|
138
|
-
const object = await expressionObject(entries);
|
|
142
|
+
const object = await expressionObject("test.ori/", entries);
|
|
139
143
|
assert.deepEqual(object[symbols.keys](), [
|
|
140
144
|
"getter/",
|
|
141
145
|
"hasSlash/",
|
|
@@ -152,7 +156,7 @@ describe("expressionObject", () => {
|
|
|
152
156
|
const getNumber = () =>
|
|
153
157
|
systemCache.getOrInsertComputed("dependency", () => 1);
|
|
154
158
|
const entries = [["number", [ops.getter, [getNumber]]]];
|
|
155
|
-
const object = await expressionObject(entries);
|
|
159
|
+
const object = await expressionObject("test.ori/", entries);
|
|
156
160
|
object[cachePathSymbol] = "src/test.ori/"; // enable caching on this object tree
|
|
157
161
|
const number = await object.number;
|
|
158
162
|
assert.equal(number, 1);
|
|
@@ -162,4 +166,11 @@ describe("expressionObject", () => {
|
|
|
162
166
|
assert(dependencyEntry.downstreams.has("src/test.ori/number"));
|
|
163
167
|
assert(objectEntry.upstreams.has("dependency"));
|
|
164
168
|
});
|
|
169
|
+
|
|
170
|
+
test("generates a unique cache path for an unattached object", async () => {
|
|
171
|
+
const object0 = await expressionObject("test.ori/_objects/", [["a", 1]]);
|
|
172
|
+
assert.equal(object0[cachePathSymbol], "test.ori/_objects/0/");
|
|
173
|
+
const object1 = await expressionObject("test.ori/_objects/", [["a", 1]]);
|
|
174
|
+
assert.equal(object1[cachePathSymbol], "test.ori/_objects/1/");
|
|
175
|
+
});
|
|
165
176
|
});
|
|
@@ -4,11 +4,9 @@ import { describe, test } from "node:test";
|
|
|
4
4
|
import * as handlers from "../../src/handlers/handlers.js";
|
|
5
5
|
import handleExtension from "../../src/runtime/handleExtension.js";
|
|
6
6
|
import OrigamiFileMap from "../../src/runtime/OrigamiFileMap.js";
|
|
7
|
-
import { cachePathSymbol } from "../../src/runtime/symbols.js";
|
|
8
7
|
|
|
9
8
|
const fixturesUrl = new URL("fixtures/unpack", import.meta.url);
|
|
10
9
|
const fixtureFiles = new OrigamiFileMap(fixturesUrl);
|
|
11
|
-
fixtureFiles[cachePathSymbol] = "fixtures";
|
|
12
10
|
fixtureFiles.globals = handlers;
|
|
13
11
|
|
|
14
12
|
describe("handleExtension", () => {
|
package/test/runtime/ops.test.js
CHANGED
|
@@ -56,7 +56,7 @@ describe("ops", () => {
|
|
|
56
56
|
|
|
57
57
|
test("ops.cache", async () => {
|
|
58
58
|
const fn = () => 1;
|
|
59
|
-
const code = createCode([ops.object, ["a", [ops.getter, [fn]]]]);
|
|
59
|
+
const code = createCode([ops.object, null, ["a", [ops.getter, [fn]]]]);
|
|
60
60
|
const result = await ops.cache("a.ori/_refs/b.ori/", code, {});
|
|
61
61
|
assert.deepEqual(await Tree.plain(result), { a: 1 });
|
|
62
62
|
const cachedResult = await systemCache.get("a.ori/_refs/b.ori/");
|
|
@@ -333,15 +333,16 @@ describe("ops", () => {
|
|
|
333
333
|
const code = createCode([
|
|
334
334
|
[
|
|
335
335
|
ops.object,
|
|
336
|
+
null,
|
|
336
337
|
["a", [ops.literal, 1]],
|
|
337
338
|
["c", [[ops.inherited, 0], "a"]],
|
|
338
339
|
[
|
|
339
340
|
"_result",
|
|
340
341
|
[
|
|
341
342
|
ops.merge,
|
|
342
|
-
[ops.object, ["a", [ops.getter, [[ops.inherited, 1], "a"]]]],
|
|
343
|
+
[ops.object, null, ["a", [ops.getter, [[ops.inherited, 1], "a"]]]],
|
|
343
344
|
[[ops.scope], "more"],
|
|
344
|
-
[ops.object, ["c", [ops.getter, [[ops.inherited, 1], "c"]]]],
|
|
345
|
+
[ops.object, null, ["c", [ops.getter, [[ops.inherited, 1], "c"]]]],
|
|
345
346
|
],
|
|
346
347
|
],
|
|
347
348
|
],
|
|
@@ -390,6 +391,7 @@ describe("ops", () => {
|
|
|
390
391
|
|
|
391
392
|
const code = createCode([
|
|
392
393
|
ops.object,
|
|
394
|
+
null,
|
|
393
395
|
["hello", [[[ops.scope], "upper"], "hello"]],
|
|
394
396
|
["world", [[[ops.scope], "upper"], "world"]],
|
|
395
397
|
]);
|
|
@@ -2,12 +2,35 @@ import { SyncMap } from "@weborigami/async-tree";
|
|
|
2
2
|
import SyncCacheTransform from "../../src/runtime/SyncCacheTransform.js";
|
|
3
3
|
|
|
4
4
|
export default function syncCalcs(iterable) {
|
|
5
|
-
const data = new (SyncCacheTransform(
|
|
6
|
-
const calcs = new (SyncCacheTransform(
|
|
5
|
+
const data = new (SyncCacheTransform(SyncDataMap))(new Map(iterable));
|
|
6
|
+
const calcs = new (SyncCacheTransform(SyncCalcsMap))(data);
|
|
7
7
|
return { calcs, data };
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
class
|
|
10
|
+
class SyncDataMap extends SyncMap {
|
|
11
|
+
constructor(source) {
|
|
12
|
+
super();
|
|
13
|
+
this.source = source;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
delete(key) {
|
|
17
|
+
return this.source.delete(key);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get(key) {
|
|
21
|
+
return this.source.get(key);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
keys() {
|
|
25
|
+
return this.source.keys();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
set(key, value) {
|
|
29
|
+
return this.source.set(key, value);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
class SyncCalcsMap extends SyncMap {
|
|
11
34
|
constructor(source) {
|
|
12
35
|
super();
|
|
13
36
|
this.source = source;
|
|
@@ -48,12 +48,16 @@ describe("systemCache", () => {
|
|
|
48
48
|
|
|
49
49
|
// Add new data.json to src folder, overriding the one in project root
|
|
50
50
|
src.set("data.json", "2");
|
|
51
|
+
// Manually trigger cache invalidation
|
|
52
|
+
src.onValueChange("data.json");
|
|
51
53
|
|
|
52
54
|
const value2 = await site.value;
|
|
53
55
|
assert.equal(value2, 2);
|
|
54
56
|
|
|
55
57
|
// Delete data.json from src folder, reverting to the one in project root
|
|
56
58
|
src.delete("data.json");
|
|
59
|
+
// Manually trigger cache invalidation
|
|
60
|
+
src.onValueChange("data.json");
|
|
57
61
|
|
|
58
62
|
const value3 = await site.value;
|
|
59
63
|
assert.equal(value3, 1);
|