@weborigami/async-tree 0.5.8 → 0.6.1

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 (182) hide show
  1. package/browser.js +1 -1
  2. package/index.ts +43 -35
  3. package/main.js +1 -2
  4. package/package.json +4 -7
  5. package/shared.js +74 -12
  6. package/src/Tree.js +11 -2
  7. package/src/drivers/AsyncMap.js +237 -0
  8. package/src/drivers/{BrowserFileTree.js → BrowserFileMap.js} +54 -38
  9. package/src/drivers/{calendarTree.js → CalendarMap.js} +80 -63
  10. package/src/drivers/ConstantMap.js +28 -0
  11. package/src/drivers/{ExplorableSiteTree.js → ExplorableSiteMap.js} +7 -7
  12. package/src/drivers/FileMap.js +238 -0
  13. package/src/drivers/{FunctionTree.js → FunctionMap.js} +19 -22
  14. package/src/drivers/ObjectMap.js +151 -0
  15. package/src/drivers/SetMap.js +13 -0
  16. package/src/drivers/{SiteTree.js → SiteMap.js} +17 -20
  17. package/src/drivers/SyncMap.js +260 -0
  18. package/src/jsonKeys.d.ts +2 -2
  19. package/src/jsonKeys.js +20 -5
  20. package/src/operations/addNextPrevious.js +35 -36
  21. package/src/operations/assign.js +27 -23
  22. package/src/operations/cache.js +30 -36
  23. package/src/operations/cachedKeyFunctions.js +1 -1
  24. package/src/operations/calendar.js +5 -0
  25. package/src/operations/child.js +35 -0
  26. package/src/operations/clear.js +13 -12
  27. package/src/operations/constant.js +5 -0
  28. package/src/operations/deepEntries.js +23 -0
  29. package/src/operations/deepMap.js +9 -9
  30. package/src/operations/deepMerge.js +36 -25
  31. package/src/operations/deepReverse.js +23 -16
  32. package/src/operations/deepTake.js +7 -7
  33. package/src/operations/deepText.js +4 -4
  34. package/src/operations/deepValues.js +3 -6
  35. package/src/operations/deepValuesIterator.js +11 -11
  36. package/src/operations/delete.js +8 -12
  37. package/src/operations/entries.js +17 -10
  38. package/src/operations/filter.js +9 -7
  39. package/src/operations/first.js +12 -10
  40. package/src/operations/forEach.js +10 -13
  41. package/src/operations/from.js +30 -39
  42. package/src/operations/globKeys.js +22 -17
  43. package/src/operations/group.js +2 -2
  44. package/src/operations/groupBy.js +24 -22
  45. package/src/operations/has.js +7 -9
  46. package/src/operations/indent.js +2 -2
  47. package/src/operations/inners.js +19 -15
  48. package/src/operations/invokeFunctions.js +22 -10
  49. package/src/operations/isAsyncMutableTree.js +5 -12
  50. package/src/operations/isAsyncTree.js +5 -20
  51. package/src/operations/isMap.js +39 -0
  52. package/src/operations/isMaplike.js +34 -0
  53. package/src/operations/isReadOnlyMap.js +14 -0
  54. package/src/operations/isTraversable.js +3 -3
  55. package/src/operations/isTreelike.js +5 -30
  56. package/src/operations/json.js +4 -12
  57. package/src/operations/keys.js +17 -8
  58. package/src/operations/length.js +9 -8
  59. package/src/operations/map.js +28 -30
  60. package/src/operations/mapExtension.js +20 -16
  61. package/src/operations/mapReduce.js +38 -24
  62. package/src/operations/mask.js +54 -29
  63. package/src/operations/match.js +13 -9
  64. package/src/operations/merge.js +43 -35
  65. package/src/operations/paginate.js +26 -18
  66. package/src/operations/parent.js +7 -7
  67. package/src/operations/paths.js +20 -22
  68. package/src/operations/plain.js +6 -6
  69. package/src/operations/reduce.js +16 -0
  70. package/src/operations/regExpKeys.js +21 -12
  71. package/src/operations/reverse.js +21 -15
  72. package/src/operations/root.js +6 -5
  73. package/src/operations/scope.js +31 -26
  74. package/src/operations/set.js +20 -0
  75. package/src/operations/shuffle.js +23 -16
  76. package/src/operations/size.js +13 -0
  77. package/src/operations/sort.js +55 -40
  78. package/src/operations/sync.js +14 -0
  79. package/src/operations/take.js +23 -11
  80. package/src/operations/text.js +4 -4
  81. package/src/operations/toFunction.js +7 -7
  82. package/src/operations/traverse.js +4 -4
  83. package/src/operations/traverseOrThrow.js +18 -9
  84. package/src/operations/traversePath.js +2 -2
  85. package/src/operations/values.js +18 -9
  86. package/src/operations/withKeys.js +22 -16
  87. package/src/symbols.js +1 -0
  88. package/src/utilities/castArraylike.js +24 -13
  89. package/src/utilities/getMapArgument.js +38 -0
  90. package/src/utilities/getParent.js +2 -2
  91. package/src/utilities/isStringlike.js +7 -5
  92. package/src/utilities/setParent.js +7 -7
  93. package/src/utilities/toFunction.js +2 -2
  94. package/src/utilities/toPlainValue.js +21 -19
  95. package/test/SampleAsyncMap.js +34 -0
  96. package/test/browser/assert.js +20 -0
  97. package/test/browser/index.html +53 -21
  98. package/test/drivers/AsyncMap.test.js +119 -0
  99. package/test/drivers/{BrowserFileTree.test.js → BrowserFileMap.test.js} +50 -33
  100. package/test/drivers/{calendarTree.test.js → CalendarMap.test.js} +17 -19
  101. package/test/drivers/ConstantMap.test.js +15 -0
  102. package/test/drivers/{ExplorableSiteTree.test.js → ExplorableSiteMap.test.js} +29 -14
  103. package/test/drivers/FileMap.test.js +156 -0
  104. package/test/drivers/FunctionMap.test.js +56 -0
  105. package/test/drivers/ObjectMap.test.js +194 -0
  106. package/test/drivers/SetMap.test.js +35 -0
  107. package/test/drivers/{SiteTree.test.js → SiteMap.test.js} +14 -10
  108. package/test/drivers/SyncMap.test.js +335 -0
  109. package/test/jsonKeys.test.js +18 -6
  110. package/test/operations/addNextPrevious.test.js +3 -2
  111. package/test/operations/assign.test.js +30 -35
  112. package/test/operations/cache.test.js +17 -12
  113. package/test/operations/cachedKeyFunctions.test.js +12 -9
  114. package/test/operations/child.test.js +34 -0
  115. package/test/operations/clear.test.js +6 -27
  116. package/test/operations/deepEntries.test.js +32 -0
  117. package/test/operations/deepMerge.test.js +23 -16
  118. package/test/operations/deepReverse.test.js +2 -2
  119. package/test/operations/deepTake.test.js +2 -2
  120. package/test/operations/deepText.test.js +4 -4
  121. package/test/operations/deepValuesIterator.test.js +2 -2
  122. package/test/operations/delete.test.js +2 -2
  123. package/test/operations/extensionKeyFunctions.test.js +6 -5
  124. package/test/operations/filter.test.js +3 -3
  125. package/test/operations/from.test.js +25 -31
  126. package/test/operations/globKeys.test.js +9 -9
  127. package/test/operations/groupBy.test.js +6 -5
  128. package/test/operations/inners.test.js +17 -14
  129. package/test/operations/invokeFunctions.test.js +2 -2
  130. package/test/operations/isMap.test.js +15 -0
  131. package/test/operations/isMaplike.test.js +15 -0
  132. package/test/operations/json.test.js +2 -2
  133. package/test/operations/keys.test.js +16 -3
  134. package/test/operations/map.test.js +40 -30
  135. package/test/operations/mapExtension.test.js +6 -6
  136. package/test/operations/mapReduce.test.js +14 -12
  137. package/test/operations/mask.test.js +16 -3
  138. package/test/operations/match.test.js +2 -2
  139. package/test/operations/merge.test.js +20 -14
  140. package/test/operations/paginate.test.js +5 -5
  141. package/test/operations/parent.test.js +3 -3
  142. package/test/operations/paths.test.js +20 -27
  143. package/test/operations/plain.test.js +8 -8
  144. package/test/operations/regExpKeys.test.js +22 -18
  145. package/test/operations/reverse.test.js +4 -3
  146. package/test/operations/scope.test.js +6 -5
  147. package/test/operations/set.test.js +11 -0
  148. package/test/operations/shuffle.test.js +3 -2
  149. package/test/operations/sort.test.js +7 -10
  150. package/test/operations/sync.test.js +43 -0
  151. package/test/operations/take.test.js +2 -2
  152. package/test/operations/toFunction.test.js +2 -2
  153. package/test/operations/traverse.test.js +17 -5
  154. package/test/operations/withKeys.test.js +2 -2
  155. package/test/utilities/castArrayLike.test.js +53 -0
  156. package/test/utilities/setParent.test.js +6 -6
  157. package/test/utilities/toFunction.test.js +2 -2
  158. package/test/utilities/toPlainValue.test.js +51 -12
  159. package/src/drivers/DeepMapTree.js +0 -23
  160. package/src/drivers/DeepObjectTree.js +0 -18
  161. package/src/drivers/DeferredTree.js +0 -81
  162. package/src/drivers/FileTree.js +0 -276
  163. package/src/drivers/MapTree.js +0 -70
  164. package/src/drivers/ObjectTree.js +0 -158
  165. package/src/drivers/SetTree.js +0 -34
  166. package/src/drivers/constantTree.js +0 -19
  167. package/src/drivers/limitConcurrency.js +0 -63
  168. package/src/internal.js +0 -16
  169. package/src/utilities/getTreeArgument.js +0 -43
  170. package/test/drivers/DeepMapTree.test.js +0 -17
  171. package/test/drivers/DeepObjectTree.test.js +0 -35
  172. package/test/drivers/DeferredTree.test.js +0 -22
  173. package/test/drivers/FileTree.test.js +0 -192
  174. package/test/drivers/FunctionTree.test.js +0 -46
  175. package/test/drivers/MapTree.test.js +0 -59
  176. package/test/drivers/ObjectTree.test.js +0 -163
  177. package/test/drivers/SetTree.test.js +0 -44
  178. package/test/drivers/constantTree.test.js +0 -13
  179. package/test/drivers/limitConcurrency.test.js +0 -41
  180. package/test/operations/isAsyncMutableTree.test.js +0 -17
  181. package/test/operations/isAsyncTree.test.js +0 -26
  182. package/test/operations/isTreelike.test.js +0 -13
