@weborigami/language 0.6.17 → 0.7.0-beta.2

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 (90) hide show
  1. package/index.ts +1 -0
  2. package/main.js +7 -1
  3. package/package.json +7 -6
  4. package/src/compiler/compile.js +10 -3
  5. package/src/compiler/optimize.js +71 -40
  6. package/src/compiler/parse.js +1 -1
  7. package/src/compiler/parserHelpers.js +5 -3
  8. package/src/handlers/addExtensionKeyFn.js +18 -0
  9. package/src/handlers/epub_handler.js +54 -0
  10. package/src/handlers/getSource.js +11 -0
  11. package/src/handlers/handlers.js +2 -0
  12. package/src/handlers/htm_handler.js +1 -1
  13. package/src/handlers/js_handler.js +13 -4
  14. package/src/handlers/mediaTypeExtensions.json +15 -0
  15. package/src/handlers/ori_handler.js +8 -7
  16. package/src/handlers/oridocument_handler.js +19 -28
  17. package/src/handlers/processOriExport.js +17 -0
  18. package/src/handlers/tsv_handler.js +1 -1
  19. package/src/handlers/txt_handler.js +4 -2
  20. package/src/handlers/xhtml_handler.js +1 -1
  21. package/src/handlers/yaml_handler.js +6 -3
  22. package/src/handlers/zip_handler.js +112 -0
  23. package/src/project/activeProjectRoot.js +9 -0
  24. package/src/project/getGlobalsForTree.js +5 -0
  25. package/src/project/{projectGlobals.js → initializeGlobalsForTree.js} +8 -13
  26. package/src/project/jsGlobals.js +1 -0
  27. package/src/project/projectConfig.js +2 -2
  28. package/src/project/projectRootFromPath.js +2 -0
  29. package/src/protocols/constructHref.js +3 -3
  30. package/src/protocols/constructSiteTree.js +11 -2
  31. package/src/protocols/explore.js +1 -1
  32. package/src/protocols/explorehttp.js +1 -1
  33. package/src/protocols/fetchAndHandleExtension.js +23 -11
  34. package/src/protocols/files.js +1 -0
  35. package/src/protocols/http.js +4 -1
  36. package/src/protocols/https.js +4 -1
  37. package/src/protocols/httpstree.js +1 -1
  38. package/src/protocols/httptree.js +1 -1
  39. package/src/protocols/package.js +15 -3
  40. package/src/runtime/AsyncCacheTransform.d.ts +5 -0
  41. package/src/runtime/AsyncCacheTransform.js +134 -0
  42. package/src/runtime/HandleExtensionsTransform.d.ts +3 -1
  43. package/src/runtime/HandleExtensionsTransform.js +18 -2
  44. package/src/runtime/OrigamiFileMap.d.ts +5 -2
  45. package/src/runtime/OrigamiFileMap.js +27 -4
  46. package/src/runtime/ScopeMap.js +72 -0
  47. package/src/runtime/SyncCacheTransform.d.ts +8 -0
  48. package/src/runtime/SyncCacheTransform.js +133 -0
  49. package/src/runtime/SystemCacheMap.js +259 -0
  50. package/src/runtime/WatchFilesMixin.js +52 -19
  51. package/src/runtime/enableValueCaching.js +192 -0
  52. package/src/runtime/execute.js +2 -2
  53. package/src/runtime/executionContext.js +7 -0
  54. package/src/runtime/explainReferenceError.js +7 -2
  55. package/src/runtime/expressionObject.js +54 -46
  56. package/src/runtime/handleExtension.js +65 -34
  57. package/src/runtime/interop.js +2 -2
  58. package/src/runtime/mergeTrees.js +1 -1
  59. package/src/runtime/ops.js +28 -33
  60. package/src/runtime/symbols.js +3 -0
  61. package/src/runtime/systemCache.js +3 -0
  62. package/src/runtime/volatile.js +14 -0
  63. package/test/compiler/codeHelpers.js +2 -1
  64. package/test/compiler/optimize.test.js +62 -54
  65. package/test/handlers/epub_handler.test.js +27 -0
  66. package/test/handlers/fixtures/test.zip +0 -0
  67. package/test/handlers/ori_handler.test.js +22 -3
  68. package/test/handlers/oridocument_handler.test.js +1 -1
  69. package/test/handlers/zip_handler.test.js +45 -0
  70. package/test/protocols/https.test.js +19 -0
  71. package/test/protocols/package.test.js +7 -2
  72. package/test/runtime/AsyncCacheTransform.test.js +91 -0
  73. package/test/runtime/OrigamiFileMap.test.js +26 -23
  74. package/test/runtime/ScopeMap.test.js +49 -0
  75. package/test/runtime/SyncCacheTransform.test.js +93 -0
  76. package/test/runtime/SystemCacheMap.test.js +239 -0
  77. package/test/runtime/asyncCalcs.js +28 -0
  78. package/test/runtime/enableValueCaching.test.js +55 -0
  79. package/test/runtime/errors.test.js +53 -30
  80. package/test/runtime/evaluate.test.js +9 -4
  81. package/test/runtime/execute.test.js +6 -1
  82. package/test/runtime/expressionObject.test.js +55 -15
  83. package/test/runtime/fetchAndHandleExtension.test.js +24 -0
  84. package/test/runtime/fixtures/unpack/hello.json +1 -0
  85. package/test/runtime/handleExtension.test.js +12 -1
  86. package/test/runtime/ops.test.js +70 -65
  87. package/test/runtime/syncCalcs.js +27 -0
  88. package/test/runtime/systemCache.test.js +66 -0
  89. package/src/runtime/assignPropertyDescriptors.js +0 -23
  90. package/src/runtime/asyncStorage.js +0 -7
