@weborigami/async-tree 0.5.4 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.ts +16 -6
- package/package.json +2 -2
- package/shared.js +20 -30
- package/src/Tree.js +62 -513
- package/src/constants.js +2 -0
- package/src/drivers/BrowserFileTree.js +9 -10
- package/src/drivers/DeepMapTree.js +3 -3
- package/src/drivers/DeepObjectTree.js +4 -5
- package/src/drivers/DeferredTree.js +2 -2
- package/src/drivers/FileTree.js +11 -33
- package/src/drivers/FunctionTree.js +1 -1
- package/src/drivers/MapTree.js +6 -6
- package/src/drivers/ObjectTree.js +4 -3
- package/src/drivers/SetTree.js +1 -1
- package/src/drivers/SiteTree.js +1 -1
- package/src/drivers/constantTree.js +1 -1
- package/src/extension.js +5 -3
- package/src/jsonKeys.js +5 -7
- package/src/operations/addNextPrevious.js +10 -9
- package/src/operations/assign.js +40 -0
- package/src/operations/cache.js +18 -12
- package/src/operations/cachedKeyFunctions.js +15 -4
- package/src/operations/clear.js +20 -0
- package/src/operations/concat.js +17 -0
- package/src/operations/deepMap.js +25 -0
- package/src/operations/deepMerge.js +11 -25
- package/src/operations/deepReverse.js +6 -7
- package/src/operations/deepTake.js +6 -7
- package/src/operations/deepText.js +4 -4
- package/src/operations/deepValuesIterator.js +8 -6
- package/src/operations/defineds.js +32 -0
- package/src/operations/delete.js +20 -0
- package/src/operations/entries.js +16 -0
- package/src/operations/extensionKeyFunctions.js +1 -1
- package/src/operations/filter.js +7 -8
- package/src/operations/first.js +18 -0
- package/src/operations/forEach.js +20 -0
- package/src/operations/from.js +77 -0
- package/src/operations/fromFn.js +26 -0
- package/src/operations/globKeys.js +8 -8
- package/src/operations/group.js +9 -7
- package/src/operations/has.js +16 -0
- package/src/operations/indent.js +4 -2
- package/src/operations/inners.js +29 -0
- package/src/operations/invokeFunctions.js +5 -4
- package/src/operations/isAsyncMutableTree.js +15 -0
- package/src/operations/isAsyncTree.js +21 -0
- package/src/operations/isTraversable.js +15 -0
- package/src/operations/isTreelike.js +33 -0
- package/src/operations/json.js +4 -3
- package/src/operations/keys.js +14 -0
- package/src/operations/length.js +15 -0
- package/src/operations/map.js +151 -95
- package/src/operations/mapExtension.js +27 -0
- package/src/operations/mapReduce.js +44 -0
- package/src/operations/mask.js +18 -16
- package/src/operations/match.js +74 -0
- package/src/operations/merge.js +22 -20
- package/src/operations/paginate.js +3 -5
- package/src/operations/parent.js +13 -0
- package/src/operations/paths.js +51 -0
- package/src/operations/plain.js +34 -0
- package/src/operations/regExpKeys.js +4 -5
- package/src/operations/remove.js +14 -0
- package/src/operations/reverse.js +4 -6
- package/src/operations/root.js +17 -0
- package/src/operations/scope.js +4 -6
- package/src/operations/setDeep.js +50 -0
- package/src/operations/shuffle.js +46 -0
- package/src/operations/sort.js +19 -12
- package/src/operations/take.js +3 -5
- package/src/operations/text.js +3 -3
- package/src/operations/toFunction.js +14 -0
- package/src/operations/traverse.js +25 -0
- package/src/operations/traverseOrThrow.js +64 -0
- package/src/operations/traversePath.js +16 -0
- package/src/operations/values.js +15 -0
- package/src/operations/withKeys.js +33 -0
- package/src/utilities/TypedArray.js +2 -0
- package/src/utilities/box.js +20 -0
- package/src/utilities/castArraylike.js +38 -0
- package/src/utilities/getParent.js +33 -0
- package/src/utilities/getRealmObjectPrototype.js +19 -0
- package/src/utilities/getTreeArgument.js +43 -0
- package/src/utilities/isPacked.js +20 -0
- package/src/utilities/isPlainObject.js +29 -0
- package/src/utilities/isPrimitive.js +13 -0
- package/src/utilities/isStringlike.js +25 -0
- package/src/utilities/isUnpackable.js +13 -0
- package/src/utilities/keysFromPath.js +34 -0
- package/src/utilities/naturalOrder.js +9 -0
- package/src/utilities/pathFromKeys.js +18 -0
- package/src/utilities/setParent.js +38 -0
- package/src/utilities/toFunction.js +41 -0
- package/src/utilities/toPlainValue.js +95 -0
- package/src/utilities/toString.js +37 -0
- package/test/drivers/ExplorableSiteTree.test.js +1 -1
- package/test/drivers/FileTree.test.js +1 -1
- package/test/drivers/calendarTree.test.js +1 -1
- package/test/jsonKeys.test.js +1 -1
- package/test/operations/assign.test.js +54 -0
- package/test/operations/cache.test.js +1 -1
- package/test/operations/cachedKeyFunctions.test.js +16 -16
- package/test/operations/clear.test.js +34 -0
- package/test/operations/deepMap.test.js +29 -0
- package/test/operations/deepMerge.test.js +2 -6
- package/test/operations/deepReverse.test.js +1 -1
- package/test/operations/defineds.test.js +25 -0
- package/test/operations/delete.test.js +20 -0
- package/test/operations/entries.test.js +18 -0
- package/test/operations/extensionKeyFunctions.test.js +10 -10
- package/test/operations/first.test.js +15 -0
- package/test/operations/fixtures/README.md +1 -0
- package/test/operations/forEach.test.js +22 -0
- package/test/operations/from.test.js +67 -0
- package/test/operations/globKeys.test.js +3 -3
- package/test/operations/has.test.js +15 -0
- package/test/operations/inners.test.js +30 -0
- package/test/operations/invokeFunctions.test.js +1 -1
- package/test/operations/isAsyncMutableTree.test.js +17 -0
- package/test/operations/isAsyncTree.test.js +26 -0
- package/test/operations/isTreelike.test.js +13 -0
- package/test/operations/keys.test.js +15 -0
- package/test/operations/length.test.js +15 -0
- package/test/operations/map.test.js +61 -42
- package/test/operations/mapExtension.test.js +0 -0
- package/test/operations/mapReduce.test.js +23 -0
- package/test/operations/mask.test.js +1 -1
- package/test/operations/match.test.js +33 -0
- package/test/operations/merge.test.js +23 -9
- package/test/operations/parent.test.js +15 -0
- package/test/operations/paths.test.js +40 -0
- package/test/operations/plain.test.js +69 -0
- package/test/operations/reverse.test.js +1 -1
- package/test/operations/scope.test.js +1 -1
- package/test/operations/setDeep.test.js +53 -0
- package/test/operations/shuffle.test.js +18 -0
- package/test/operations/sort.test.js +3 -3
- package/test/operations/toFunction.test.js +16 -0
- package/test/operations/traverse.test.js +43 -0
- package/test/operations/traversePath.test.js +16 -0
- package/test/operations/values.test.js +18 -0
- package/test/operations/withKeys.test.js +21 -0
- package/test/utilities/box.test.js +26 -0
- package/test/utilities/getRealmObjectPrototype.test.js +11 -0
- package/test/utilities/isPlainObject.test.js +13 -0
- package/test/utilities/keysFromPath.test.js +14 -0
- package/test/utilities/naturalOrder.test.js +11 -0
- package/test/utilities/pathFromKeys.test.js +12 -0
- package/test/utilities/setParent.test.js +34 -0
- package/test/utilities/toFunction.test.js +34 -0
- package/test/utilities/toPlainValue.test.js +27 -0
- package/test/utilities/toString.test.js +22 -0
- package/src/Tree.d.ts +0 -24
- package/src/utilities.d.ts +0 -21
- package/src/utilities.js +0 -443
- package/test/Tree.test.js +0 -407
- package/test/utilities.test.js +0 -141
package/test/Tree.test.js
DELETED
|
@@ -1,407 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert";
|
|
2
|
-
import { describe, test } from "node:test";
|
|
3
|
-
import MapTree from "../src/drivers/MapTree.js";
|
|
4
|
-
import { DeepObjectTree, ObjectTree, Tree } from "../src/internal.js";
|
|
5
|
-
import * as symbols from "../src/symbols.js";
|
|
6
|
-
|
|
7
|
-
describe("Tree", () => {
|
|
8
|
-
test("assign applies one tree to another", async () => {
|
|
9
|
-
const target = new DeepObjectTree({
|
|
10
|
-
a: 1,
|
|
11
|
-
b: 2,
|
|
12
|
-
more: {
|
|
13
|
-
d: 3,
|
|
14
|
-
},
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
const source = new DeepObjectTree({
|
|
18
|
-
a: 4, // Overwrite existing value
|
|
19
|
-
b: undefined, // Delete
|
|
20
|
-
c: 5, // Add
|
|
21
|
-
more: {
|
|
22
|
-
// Should leave existing `more` keys alone.
|
|
23
|
-
e: 6, // Add
|
|
24
|
-
},
|
|
25
|
-
// Add new subtree
|
|
26
|
-
extra: {
|
|
27
|
-
f: 7,
|
|
28
|
-
},
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
// Apply changes.
|
|
32
|
-
const result = await Tree.assign(target, source);
|
|
33
|
-
|
|
34
|
-
assert.equal(result, target);
|
|
35
|
-
const plain = await Tree.plain(target);
|
|
36
|
-
assert.deepEqual(plain, {
|
|
37
|
-
a: 4,
|
|
38
|
-
c: 5,
|
|
39
|
-
more: {
|
|
40
|
-
d: 3,
|
|
41
|
-
e: 6,
|
|
42
|
-
},
|
|
43
|
-
extra: {
|
|
44
|
-
f: 7,
|
|
45
|
-
},
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test("assign() can apply updates to an array", async () => {
|
|
50
|
-
const target = new ObjectTree(["a", "b", "c"]);
|
|
51
|
-
await Tree.assign(target, ["d", "e"]);
|
|
52
|
-
assert.deepEqual(await Tree.plain(target), ["d", "e", "c"]);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test("clear() removes all values", async () => {
|
|
56
|
-
const fixture = createFixture();
|
|
57
|
-
await Tree.clear(fixture);
|
|
58
|
-
assert.deepEqual(Array.from(await Tree.entries(fixture)), []);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test("entries() returns the [key, value] pairs", async () => {
|
|
62
|
-
const fixture = createFixture();
|
|
63
|
-
assert.deepEqual(Array.from(await Tree.entries(fixture)), [
|
|
64
|
-
["Alice.md", "Hello, **Alice**."],
|
|
65
|
-
["Bob.md", "Hello, **Bob**."],
|
|
66
|
-
["Carol.md", "Hello, **Carol**."],
|
|
67
|
-
]);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
test("forEach() invokes a callback for each entry", async () => {
|
|
71
|
-
const fixture = createFixture();
|
|
72
|
-
const results = {};
|
|
73
|
-
await Tree.forEach(fixture, async (value, key) => {
|
|
74
|
-
results[key] = value;
|
|
75
|
-
});
|
|
76
|
-
assert.deepEqual(results, {
|
|
77
|
-
"Alice.md": "Hello, **Alice**.",
|
|
78
|
-
"Bob.md": "Hello, **Bob**.",
|
|
79
|
-
"Carol.md": "Hello, **Carol**.",
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
test("from() returns an async tree as is", async () => {
|
|
84
|
-
const tree1 = new ObjectTree({
|
|
85
|
-
a: "Hello, a.",
|
|
86
|
-
});
|
|
87
|
-
const tree2 = Tree.from(tree1);
|
|
88
|
-
assert.equal(tree2, tree1);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
test("from() uses an object's unpack() method if defined", async () => {
|
|
92
|
-
const obj = new String();
|
|
93
|
-
/** @type {any} */ (obj).unpack = () => ({
|
|
94
|
-
a: "Hello, a.",
|
|
95
|
-
});
|
|
96
|
-
const tree = Tree.from(obj);
|
|
97
|
-
assert.deepEqual(await Tree.plain(tree), {
|
|
98
|
-
a: "Hello, a.",
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
test("from returns a deep object tree if deep option is true", async () => {
|
|
103
|
-
const obj = {
|
|
104
|
-
sub: {
|
|
105
|
-
a: 1,
|
|
106
|
-
},
|
|
107
|
-
};
|
|
108
|
-
const tree = Tree.from(obj, { deep: true });
|
|
109
|
-
assert(tree instanceof DeepObjectTree);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
test("from returns a deep object tree if object has [deep] symbol set", async () => {
|
|
113
|
-
const obj = {
|
|
114
|
-
sub: {
|
|
115
|
-
a: 1,
|
|
116
|
-
},
|
|
117
|
-
};
|
|
118
|
-
Object.defineProperty(obj, symbols.deep, { value: true });
|
|
119
|
-
const tree = Tree.from(obj);
|
|
120
|
-
assert(tree instanceof DeepObjectTree);
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
test("from() creates a deferred tree if unpack() returns a promise", async () => {
|
|
124
|
-
const obj = new String();
|
|
125
|
-
/** @type {any} */ (obj).unpack = async () => ({
|
|
126
|
-
a: "Hello, a.",
|
|
127
|
-
});
|
|
128
|
-
const tree = Tree.from(obj);
|
|
129
|
-
assert.deepEqual(await Tree.plain(tree), {
|
|
130
|
-
a: "Hello, a.",
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
test("from() autoboxes primitive values", async () => {
|
|
135
|
-
const tree = Tree.from("Hello, world.");
|
|
136
|
-
const slice = await tree.get("slice");
|
|
137
|
-
const result = await slice(0, 5);
|
|
138
|
-
assert.equal(result, "Hello");
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
test("has returns true if the key exists", async () => {
|
|
142
|
-
const fixture = createFixture();
|
|
143
|
-
assert.equal(await Tree.has(fixture, "Alice.md"), true);
|
|
144
|
-
assert.equal(await Tree.has(fixture, "David.md"), false);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
test("isAsyncTree returns true if the object is a tree", () => {
|
|
148
|
-
const missingGetAndKeys = {};
|
|
149
|
-
assert(!Tree.isAsyncTree(missingGetAndKeys));
|
|
150
|
-
|
|
151
|
-
const missingIterator = {
|
|
152
|
-
async get() {},
|
|
153
|
-
};
|
|
154
|
-
assert(!Tree.isAsyncTree(missingIterator));
|
|
155
|
-
|
|
156
|
-
const missingGet = {
|
|
157
|
-
async keys() {},
|
|
158
|
-
};
|
|
159
|
-
assert(!Tree.isAsyncTree(missingGet));
|
|
160
|
-
|
|
161
|
-
const hasGetAndKeys = {
|
|
162
|
-
async get() {},
|
|
163
|
-
async keys() {},
|
|
164
|
-
};
|
|
165
|
-
assert(Tree.isAsyncTree(hasGetAndKeys));
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
test("isAsyncMutableTree returns true if the object is a mutable tree", () => {
|
|
169
|
-
assert.equal(
|
|
170
|
-
Tree.isAsyncMutableTree({
|
|
171
|
-
get() {},
|
|
172
|
-
keys() {},
|
|
173
|
-
}),
|
|
174
|
-
false
|
|
175
|
-
);
|
|
176
|
-
assert.equal(Tree.isAsyncMutableTree(createFixture()), true);
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
test("isTreelike() returns true if the argument can be cast to an async tree", () => {
|
|
180
|
-
assert(!Tree.isTreelike(null));
|
|
181
|
-
assert(Tree.isTreelike({}));
|
|
182
|
-
assert(Tree.isTreelike([]));
|
|
183
|
-
assert(Tree.isTreelike(new Map()));
|
|
184
|
-
assert(Tree.isTreelike(new Set()));
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
test("map() maps values", async () => {
|
|
188
|
-
const tree = new DeepObjectTree({
|
|
189
|
-
a: "Alice",
|
|
190
|
-
more: {
|
|
191
|
-
b: "Bob",
|
|
192
|
-
},
|
|
193
|
-
});
|
|
194
|
-
const mapped = Tree.map(tree, {
|
|
195
|
-
deep: true,
|
|
196
|
-
value: (value) => value.toUpperCase(),
|
|
197
|
-
});
|
|
198
|
-
assert.deepEqual(await Tree.plain(mapped), {
|
|
199
|
-
a: "ALICE",
|
|
200
|
-
more: {
|
|
201
|
-
b: "BOB",
|
|
202
|
-
},
|
|
203
|
-
});
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
test("mapReduce() can map values and reduce them", async () => {
|
|
207
|
-
const tree = new DeepObjectTree({
|
|
208
|
-
a: 1,
|
|
209
|
-
b: 2,
|
|
210
|
-
more: {
|
|
211
|
-
c: 3,
|
|
212
|
-
},
|
|
213
|
-
d: 4,
|
|
214
|
-
});
|
|
215
|
-
const reduced = await Tree.mapReduce(
|
|
216
|
-
tree,
|
|
217
|
-
(value) => value,
|
|
218
|
-
async (values) => String.prototype.concat(...values)
|
|
219
|
-
);
|
|
220
|
-
assert.deepEqual(reduced, "1234");
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
test("paths returns an array of paths to the values in the tree", async () => {
|
|
224
|
-
const tree = new DeepObjectTree({
|
|
225
|
-
a: 1,
|
|
226
|
-
b: 2,
|
|
227
|
-
c: {
|
|
228
|
-
d: 3,
|
|
229
|
-
e: 4,
|
|
230
|
-
},
|
|
231
|
-
});
|
|
232
|
-
assert.deepEqual(await Tree.paths(tree), ["a", "b", "c/d", "c/e"]);
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
test("paths can focus just on keys with trailing slashes", async () => {
|
|
236
|
-
const tree = new ObjectTree({
|
|
237
|
-
a: 1,
|
|
238
|
-
b: 2,
|
|
239
|
-
// This is a shallow ObjectTree, so `c` won't have a trailing slash
|
|
240
|
-
c: {
|
|
241
|
-
d: 3,
|
|
242
|
-
},
|
|
243
|
-
// Explicitly include a trailing slash to signal a subtree
|
|
244
|
-
"d/": new ObjectTree({
|
|
245
|
-
e: 4,
|
|
246
|
-
}),
|
|
247
|
-
});
|
|
248
|
-
assert.deepEqual(await Tree.paths(tree, { assumeSlashes: true }), [
|
|
249
|
-
"a",
|
|
250
|
-
"b",
|
|
251
|
-
"c",
|
|
252
|
-
"d/e",
|
|
253
|
-
]);
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
test("plain() produces a plain object version of a tree", async () => {
|
|
257
|
-
const tree = new ObjectTree({
|
|
258
|
-
a: 1,
|
|
259
|
-
// Slashes should be normalized
|
|
260
|
-
"sub1/": {
|
|
261
|
-
b: 2,
|
|
262
|
-
},
|
|
263
|
-
sub2: {
|
|
264
|
-
c: 3,
|
|
265
|
-
},
|
|
266
|
-
});
|
|
267
|
-
const plain = await Tree.plain(tree);
|
|
268
|
-
assert.deepEqual(plain, {
|
|
269
|
-
a: 1,
|
|
270
|
-
sub1: {
|
|
271
|
-
b: 2,
|
|
272
|
-
},
|
|
273
|
-
sub2: {
|
|
274
|
-
c: 3,
|
|
275
|
-
},
|
|
276
|
-
});
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
test("plain() produces an array for an array-like tree", async () => {
|
|
280
|
-
const original = ["a", "b", "c"];
|
|
281
|
-
const tree = new ObjectTree(original);
|
|
282
|
-
const plain = await Tree.plain(tree);
|
|
283
|
-
assert.deepEqual(plain, original);
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
test("plain() leaves an array-like tree as an object if keys aren't consecutive", async () => {
|
|
287
|
-
const original = {
|
|
288
|
-
0: "a",
|
|
289
|
-
1: "b",
|
|
290
|
-
// missing
|
|
291
|
-
3: "c",
|
|
292
|
-
};
|
|
293
|
-
const tree = new ObjectTree(original);
|
|
294
|
-
const plain = await Tree.plain(tree);
|
|
295
|
-
assert.deepEqual(plain, original);
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
test("plain() returns empty array or object for ObjectTree as necessary", async () => {
|
|
299
|
-
const tree = new ObjectTree({});
|
|
300
|
-
assert.deepEqual(await Tree.plain(tree), {});
|
|
301
|
-
const arrayTree = new ObjectTree([]);
|
|
302
|
-
assert.deepEqual(await Tree.plain(arrayTree), []);
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
test("plain() awaits async properties", async () => {
|
|
306
|
-
const object = {
|
|
307
|
-
get name() {
|
|
308
|
-
return Promise.resolve("Alice");
|
|
309
|
-
},
|
|
310
|
-
};
|
|
311
|
-
assert.deepEqual(await Tree.plain(object), { name: "Alice" });
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
test("plain() coerces TypedArray values to strings", async () => {
|
|
315
|
-
const tree = new ObjectTree({
|
|
316
|
-
a: new TextEncoder().encode("Hello, world."),
|
|
317
|
-
});
|
|
318
|
-
const plain = await Tree.plain(tree);
|
|
319
|
-
assert.equal(plain.a, "Hello, world.");
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
test("remove method removes a value", async () => {
|
|
323
|
-
const fixture = createFixture();
|
|
324
|
-
await Tree.remove(fixture, "Alice.md");
|
|
325
|
-
assert.deepEqual(Array.from(await Tree.entries(fixture)), [
|
|
326
|
-
["Bob.md", "Hello, **Bob**."],
|
|
327
|
-
["Carol.md", "Hello, **Carol**."],
|
|
328
|
-
]);
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
test("toFunction returns a function that invokes a tree's get() method", async () => {
|
|
332
|
-
const tree = new ObjectTree({
|
|
333
|
-
a: 1,
|
|
334
|
-
b: 2,
|
|
335
|
-
});
|
|
336
|
-
const fn = Tree.toFunction(tree);
|
|
337
|
-
assert.equal(await fn("a"), 1);
|
|
338
|
-
assert.equal(await fn("b"), 2);
|
|
339
|
-
});
|
|
340
|
-
|
|
341
|
-
test("traverse() a path of keys", async () => {
|
|
342
|
-
const tree = new ObjectTree({
|
|
343
|
-
a1: 1,
|
|
344
|
-
a2: {
|
|
345
|
-
b1: 2,
|
|
346
|
-
b2: {
|
|
347
|
-
c1: 3,
|
|
348
|
-
c2: 4,
|
|
349
|
-
},
|
|
350
|
-
},
|
|
351
|
-
});
|
|
352
|
-
assert.equal(await Tree.traverse(tree), tree);
|
|
353
|
-
assert.equal(await Tree.traverse(tree, "a1"), 1);
|
|
354
|
-
assert.equal(await Tree.traverse(tree, "a2", "b2", "c2"), 4);
|
|
355
|
-
assert.equal(
|
|
356
|
-
await Tree.traverse(tree, "a2", "doesntexist", "c2"),
|
|
357
|
-
undefined
|
|
358
|
-
);
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
test("traverse() a function with fixed number of arguments", async () => {
|
|
362
|
-
const tree = (a, b) => ({
|
|
363
|
-
c: "Result",
|
|
364
|
-
});
|
|
365
|
-
assert.equal(await Tree.traverse(tree, "a", "b", "c"), "Result");
|
|
366
|
-
});
|
|
367
|
-
|
|
368
|
-
test("traverse() from one tree into another", async () => {
|
|
369
|
-
const tree = new ObjectTree({
|
|
370
|
-
a: {
|
|
371
|
-
b: new MapTree([
|
|
372
|
-
["c", "Hello"],
|
|
373
|
-
["d", "Goodbye"],
|
|
374
|
-
]),
|
|
375
|
-
},
|
|
376
|
-
});
|
|
377
|
-
assert.equal(await Tree.traverse(tree, "a", "b", "c"), "Hello");
|
|
378
|
-
});
|
|
379
|
-
|
|
380
|
-
test("traversePath() traverses a slash-separated path", async () => {
|
|
381
|
-
const tree = new ObjectTree({
|
|
382
|
-
a: {
|
|
383
|
-
b: {
|
|
384
|
-
c: "Hello",
|
|
385
|
-
},
|
|
386
|
-
},
|
|
387
|
-
});
|
|
388
|
-
assert.equal(await Tree.traversePath(tree, "a/b/c"), "Hello");
|
|
389
|
-
});
|
|
390
|
-
|
|
391
|
-
test("values() returns the store's values", async () => {
|
|
392
|
-
const fixture = createFixture();
|
|
393
|
-
assert.deepEqual(Array.from(await Tree.values(fixture)), [
|
|
394
|
-
"Hello, **Alice**.",
|
|
395
|
-
"Hello, **Bob**.",
|
|
396
|
-
"Hello, **Carol**.",
|
|
397
|
-
]);
|
|
398
|
-
});
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
function createFixture() {
|
|
402
|
-
return new ObjectTree({
|
|
403
|
-
"Alice.md": "Hello, **Alice**.",
|
|
404
|
-
"Bob.md": "Hello, **Bob**.",
|
|
405
|
-
"Carol.md": "Hello, **Carol**.",
|
|
406
|
-
});
|
|
407
|
-
}
|
package/test/utilities.test.js
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert";
|
|
2
|
-
import { describe, test } from "node:test";
|
|
3
|
-
import { ObjectTree } from "../src/internal.js";
|
|
4
|
-
import * as symbols from "../src/symbols.js";
|
|
5
|
-
import * as utilities from "../src/utilities.js";
|
|
6
|
-
|
|
7
|
-
describe("utilities", () => {
|
|
8
|
-
test("box returns a boxed value", () => {
|
|
9
|
-
const string = "string";
|
|
10
|
-
const stringObject = utilities.box(string);
|
|
11
|
-
assert(stringObject instanceof String);
|
|
12
|
-
assert.equal(stringObject, string);
|
|
13
|
-
|
|
14
|
-
const number = 1;
|
|
15
|
-
const numberObject = utilities.box(number);
|
|
16
|
-
assert(numberObject instanceof Number);
|
|
17
|
-
assert.equal(numberObject, number);
|
|
18
|
-
|
|
19
|
-
const boolean = true;
|
|
20
|
-
const booleanObject = utilities.box(boolean);
|
|
21
|
-
assert(booleanObject instanceof Boolean);
|
|
22
|
-
assert.equal(booleanObject, boolean);
|
|
23
|
-
|
|
24
|
-
const object = {};
|
|
25
|
-
const boxedObject = utilities.box(object);
|
|
26
|
-
assert.equal(boxedObject, object);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
test("getRealmObjectPrototype returns the object's root prototype", () => {
|
|
30
|
-
const object = {};
|
|
31
|
-
const proto = utilities.getRealmObjectPrototype(object);
|
|
32
|
-
assert.equal(proto, Object.prototype);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
test("isPlainObject returns true if the object is a plain object", () => {
|
|
36
|
-
assert.equal(utilities.isPlainObject({}), true);
|
|
37
|
-
assert.equal(utilities.isPlainObject(new Object()), true);
|
|
38
|
-
assert.equal(utilities.isPlainObject(Object.create(null)), true);
|
|
39
|
-
class Foo {}
|
|
40
|
-
assert.equal(utilities.isPlainObject(new Foo()), false);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test("keysFromPath() returns the keys from a slash-separated path", () => {
|
|
44
|
-
assert.deepEqual(utilities.keysFromPath(""), []);
|
|
45
|
-
assert.deepEqual(utilities.keysFromPath("/"), []);
|
|
46
|
-
assert.deepEqual(utilities.keysFromPath("a/b/c"), ["a/", "b/", "c"]);
|
|
47
|
-
assert.deepEqual(utilities.keysFromPath("a/b/c/"), ["a/", "b/", "c/"]);
|
|
48
|
-
assert.deepEqual(utilities.keysFromPath("/foo/"), ["foo/"]);
|
|
49
|
-
assert.deepEqual(utilities.keysFromPath("a///b"), ["a/", "b"]);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test("naturalOrder compares strings in natural order", () => {
|
|
53
|
-
const strings = ["file10", "file1", "file9"];
|
|
54
|
-
strings.sort(utilities.naturalOrder);
|
|
55
|
-
assert.deepEqual(strings, ["file1", "file9", "file10"]);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test("pathFromKeys() returns a slash-separated path from keys", () => {
|
|
59
|
-
assert.equal(utilities.pathFromKeys([]), "");
|
|
60
|
-
assert.equal(utilities.pathFromKeys(["a", "b", "c"]), "a/b/c");
|
|
61
|
-
assert.equal(utilities.pathFromKeys(["a/", "b/", "c"]), "a/b/c");
|
|
62
|
-
assert.equal(utilities.pathFromKeys(["a/", "b/", "c/"]), "a/b/c/");
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
test("pipeline applies a series of functions to a value", async () => {
|
|
66
|
-
const addOne = (n) => n + 1;
|
|
67
|
-
const double = (n) => n * 2;
|
|
68
|
-
const square = (n) => n * n;
|
|
69
|
-
const result = await utilities.pipeline(1, addOne, double, square);
|
|
70
|
-
assert.equal(result, 16);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
test("setParent sets a child's parent", () => {
|
|
74
|
-
const parent = new ObjectTree({});
|
|
75
|
-
|
|
76
|
-
// Set [symbols.parent] on a plain object.
|
|
77
|
-
const object = {};
|
|
78
|
-
utilities.setParent(object, parent);
|
|
79
|
-
assert.equal(object[symbols.parent], parent);
|
|
80
|
-
|
|
81
|
-
// Leave [symbols.parent] alone if it's already set.
|
|
82
|
-
const childWithParent = {
|
|
83
|
-
[symbols.parent]: "parent",
|
|
84
|
-
};
|
|
85
|
-
utilities.setParent(childWithParent, parent);
|
|
86
|
-
assert.equal(childWithParent[symbols.parent], "parent");
|
|
87
|
-
|
|
88
|
-
// Set `parent` on a tree.
|
|
89
|
-
const tree = new ObjectTree({});
|
|
90
|
-
utilities.setParent(tree, parent);
|
|
91
|
-
assert.equal(tree.parent, parent);
|
|
92
|
-
|
|
93
|
-
// Leave `parent` alone if it's already set.
|
|
94
|
-
const treeWithParent = new ObjectTree({});
|
|
95
|
-
treeWithParent.parent = "parent";
|
|
96
|
-
utilities.setParent(treeWithParent, parent);
|
|
97
|
-
assert.equal(treeWithParent.parent, "parent");
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
test("toPlainValue returns the plainest representation of an object", async () => {
|
|
101
|
-
class User {
|
|
102
|
-
constructor(name) {
|
|
103
|
-
this.name = name;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
assert.equal(await utilities.toPlainValue(1), 1);
|
|
108
|
-
assert.equal(await utilities.toPlainValue("string"), "string");
|
|
109
|
-
assert.deepEqual(await utilities.toPlainValue({ a: 1 }), { a: 1 });
|
|
110
|
-
assert.equal(
|
|
111
|
-
await utilities.toPlainValue(new TextEncoder().encode("bytes")),
|
|
112
|
-
"bytes"
|
|
113
|
-
);
|
|
114
|
-
// ArrayBuffer with non-printable characters should be returned as base64
|
|
115
|
-
assert.equal(
|
|
116
|
-
await utilities.toPlainValue(new Uint8Array([1, 2, 3]).buffer),
|
|
117
|
-
"AQID"
|
|
118
|
-
);
|
|
119
|
-
assert.equal(await utilities.toPlainValue(async () => "result"), "result");
|
|
120
|
-
assert.deepEqual(await utilities.toPlainValue(new User("Alice")), {
|
|
121
|
-
name: "Alice",
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
test("toString returns the value of an object's `toString` method", () => {
|
|
126
|
-
const object = {
|
|
127
|
-
toString: () => "text",
|
|
128
|
-
};
|
|
129
|
-
assert.equal(utilities.toString(object), "text");
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
test("toString returns null for an object with no useful `toString`", () => {
|
|
133
|
-
const object = {};
|
|
134
|
-
assert.equal(utilities.toString(object), null);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
test("toString decodes an ArrayBuffer as UTF-8", () => {
|
|
138
|
-
const arrayBuffer = new TextEncoder().encode("text").buffer;
|
|
139
|
-
assert.equal(utilities.toString(arrayBuffer), "text");
|
|
140
|
-
});
|
|
141
|
-
});
|