@@ -0,0 +1,335 @@
1
+ import assert from "node:assert";
2
+ import { describe, test } from "node:test";
3
+ import SyncMap from "../../src/drivers/SyncMap.js";
4
+
5
+ describe("SyncMap", () => {
6
+ test("passes instanceof Map", () => {
7
+ const map = new SyncMap();
8
+ assert(map instanceof Map);
9
+ });
10
+
11
+ test("can be constructed with an iterable", () => {
12
+ const map = new SyncMap([
13
+ ["a", 1],
14
+ ["b", 2],
15
+ ]);
16
+ assert.strictEqual(map.size, 2);
17
+ assert.strictEqual(map.get("a"), 1);
18
+ assert.strictEqual(map.get("b"), 2);
19
+ });
20
+
21
+ test("can be constructed with another SyncMap", () => {
22
+ const map1 = new SyncMap([
23
+ ["a", 1],
24
+ ["b", 2],
25
+ ]);
26
+ const map2 = new SyncMap(map1);
27
+ const entries = Array.from(map2.entries());
28
+ assert.deepStrictEqual(entries, [
29
+ ["a", 1],
30
+ ["b", 2],
31
+ ]);
32
+ });
33
+
34
+ test("clear calls delete for each key", () => {
35
+ const deletedKeys = [];
36
+ const keys = ["a", "b", "c"];
37
+ class Fixture extends SyncMap {
38
+ delete(key) {
39
+ deletedKeys.push(key);
40
+ return keys.includes(key);
41
+ }
42
+
43
+ keys() {
44
+ return keys[Symbol.iterator]();
45
+ }
46
+ }
47
+ const map = new Fixture();
48
+ map.clear();
49
+ assert.deepStrictEqual(deletedKeys, ["a", "b", "c"]);
50
+ });
51
+
52
+ test("delete", () => {
53
+ const map = new SyncMap([
54
+ ["a", 1],
55
+ ["b", 2],
56
+ ]);
57
+ assert.strictEqual(map.size, 2);
58
+ assert.strictEqual(map.delete("a"), true);
59
+ assert.strictEqual(map.size, 1);
60
+ assert.strictEqual(map.get("a"), undefined);
61
+ assert.strictEqual(map.delete("a"), false);
62
+ assert.strictEqual(map.size, 1);
63
+ });
64
+
65
+ test("delete on read-only map throws", () => {
66
+ class Fixture extends SyncMap {
67
+ get(key) {
68
+ return super.get(key);
69
+ }
70
+ }
71
+ const map = new Fixture([
72
+ ["a", 1],
73
+ ["b", 2],
74
+ ]);
75
+ assert.throws(() => map.delete("a"), {
76
+ name: "TypeError",
77
+ message: "delete() can't be called on a read-only map",
78
+ });
79
+ });
80
+
81
+ test("entries", () => {
82
+ const map = new SyncMap([
83
+ ["a", 1],
84
+ ["b", 2],
85
+ ]);
86
+ const entries = Array.from(map.entries());
87
+ assert.deepStrictEqual(entries, [
88
+ ["a", 1],
89
+ ["b", 2],
90
+ ]);
91
+ });
92
+
93
+ test("forEach", () => {
94
+ const map = new SyncMap([
95
+ ["a", 1],
96
+ ["b", 2],
97
+ ]);
98
+ const calls = [];
99
+ map.forEach((value, key, theMap) => {
100
+ calls.push([key, value, theMap]);
101
+ });
102
+ assert.deepStrictEqual(calls, [
103
+ ["a", 1, map],
104
+ ["b", 2, map],
105
+ ]);
106
+ });
107
+
108
+ test("get", () => {
109
+ const map = new SyncMap([
110
+ ["a", 1],
111
+ ["b", 2],
112
+ ]);
113
+ assert.strictEqual(map.get("a"), 1);
114
+ assert.strictEqual(map.get("b"), 2);
115
+ assert.strictEqual(map.get("c"), undefined);
116
+ });
117
+
118
+ test("get with trailing slash", () => {
119
+ const subMap = new SyncMap();
120
+ const map = new SyncMap([
121
+ ["a", 1],
122
+ ["b/", subMap],
123
+ ]);
124
+ assert.strictEqual(map.get("a"), 1);
125
+
126
+ const b = map.get("b/");
127
+ assert.strictEqual(b, subMap);
128
+ assert.strictEqual(b.parent, map);
129
+
130
+ // Trailing slash optional
131
+ assert.strictEqual(map.get("b"), subMap);
132
+
133
+ assert.strictEqual(map.get("c"), undefined);
134
+ });
135
+
136
+ test("has returns true if key exists in keys()", () => {
137
+ const map = new SyncMap();
138
+ map.keys = () => {
139
+ return ["a", "b/"][Symbol.iterator]();
140
+ };
141
+ assert.strictEqual(map.has("a"), true);
142
+ assert.strictEqual(map.has("b"), true); // trailing slash optional
143
+ assert.strictEqual(map.has("b/"), true);
144
+ assert.strictEqual(map.has("c"), false);
145
+ });
146
+
147
+ test("readOnly if get() is overridden but not delete() and set()", () => {
148
+ const map4 = new SyncMap();
149
+ assert.strictEqual(map4.readOnly, false);
150
+
151
+ class ReadOnly1 extends SyncMap {
152
+ get(key) {
153
+ return super.get(key);
154
+ }
155
+ }
156
+ const map1 = new ReadOnly1();
157
+ assert.strictEqual(map1.readOnly, true);
158
+
159
+ class ReadOnly2 extends SyncMap {
160
+ get(key) {
161
+ return super.get(key);
162
+ }
163
+ set(key, value) {
164
+ return super.set(key, value);
165
+ }
166
+ }
167
+ const map2 = new ReadOnly2();
168
+ assert.strictEqual(map2.readOnly, true);
169
+
170
+ class ReadWrite extends SyncMap {
171
+ get(key) {
172
+ return super.get(key);
173
+ }
174
+ set(key, value) {
175
+ return super.set(key, value);
176
+ }
177
+ delete(key) {
178
+ return super.delete(key);
179
+ }
180
+ }
181
+ const map3 = new ReadWrite();
182
+ assert.strictEqual(map3.readOnly, false);
183
+ });
184
+
185
+ test("Symbol.iterator", () => {
186
+ const map = new SyncMap([
187
+ ["a", 1],
188
+ ["b", 2],
189
+ ]);
190
+ const entries = Array.from(map[Symbol.iterator]());
191
+ assert.deepStrictEqual(entries, [
192
+ ["a", 1],
193
+ ["b", 2],
194
+ ]);
195
+ });
196
+
197
+ test("keys", () => {
198
+ const map = new SyncMap([
199
+ ["a", 1],
200
+ ["b", 2],
201
+ ]);
202
+ const keys = Array.from(map.keys());
203
+ assert.deepStrictEqual(keys, ["a", "b"]);
204
+ });
205
+
206
+ test("set", () => {
207
+ const map = new SyncMap();
208
+ assert.strictEqual(map.size, 0);
209
+ map.set("a", 1);
210
+ assert.strictEqual(map.size, 1);
211
+ assert.strictEqual(map.get("a"), 1);
212
+ map.set("a", 2);
213
+ assert.strictEqual(map.size, 1);
214
+ assert.strictEqual(map.get("a"), 2);
215
+ map.set("b", 3);
216
+ assert.strictEqual(map.size, 2);
217
+ assert.strictEqual(map.get("b"), 3);
218
+ });
219
+
220
+ test("child creates new map when not present", () => {
221
+ // Create child when not present
222
+ const map = new SyncMap();
223
+ const child1 = map.child("sub");
224
+ assert(child1 instanceof SyncMap);
225
+ const stored1 = map.get("sub");
226
+ assert.strictEqual(stored1, child1);
227
+
228
+ // Return existing child
229
+ const child2 = map.child("sub");
230
+ assert.strictEqual(child2, child1);
231
+ });
232
+
233
+ test("child overwrites non-map value", () => {
234
+ const map = new SyncMap();
235
+ map.set("sub", 123);
236
+ const child = map.child("sub");
237
+ assert(child instanceof SyncMap);
238
+ const stored = map.get("sub");
239
+ assert.strictEqual(stored, child);
240
+ });
241
+
242
+ test("set on read-only map throws", () => {
243
+ class Fixture extends SyncMap {
244
+ get(key) {
245
+ return super.get(key);
246
+ }
247
+ }
248
+ const map = new Fixture();
249
+ assert.throws(() => map.set("a", 1), {
250
+ name: "TypeError",
251
+ message: "set() can't be called on a read-only map",
252
+ });
253
+ });
254
+
255
+ test("size", () => {
256
+ const map = new SyncMap();
257
+ assert.strictEqual(map.size, 0);
258
+ map.set("a", 1);
259
+ assert.strictEqual(map.size, 1);
260
+ map.set("b", 2);
261
+ assert.strictEqual(map.size, 2);
262
+ map.delete("a");
263
+ assert.strictEqual(map.size, 1);
264
+ map.clear();
265
+ assert.strictEqual(map.size, 0);
266
+ });
267
+
268
+ test("values", () => {
269
+ const map = new SyncMap([
270
+ ["a", 1],
271
+ ["b", 2],
272
+ ]);
273
+ const values = Array.from(map.values());
274
+ assert.deepStrictEqual(values, [1, 2]);
275
+ });
276
+
277
+ test("all methods work with prototype chain extension", () => {
278
+ const map = new SyncMap([
279
+ ["a", 1],
280
+ ["b", 2],
281
+ ]);
282
+ const map2 = Object.create(map);
283
+ assert.strictEqual(map2.get("a"), 1);
284
+ assert.strictEqual(map2.has("b"), true);
285
+ assert.strictEqual(map2.size, 2);
286
+
287
+ const entries = Array.from(map2.entries());
288
+ assert.deepStrictEqual(entries, [
289
+ ["a", 1],
290
+ ["b", 2],
291
+ ]);
292
+
293
+ const keys = Array.from(map2.keys());
294
+ assert.deepStrictEqual(keys, ["a", "b"]);
295
+
296
+ const values = Array.from(map2.values());
297
+ assert.deepStrictEqual(values, [1, 2]);
298
+
299
+ const iteratedEntries = Array.from(map2[Symbol.iterator]());
300
+ assert.deepStrictEqual(iteratedEntries, [
301
+ ["a", 1],
302
+ ["b", 2],
303
+ ]);
304
+
305
+ const forEachCalls = [];
306
+ map2.forEach((value, key, thisArg) => {
307
+ forEachCalls.push([key, value, thisArg]);
308
+ });
309
+ assert.deepStrictEqual(forEachCalls, [
310
+ ["a", 1, map2],
311
+ ["b", 2, map2],
312
+ ]);
313
+ });
314
+
315
+ if ("groupBy" in Map) {
316
+ test("acceptable to Map.groupBy", () => {
317
+ const map = new SyncMap([
318
+ ["a", 1],
319
+ ["b", 2],
320
+ ["c", 3],
321
+ ]);
322
+ // @ts-ignore
323
+ const grouped = Map.groupBy(map, ([key, value]) =>
324
+ value % 2 === 0 ? "even" : "odd"
325
+ );
326
+ assert(grouped instanceof Map);
327
+ assert.strictEqual(grouped.size, 2);
328
+ assert.deepStrictEqual(grouped.get("odd"), [
329
+ ["a", 1],
330
+ ["c", 3],
331
+ ]);
332
+ assert.deepStrictEqual(grouped.get("even"), [["b", 2]]);
333
+ });
334
+ }
335
+ });
@@ -1,14 +1,26 @@
1
1
  import assert from "node:assert";