@@ -1,40 +1,43 @@
1
1
  import assert from "node:assert";
2
2
  import * as fs from "node:fs";
3
3
  import path from "node:path";
4
- import { describe, test } from "node:test";
4
+ import { afterEach, beforeEach, describe, test } from "node:test";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import OrigamiFileMap from "../../src/runtime/OrigamiFileMap.js";
7
7
 
8
8
  const dirname = path.dirname(fileURLToPath(import.meta.url));
9
- const tempDirectory = path.join(dirname, "fixtures/temp/OrigamiFileMap");
9
+ const tempDirectory = path.join(dirname, "fixtures/temp");
10
10
 
11
11
  describe("OrigamiFileMap", () => {
12
- test.skip("can watch its folder for changes", { timeout: 2000 }, async () => {
13
- createTempDirectory();
12
+ let tempFiles;
14
13
 
15
- const tempFiles = new OrigamiFileMap(tempDirectory);
16
- const changedFileName = await new Promise(async (resolve) => {
14
+ beforeEach(() => {
15
+ // Remove any existing files or directories inside the temp directory so
16
+ // tests start from a clean slate. Use force so this is safe if the
17
+ // directory doesn't exist.
18
+ fs.rmSync(tempDirectory, { force: true, recursive: true });
19
+ fs.mkdirSync(tempDirectory, { recursive: true });
20
+ tempFiles = new OrigamiFileMap(tempDirectory);
21
+ });
22
+
23
+ afterEach(() => {
24
+ // HACK: should removeEventListener, which should stop watching
25
+ tempFiles.unwatch();
26
+ fs.rmSync(tempDirectory, { force: true, recursive: true });
27
+ });
28
+
29
+ test("can watch its folder for changes", { timeout: 2000 }, async () => {
30
+ const changedFilePath = await new Promise(async (resolve) => {
17
31
  tempFiles.addEventListener("change", (event) => {
18
- resolve(/** @type {any} */ (event).options.key);
32
+ resolve(/** @type {any} */ (event).options.filePath);
19
33
  });
34
+ await tempFiles.watch();
20
35
  tempFiles.set(
21
- "foo.txt",
22
- "This file is left over from testing and can be removed."
36
+ "temp.txt",
37
+ "This file is left over from testing and can be removed.",
23
38
  );
24
39
  });
25
- removeTempDirectory();
26
- assert.equal(changedFileName, "foo.txt");
40
+
41
+ assert.equal(path.basename(changedFilePath), "temp.txt");
27
42
  });
28
43
  });
29
-
30
- function createTempDirectory() {
31
- // Remove any existing files or directories inside the temp directory so
32
- // tests start from a clean slate. Use force so this is safe if the
33
- // directory doesn't exist.
34
- fs.rmSync(tempDirectory, { force: true, recursive: true });
35
- fs.mkdirSync(tempDirectory, { recursive: true });
36
- }
37
-
38
- function removeTempDirectory() {
39
- fs.rmSync(tempDirectory, { force: true, recursive: true });
40
- }
@@ -0,0 +1,49 @@
1
+ import { ObjectMap } from "@weborigami/async-tree";
2
+ import assert from "node:assert";
3
+ import { describe, test } from "node:test";
4
+ import ScopeMap from "../../src/runtime/ScopeMap.js";
5
+ import { cachePathSymbol } from "../../src/runtime/symbols.js";
6
+ import SyncCacheTransform from "../../src/runtime/SyncCacheTransform.js";
7
+ import systemCache from "../../src/runtime/systemCache.js";
8
+
9
+ describe("scope", () => {
10
+ test("gets the first defined value from the scope trees", async () => {
11
+ class SyncCacheObjectMap extends SyncCacheTransform(ObjectMap) {}
12
+
13
+ /** @type {any} */
14
+ const outer = new SyncCacheObjectMap({
15
+ a: 1,
16
+ b: 2,
17
+ });
18
+ outer[cachePathSymbol] = "outer";
19
+
20
+ /** @type {any} */
21
+ const inner = new SyncCacheObjectMap({
22
+ a: 3,
23
+ });
24
+ inner[cachePathSymbol] = "outer/inner";
25
+
26
+ inner.parent = outer;
27
+ const innerScope = new ScopeMap(inner);
28
+
29
+ // Inner tree has precedence
30
+ const a = systemCache.getOrInsertComputed("test/a", () =>
31
+ innerScope.get("a"),
32
+ );
33
+ assert.equal(a, 3);
34
+
35
+ // If tree doesn't have value, finds value from parent
36
+ const b = systemCache.getOrInsertComputed("test/b", () =>
37
+ innerScope.get("b"),
38
+ );
39
+ assert.equal(b, 2);
40
+
41
+ const c = systemCache.getOrInsertComputed("test/c", () =>
42
+ innerScope.get("c"),
43
+ );
44
+ assert.equal(c, undefined);
45
+
46
+ assert.deepEqual([...innerScope.keys()], ["a", "b"]);
47
+ assert.deepEqual(/** @type {any} */ (innerScope).trees, [inner, outer]);
48
+ });
49
+ });
@@ -0,0 +1,93 @@
1
+ import assert from "node:assert";
2
+ import { beforeEach, describe, test } from "node:test";
3
+ import systemCache from "../../src/runtime/systemCache.js";
4
+
5
+ // We test SyncCacheTransform via syncCalcs since it's a fairly small
6
+ // application of the transform.
7
+ import syncCalcs from "./syncCalcs.js";
8
+
9
+ describe("SyncCacheTransform", () => {
10
+ beforeEach(() => {
11
+ systemCache.clear();
12
+ });
13
+
14
+ test("caches values and records dependencies", () => {
15
+ // { a = 2 * b, b = c + 1, c = 3 }
16
+ let log = [];
17
+ const { calcs, data } = syncCalcs([
18
+ [
19
+ "a",
20
+ () => {
21
+ log.push("a");
22
+ const b = calcs.get("b");
23
+ return 2 * b;
24
+ },
25
+ ],
26
+ [
27
+ "b",
28
+ () => {
29
+ log.push("b");
30
+ const c = calcs.get("c");
31
+ return c + 1;
32
+ },
33
+ ],
34
+ [
35
+ "c",
36
+ () => {
37
+ log.push("c");
38
+ return 3;
39
+ },
40
+ ],
41
+ ]);
42
+
43
+ assert.deepEqual(
44
+ [...calcs.entries()],
45
+ [
46
+ ["a", 8],
47
+ ["b", 4],
48
+ ["c", 3],
49
+ ],
50
+ );
51
+ assert.deepEqual(log, ["a", "b", "c"]);
52
+
53
+ log = [];
54
+ const a1 = calcs.get("a");
55
+ assert.strictEqual(a1, 8);
56
+ assert.deepEqual(log, []); // a is cached, no new calcs
57
+
58
+ // Replace formula for a
59
+ // { a = 3 * b, b = c + 1, c = 3 }
60
+ data.set("a", () => {
61
+ log.push("a");
62
+ const b = calcs.get("b");
63
+ return 3 * b;
64
+ });
65
+ log = [];
66
+ const a2 = calcs.get("a");
67
+ assert.strictEqual(a2, 12);
68
+ assert.deepEqual(log, ["a"]); // recalc only a
69
+
70
+ // Replace formula for b
71
+ // { a = 3 * b, b = c + 10, c = 3 }
72
+ data.set("b", () => {
73
+ log.push("b");
74
+ const c = calcs.get("c");
75
+ return c + 10;
76
+ });
77
+ log = [];
78
+ const a3 = calcs.get("a");
79
+ assert.strictEqual(a3, 39);
80
+ assert.deepEqual(log, ["a", "b"]); // recalc a and b
81
+
82
+ // Replace value of c
83
+ // { a = 3 * b, b = c + 10, c = 100 }
84
+ data.set("c", () => {
85
+ log.push("c");
86
+ return 100;
87
+ });
88
+ log = [];
89
+ const a4 = calcs.get("a");
90
+ assert.strictEqual(a4, 330);
91
+ assert.deepEqual(log, ["a", "b", "c"]); // recalc all
92
+ });
93
+ });
@@ -0,0 +1,239 @@
1
+ import assert from "node:assert";
2
+ import { describe, test } from "node:test";
3
+ import SystemCacheMap from "../../src/runtime/SystemCacheMap.js";
4
+ import volatile from "../../src/runtime/volatile.js";
5
+
6
+ describe("SystemCacheMap", () => {
7
+ test("getOrInsertComputed tracks sync dependencies", async () => {
8
+ const cache = new SystemCacheMap();
9
+ let log;
10
+
11
+ // Create cache entries for
12
+ // { a = b + 1, b = 2 }
13
+ let getB = () =>
14
+ cache.getOrInsertComputed("b", () => {
15
+ log.push("b");
16
+ return 2;
17
+ });
18
+ let getA = () =>
19
+ cache.getOrInsertComputed("a", () => {
20
+ log.push("a");
21
+ const b = getB();
22
+ return b + 1;
23
+ });
24
+
25
+ log = [];
26
+ const a1 = getA();
27
+ assert.strictEqual(a1, 3);
28
+ assert.deepEqual(log, ["a", "b"]);
29
+ assert.deepEqual(cacheEntries(cache), [
30
+ ["a", { value: 3, upstreams: ["b"] }],
31
+ ["b", { value: 2, downstreams: ["a"] }],
32
+ ]);
33
+
34
+ log = [];
35
+ const a2 = getA();
36
+ assert.strictEqual(a2, 3);
37
+ assert.deepEqual(log, []); // no recalculation
38
+
39
+ // Delete a
40
+ cache.delete("a");
41
+ assert.deepEqual(cacheEntries(cache), [["b", { value: 2 }]]);
42
+ });
43
+
44
+ test("getOrInsertComputedAsync tracks async dependencies", async () => {
45
+ const cache = new SystemCacheMap();
46
+ let log;
47
+
48
+ // Create cache entries for
49
+ // { a = 2 * b, b = c + 1, c = 3 }
50
+ let getC = async () =>
51
+ await cache.getOrInsertComputedAsync("c", async () => {
52
+ log.push("c");
53
+ return 3;
54
+ });
55
+ let getB = async () =>
56
+ await cache.getOrInsertComputedAsync("b", async () => {
57
+ log.push("b");
58
+ const c = await getC();
59
+ return c + 1;
60
+ });
61
+ let getA = async () =>
62
+ await cache.getOrInsertComputedAsync("a", async () => {
63
+ log.push("a");
64
+ const b = await getB();
65
+ return 2 * b;
66
+ });
67
+
68
+ // Initial read of `a` populates cache
69
+ log = [];
70
+ const a1 = await getA();
71
+ assert.strictEqual(a1, 8);
72
+ assert.deepEqual(log, ["a", "b", "c"]);
73
+ assert.deepEqual(cacheEntries(cache), [
74
+ ["a", { value: 8, upstreams: ["b"] }],
75
+ ["b", { value: 4, downstreams: ["a"], upstreams: ["c"] }],
76
+ ["c", { value: 3, downstreams: ["b"] }],
77
+ ]);
78
+
79
+ // Subsequent read of `a` hits cache
80
+ log = [];
81
+ const a2 = await getA();
82
+ assert.strictEqual(a2, 8);
83
+ assert.deepEqual(log, []); // no recalculation
84
+
85
+ // Delete a
86
+ cache.delete("a");
87
+ assert.deepEqual(cacheEntries(cache), [
88
+ ["b", { value: 4, upstreams: ["c"] }],
89
+ ["c", { value: 3, downstreams: ["b"] }],
90
+ ]);
91
+
92
+ // Replace formula for a
93
+ // { a = 3 * b, b = c + 1, c = 3 }
94
+ getA = async () =>
95
+ await cache.getOrInsertComputedAsync("a", async () => {
96
+ log.push("a");
97
+ const b = await getB();
98
+ return 3 * b;
99
+ });
100
+ log = [];
101
+ const a3 = await getA();
102
+ assert.strictEqual(a3, 12);
103
+ assert.deepEqual(log, ["a"]); // recalc only a
104
+
105
+ // Delete b, confirm it's removed as both upstream and downstream
106
+ cache.delete("b");
107
+ assert.deepEqual(cacheEntries(cache), [["c", { value: 3 }]]);
108
+
109
+ // Replace formula for b
110
+ // { a = 3 * b, b = c + 10, c = 3 }
111
+ getB = async () =>
112
+ await cache.getOrInsertComputedAsync("b", async () => {
113
+ log.push("b");
114
+ const c = await getC();
115
+ return c + 10;
116
+ });
117
+ log = [];
118
+ const a4 = await getA();
119
+ assert.strictEqual(a4, 39);
120
+ assert.deepEqual(log, ["a", "b"]); // recalc a and b
121
+
122
+ // Replace formula for c
123
+ // { a = 3 * b, b = c + 10, c = 100 }
124
+ getC = async () =>
125
+ await cache.getOrInsertComputedAsync("c", async () => {
126
+ log.push("c");
127
+ return 100;
128
+ });
129
+ cache.delete("c");
130
+ log = [];
131
+ const a5 = await getA();
132
+ assert.strictEqual(a5, 330);
133
+ assert.deepEqual(log, ["a", "b", "c"]); // recalc all
134
+ });
135
+
136
+ test("async function can track sync dependency", async () => {
137
+ const cache = new SystemCacheMap();
138
+
139
+ // Create cache entries for
140
+ // { a = b + 1, b = 2 }
141
+ const getB = () =>
142
+ cache.getOrInsertComputed("b", () => {
143
+ return 2;
144
+ });
145
+ const getA = async () =>
146
+ cache.getOrInsertComputedAsync("a", async () => {
147
+ const b = getB();
148
+ return b + 1;
149
+ });
150
+
151
+ const a1 = await getA();
152
+ assert.strictEqual(a1, 3);
153
+ });
154
+
155
+ test("sync function can't have async dependency", async () => {
156
+ const cache = new SystemCacheMap();
157
+
158
+ // Create cache entries for
159
+ // { a = b, b = 1 }
160
+ const getB = async () =>
161
+ await cache.getOrInsertComputedAsync("b", async () => {
162
+ return 1;
163
+ });
164
+ const getA = () => cache.getOrInsertComputed("a", () => getB());
165
+
166
+ // a is sync but b is async
167
+ await assert.rejects(getA);
168
+ });
169
+
170
+ test("implicit dependency of child path on parent path", async () => {
171
+ const cache = new SystemCacheMap();
172
+
173
+ // Create cache entries
174
+ // parent = 1, parent/child = 2, other = 3
175
+ const getParent = () => cache.getOrInsertComputed("parent", () => 1);
176
+ cache.getOrInsertComputed("parent/child", () => {
177
+ // Force access of parent, no explicit dependency should be recorded
178
+ getParent();
179
+ return 2;
180
+ });
181
+ cache.getOrInsertComputed("other", () => 3);
182
+
183
+ assert.deepEqual(cacheEntries(cache), [
184
+ ["parent/child", { value: 2 }],
185
+ ["parent", { value: 1 }],
186
+ ["other", { value: 3 }],
187
+ ]);
188
+
189
+ // Deleting parent implicitly deletes all children
190
+ cache.delete("parent");
191
+ assert.deepEqual(cacheEntries(cache), [["other", { value: 3 }]]);
192
+ });
193
+
194
+ test("sync volatile values are not cached", async () => {
195
+ const cache = new SystemCacheMap();
196
+ let count = 0;
197
+ const getCount = () =>
198
+ cache.getOrInsertComputed("count", () => volatile(count++));
199
+
200
+ const first = getCount();
201
+ const second = getCount();
202
+ assert.strictEqual(Number(first), 0);
203
+ assert.strictEqual(Number(second), 1);
204
+ assert.strictEqual(count, 2); // computeFn ran twice, value not cached
205
+ });
206
+
207
+ test("async volatile values are not cached", async () => {
208
+ const cache = new SystemCacheMap();
209
+ let count = 0;
210
+ const getCount = () =>
211
+ cache.getOrInsertComputedAsync("count", async () => volatile(count++));
212
+
213
+ const first = await getCount();
214
+ const second = await getCount();
215
+ assert.strictEqual(Number(first), 0);
216
+ assert.strictEqual(Number(second), 1);
217
+ assert.strictEqual(count, 2); // computeFn ran twice, value not cached
218
+ });
219
+ });
220
+
221
+ export function cacheEntries(cache) {
222
+ const entries = [...cache.entries()];
223
+ return entries.map(([key, entry]) => [key, cacheEntry(entry)]);
224
+ }
225
+
226
+ export function cacheEntry(entry) {
227
+ const { downstreams, value } = entry;
228
+
229
+ const result = { value };
230
+ if (downstreams?.size > 0) {
231
+ result.downstreams = [...downstreams];
232
+ }
233
+
234
+ if (entry.upstreams?.size > 0) {
235
+ result.upstreams = [...entry.upstreams];
236
+ }
237
+
238
+ return result;
239
+ }
@@ -0,0 +1,28 @@
1
+ import { AsyncMap, SyncMap } from "@weborigami/async-tree";
2
+ import AsyncCacheTransform from "../../src/runtime/AsyncCacheTransform.js";
3
+ import SyncCacheTransform from "../../src/runtime/SyncCacheTransform.js";
4
+
5
+ export default function asyncCalcs(iterable) {
6
+ const data = new (SyncCacheTransform(SyncMap))(iterable);
7
+ const calcs = new (AsyncCacheTransform(AsyncResultsMap))(data);
8
+ return { calcs, data };
9
+ }
10
+
11
+ class AsyncResultsMap extends AsyncMap {
12
+ constructor(source) {
13
+ super();
14
+ this.source = source;
15
+ }
16
+
17
+ async get(key) {
18
+ let value = this.source.get(key);
19
+ if (typeof value === "function") {
20
+ value = await value();
21
+ }
22
+ return value;
23
+ }
24
+
25
+ async *keys() {
26
+ yield* this.source.keys();
27
+ }
28
+ }
@@ -0,0 +1,55 @@
1
+ import assert from "node:assert";
2
+ import { beforeEach, describe, test } from "node:test";
3
+ import enableValueCaching from "../../src/runtime/enableValueCaching.js";
4
+ import { cachePathSymbol } from "../../src/runtime/symbols.js";
5
+ import systemCache from "../../src/runtime/systemCache.js";
6
+
7
+ describe("enableValueCaching", () => {
8
+ beforeEach(() => {
9
+ systemCache.clear();
10
+ });
11
+
12
+ test("leaves primitive values as is", () => {
13
+ const value1 = enableValueCaching(1, "foo.ori/");
14
+ assert.equal(value1, 1);
15
+
16
+ const value2 = enableValueCaching("hello", "foo.ori/");
17
+ assert.equal(value2, "hello");
18
+ });
19
+
20
+ test("adds cachePath to plain object", () => {
21
+ const obj = { a: 1, b: 2 };
22
+ const value = enableValueCaching(obj, "foo.ori/");
23
+ assert.equal(value, obj);
24
+ assert.equal(value[cachePathSymbol], "foo.ori/");
25
+ });
26
+
27
+ test("adds cachePath to array", () => {
28
+ const arr = [1, 2, 3];
29
+ const value = enableValueCaching(arr, "foo.ori/");
30
+ assert.equal(value, arr);
31
+ assert.equal(value[cachePathSymbol], "foo.ori/");
32
+ });
33
+
34
+ test("applies cache transform to Map", () => {
35
+ const map = new Map([
36
+ ["a", 1],
37
+ ["b", 2],
38
+ ]);
39
+ const value = enableValueCaching(map, "foo.ori/");
40
+ assert(value instanceof Map);
41
+ assert.equal(value[cachePathSymbol], "foo.ori/");
42
+ assert.equal(value.get("a"), 1);
43
+ assert(systemCache.has("foo.ori/a"));
44
+ });
45
+
46
+ test("applies cache to function with string arguments", () => {
47
+ function fn(x, y) {
48
+ return `${x} ${y}`;
49
+ }
50
+ const value = enableValueCaching(fn, "foo.ori/");
51
+ assert(typeof value === "function");
52
+ assert.equal(value("Hello", "world"), "Hello world");
53
+ assert.equal(value[cachePathSymbol], "foo.ori/");
54
+ });
55
+ });