2
2
  import { describe, test } from "node:test";
3
- import DeepObjectTree from "../src/drivers/DeepObjectTree.js";
3
+ import ObjectMap from "../src/drivers/ObjectMap.js";
4
4
  import * as jsonKeys from "../src/jsonKeys.js";
5
5
 
6
6
  describe("jsonKeys", () => {
7
- test("stringifies JSON Keys", async () => {
8
- const tree = new DeepObjectTree({
9
- about: {},
10
- "index.html": "Home",
11
- });
7
+ test("creates JSON keys for a simple map", async () => {
8
+ const tree = new /** @type {any} */ (Map)([
9
+ ["index.html", "Home"],
10
+ ["about", new Map()],
11
+ ]);
12
+ const json = await jsonKeys.stringify(tree);
13
+ assert.strictEqual(json, '["index.html","about/"]');
14
+ });
15
+
16
+ test("creates JSON keys for a map that supports trailing slashes", async () => {
17
+ const tree = new ObjectMap(
18
+ {
19
+ about: {},
20
+ "index.html": "Home",
21
+ },
22
+ { deep: true }
23
+ );
12
24
  const json = await jsonKeys.stringify(tree);
13
25
  assert.strictEqual(json, '["about/","index.html"]');
14
26
  });
@@ -1,6 +1,7 @@
1
1
  import assert from "node:assert";
2
2
  import { describe, test } from "node:test";
3
3
  import addNextPrevious from "../../src/operations/addNextPrevious.js";
4
+ import plain from "../../src/operations/plain.js";
4
5
 
5
6
  describe("addNextPrevious", () => {
6
7
  test("adds next/previous properties to values", async () => {
@@ -16,7 +17,7 @@ describe("addNextPrevious", () => {
16
17
  },
17
18
  };
18
19
  const result = await addNextPrevious(tree);
19
- assert.deepEqual(result, {
20
+ assert.deepEqual(await plain(result), {
20
21
  alice: {
21
22
  name: "Alice",
22
23
  nextKey: "bob",
@@ -36,7 +37,7 @@ describe("addNextPrevious", () => {
36
37
  test("returns a non-object value as a 'value' property", async () => {
37
38
  const array = ["Alice", "Bob", "Carol"];
38
39
  const result = await addNextPrevious(array);
39
- assert.deepEqual(result, [
40
+ assert.deepEqual(await plain(result), [
40
41
  {
41
42
  value: "Alice",
42
43
  nextKey: "1",
@@ -1,53 +1,48 @@
1
1
  import assert from "node:assert";
2
2
  import { describe, test } from "node:test";
3
- import DeepObjectTree from "../../src/drivers/DeepObjectTree.js";
4
- import ObjectTree from "../../src/drivers/ObjectTree.js";
3
+ import ObjectMap from "../../src/drivers/ObjectMap.js";
4
+ import SyncMap from "../../src/drivers/SyncMap.js";
5
5
  import assign from "../../src/operations/assign.js";
6
6
  import plain from "../../src/operations/plain.js";
7
+ import { deepEntries } from "../../src/Tree.js";
8
+ import SampleAsyncMap from "../SampleAsyncMap.js";
7
9
 
8
10
  describe("assign", () => {
9
- test("assign applies one tree to another", async () => {
10
- const target = new DeepObjectTree({
11
- a: 1,
12
- b: 2,
13
- more: {
14
- d: 3,
15
- },
16
- });
11
+ test("assign can apply updates from an async tree to a sync tree", async () => {
12
+ const target = new SyncMap([
13
+ ["a", 1],
14
+ ["b", 2],
15
+ ["more", new SyncMap([["d", 3]])],
16
+ ]);
17
17
 
18
- const source = new DeepObjectTree({
19
- a: 4, // Overwrite existing value
20
- b: undefined, // Delete
21
- c: 5, // Add
22
- more: {
23
- // Should leave existing `more` keys alone.
24
- e: 6, // Add
25
- },
26
- // Add new subtree
27
- extra: {
28
- f: 7,
29
- },
30
- });
18
+ const source = new SampleAsyncMap([
19
+ ["a", 4], // Overwrite existing value
20
+ ["c", 5], // Add
21
+ ["more", [["e", 6]]], // Should leave existing `more` keys alone.
22
+ ["extra", [["f", 7]]], // Add new subtree
23
+ ]);
31
24
 
32
25
  // Apply changes.
33
26
  const result = await assign(target, source);
34
27
 
35
28
  assert.equal(result, target);
36
- assert.deepEqual(await plain(target), {
37
- a: 4,
38
- c: 5,
39
- more: {
40
- d: 3,
41
- e: 6,
42
- },
43
- extra: {
44
- f: 7,
45
- },
46
- });
29
+ assert.deepEqual(await deepEntries(target), [
30
+ ["a", 4],
31
+ ["b", 2],
32
+ [
33
+ "more",
34
+ [
35
+ ["d", 3],
36
+ ["e", 6],
37
+ ],
38
+ ],
39
+ ["c", 5],
40
+ ["extra", [["f", 7]]],
41
+ ]);
47
42
  });
48
43
 
49
44
  test("assign() can apply updates to an array", async () => {
50
- const target = new ObjectTree(["a", "b", "c"]);
45
+ const target = new ObjectMap(["a", "b", "c"]);
51
46
  await assign(target, ["d", "e"]);
52
47
  assert.deepEqual(await plain(target), ["d", "e", "c"]);
53
48
  });
@@ -1,25 +1,30 @@
1
1
  import assert from "node:assert";
2
2
  import { describe, test } from "node:test";
3
- import { DeepObjectTree, ObjectTree } from "../../src/internal.js";
3
+ import ObjectMap from "../../src/drivers/ObjectMap.js";
4
+ import SyncMap from "../../src/drivers/SyncMap.js";
4
5
  import cache from "../../src/operations/cache.js";
6
+ import keys from "../../src/operations/keys.js";
5
7
 
6
8
  describe("cache", () => {
7
9
  test("caches reads of values from one tree into another", async () => {
8
- const objectCache = new ObjectTree({});
10
+ const objectCache = new SyncMap();
9
11
  const fixture = await cache(
10
- new DeepObjectTree({
11
- a: 1,
12
- b: 2,
13
- c: 3,
14
- more: {
15
- d: 4,
12
+ new ObjectMap(
13
+ {
14
+ a: 1,
15
+ b: 2,
16
+ c: 3,
17
+ more: {
18
+ d: 4,
19
+ },
16
20
  },
17
- }),
21
+ { deep: true }
22
+ ),
18
23
  objectCache
19
24
  );
20
25
 
21
- const keys = [...(await fixture.keys())];
22
- assert.deepEqual(keys, ["a", "b", "c", "more/"]);
26
+ const treeKeys = await keys(fixture);
27
+ assert.deepEqual(treeKeys, ["a", "b", "c", "more/"]);
23
28
 
24
29
  assert.equal(await objectCache.get("a"), undefined);
25
30
  assert.equal(await fixture.get("a"), 1);
@@ -31,7 +36,7 @@ describe("cache", () => {
31
36
 
32
37
  assert.equal(await objectCache.get("more"), undefined);
33
38
  const more = await fixture.get("more");
34
- assert.deepEqual([...(await more.keys())], ["d"]);
39
+ assert.deepEqual([...(await keys(more))], ["d"]);
35
40
  assert.equal(await more.get("d"), 4);
36
41
  const moreCache = await objectCache.get("more");
37
42
  assert.equal(await moreCache.get("d"), 4);
@@ -1,12 +1,12 @@
1
1
  import assert from "node:assert";
2
2
  import { describe, test } from "node:test";
3
- import { DeepObjectTree, ObjectTree } from "../../src/internal.js";
3
+ import ObjectMap from "../../src/drivers/ObjectMap.js";
4
4
  import cachedKeyFunctions from "../../src/operations/cachedKeyFunctions.js";
5
5
  import * as trailingSlash from "../../src/trailingSlash.js";
6
6
 
7
7
  describe("cachedKeyFunctions", () => {
8
8
  test("maps keys with caching", async () => {
9
- const tree = new ObjectTree({
9
+ const tree = new ObjectMap({
10
10
  a: "letter a",
11
11
  b: "letter b",
12
12
  });
@@ -41,12 +41,15 @@ describe("cachedKeyFunctions", () => {
41
41
  });
42
42
 
43
43
  test("maps keys with caching and deep option", async () => {
44
- const tree = new DeepObjectTree({
45
- a: "letter a",
46
- b: {
47
- c: "letter c",
44
+ const tree = new ObjectMap(
45
+ {
46
+ a: "letter a",
47
+ b: {
48
+ c: "letter c",
49
+ },
48
50
  },
49
- });
51
+ { deep: true }
52
+ );
50
53
 
51
54
  let callCount = 0;
52
55
  const addUnderscore = async (sourceValue, sourceKey, tree) => {
@@ -76,7 +79,7 @@ describe("cachedKeyFunctions", () => {
76
79
  });
77
80
 
78
81
  test("preserves trailing slashes if key function does so", async () => {
79
- const tree = new ObjectTree({
82
+ const tree = new ObjectMap({
80
83
  a: "letter a",
81
84
  });
82
85
  const addUnderscore = async (sourceValue, sourceKey) => `_${sourceKey}`;
@@ -90,7 +93,7 @@ describe("cachedKeyFunctions", () => {
90
93
  });
91
94
 
92
95
  test("if key function toggles slash, defers to key function slash handling", async () => {
93
- const tree = new ObjectTree({
96
+ const tree = new ObjectMap({
94
97
  a: "letter a",
95
98
  });
96
99
  const addUnderscoreAndSlash = async (sourceValue, sourceKey) =>
@@ -0,0 +1,34 @@
1
+ import assert from "node:assert";
2
+ import { describe, test } from "node:test";
3
+ import child from "../../src/operations/child.js";
4
+
5
+ describe("child", () => {
6
+ test("defers to map.child() if available", async () => {
7
+ class CustomMap extends Map {
8
+ child(key) {
9
+ return `child-${key}`;
10
+ }
11
+
12
+ parent = null;
13
+ trailingSlashKeys = false;
14
+ }
15
+ const map = new CustomMap();
16
+ const result = await child(map, "test");
17
+ assert.strictEqual(result, "child-test");
18
+ });
19
+
20
+ test("returns existing subtree if present", async () => {
21
+ const subtree = new Map();
22
+ const map = new Map([["sub", subtree]]);
23
+ const result = await child(map, "sub");
24
+ assert.strictEqual(result, subtree);
25
+ });
26
+
27
+ test("creates new subtree if not present", async () => {
28
+ const map = new Map();
29
+ const result = await child(map, "sub");
30
+ assert.ok(result instanceof Map);
31
+ const stored = await map.get("sub");
32
+ assert.strictEqual(stored, result);
33
+ });
34
+ });
@@ -1,34 +1,13 @@
1
1
  import assert from "node:assert";
2
- import * as fs from "node:fs/promises";
3
- import path from "node:path";
4
2
  import { describe, test } from "node:test";
5
- import { fileURLToPath } from "node:url";
6
- import FileTree from "../../src/drivers/FileTree.js";
7
- import { ObjectTree, Tree } from "../../src/internal.js";
8
-
9
- const dirname = path.dirname(fileURLToPath(import.meta.url));
10
- const tempDirectory = path.join(dirname, "fixtures/temp");
3
+ import ObjectMap from "../../src/drivers/ObjectMap.js";
4
+ import clear from "../../src/operations/clear.js";
5
+ import plain from "../../src/operations/plain.js";
11
6
 
12
7
  describe("clear", () => {
13
8
  test("unsets all public keys in an object tree", async () => {
14
- const tree = new ObjectTree({ a: 1, b: 2, c: 3 });
15
- await Tree.clear(tree);
16
- assert.deepEqual(await Tree.plain(tree), {});
17
- });
18
-
19
- test("unsets all public keys in a file tree", async () => {
20
- // Create a temp directory with some files
21
- await fs.mkdir(tempDirectory, { recursive: true });
22
- await fs.writeFile(path.join(tempDirectory, "a"), "1");
23
- await fs.writeFile(path.join(tempDirectory, "b"), "2");
24
-
25
- const tree = new FileTree(tempDirectory);
26
- await Tree.clear(tree);
27
-
28
- const files = await fs.readdir(tempDirectory);
29
- assert.deepEqual(files, []);
30
-
31
- // Remove temp directory
32
- await fs.rm(tempDirectory, { recursive: true });
9
+ const tree = new ObjectMap({ a: 1, b: 2, c: 3 });
10
+ await clear(tree);
11
+ assert.deepEqual(await plain(tree), {});
33
12
  });
34
13
  });
@@ -0,0 +1,32 @@
1
+ import assert from "node:assert";
2
+ import { describe, test } from "node:test";
3
+ import deepEntries from "../../src/operations/deepEntries.js";
4
+ import SampleAsyncMap from "../SampleAsyncMap.js";
5
+
6
+ describe("deepEntries", () => {
7
+ test("converts an async tree to an array of nested entries arrays", async () => {
8
+ const fixture = new SampleAsyncMap([
9
+ ["a", 1],
10
+ ["b", 2],
11
+ [
12
+ "more",
13
+ [
14
+ ["c", 3],
15
+ ["d", 4],
16
+ ],
17
+ ],
18
+ ]);
19
+ const result = await deepEntries(fixture);
20
+ assert.deepStrictEqual(result, [
21
+ ["a", 1],
22
+ ["b", 2],
23
+ [
24
+ "more",
25
+ [
26
+ ["c", 3],
27
+ ["d", 4],
28
+ ],
29
+ ],
30
+ ]);
31
+ });
32
+ });