@weborigami/async-tree 0.5.3 → 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 -502
- 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 +157 -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 +62 -45
- 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/paginate.test.js +2 -1
- 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 -439
- package/test/Tree.test.js +0 -407
- package/test/utilities.test.js +0 -141
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import { describe, test } from "node:test";
|
|
3
|
-
import FunctionTree from "../../src/drivers/FunctionTree.js";
|
|
4
3
|
import { DeepObjectTree, ObjectTree, Tree } from "../../src/internal.js";
|
|
5
4
|
import map from "../../src/operations/map.js";
|
|
6
5
|
import * as trailingSlash from "../../src/trailingSlash.js";
|
|
7
6
|
|
|
8
7
|
describe("map", () => {
|
|
9
|
-
test("
|
|
8
|
+
test("throws if no key or value function is supplied", async () => {
|
|
10
9
|
const tree = {
|
|
11
10
|
a: "letter a",
|
|
12
11
|
b: "letter b",
|
|
13
12
|
};
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
a: "letter a",
|
|
17
|
-
b: "letter b",
|
|
13
|
+
assert.rejects(async () => {
|
|
14
|
+
await map(tree, {});
|
|
18
15
|
});
|
|
19
16
|
});
|
|
20
17
|
|
|
@@ -24,7 +21,7 @@ describe("map", () => {
|
|
|
24
21
|
b: "letter b",
|
|
25
22
|
c: undefined, // Won't be mapped
|
|
26
23
|
});
|
|
27
|
-
const mapped = map(tree, {
|
|
24
|
+
const mapped = await map(tree, {
|
|
28
25
|
value: (sourceValue, sourceKey, innerTree) => {
|
|
29
26
|
assert(sourceKey === "a" || sourceKey === "b");
|
|
30
27
|
assert.equal(innerTree, tree);
|
|
@@ -43,7 +40,7 @@ describe("map", () => {
|
|
|
43
40
|
a: "letter a",
|
|
44
41
|
b: "letter b",
|
|
45
42
|
};
|
|
46
|
-
const uppercaseValues = map(tree, (sourceValue, sourceKey, tree) => {
|
|
43
|
+
const uppercaseValues = await map(tree, (sourceValue, sourceKey, tree) => {
|
|
47
44
|
assert(sourceKey === "a" || sourceKey === "b");
|
|
48
45
|
return sourceValue.toUpperCase();
|
|
49
46
|
});
|
|
@@ -58,7 +55,7 @@ describe("map", () => {
|
|
|
58
55
|
a: "letter a",
|
|
59
56
|
b: "letter b",
|
|
60
57
|
};
|
|
61
|
-
const underscoreKeys = map(tree, {
|
|
58
|
+
const underscoreKeys = await map(tree, {
|
|
62
59
|
key: addUnderscore,
|
|
63
60
|
inverseKey: removeUnderscore,
|
|
64
61
|
});
|
|
@@ -73,7 +70,7 @@ describe("map", () => {
|
|
|
73
70
|
a: "letter a",
|
|
74
71
|
b: "letter b",
|
|
75
72
|
};
|
|
76
|
-
const underscoreKeys = map(tree, {
|
|
73
|
+
const underscoreKeys = await map(tree, {
|
|
77
74
|
key: addUnderscore,
|
|
78
75
|
});
|
|
79
76
|
assert.deepEqual(await Tree.plain(underscoreKeys), {
|
|
@@ -83,18 +80,19 @@ describe("map", () => {
|
|
|
83
80
|
});
|
|
84
81
|
|
|
85
82
|
test("maps keys and values", async () => {
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
value:
|
|
83
|
+
const treelike = new ObjectTree([
|
|
84
|
+
{ name: "Alice", age: 1 },
|
|
85
|
+
{ name: "Bob", age: 2 },
|
|
86
|
+
{ name: "Carol", age: 3 },
|
|
87
|
+
]);
|
|
88
|
+
const result = await map(treelike, {
|
|
89
|
+
key: (value, key, tree) => value.name,
|
|
90
|
+
value: (value, key, tree) => value.age,
|
|
94
91
|
});
|
|
95
|
-
assert.deepEqual(await Tree.plain(
|
|
96
|
-
|
|
97
|
-
|
|
92
|
+
assert.deepEqual(await Tree.plain(result), {
|
|
93
|
+
Alice: 1,
|
|
94
|
+
Bob: 2,
|
|
95
|
+
Carol: 3,
|
|
98
96
|
});
|
|
99
97
|
});
|
|
100
98
|
|
|
@@ -105,8 +103,8 @@ describe("map", () => {
|
|
|
105
103
|
b: "letter b",
|
|
106
104
|
},
|
|
107
105
|
};
|
|
108
|
-
const underscoreKeys = map(tree, {
|
|
109
|
-
key: async (sourceKey, tree) => `_${sourceKey}`,
|
|
106
|
+
const underscoreKeys = await map(tree, {
|
|
107
|
+
key: async (value, sourceKey, tree) => `_${sourceKey}`,
|
|
110
108
|
inverseKey: async (resultKey, tree) => resultKey.slice(1),
|
|
111
109
|
value: async (sourceValue, sourceKey, tree) => sourceKey,
|
|
112
110
|
});
|
|
@@ -124,7 +122,7 @@ describe("map", () => {
|
|
|
124
122
|
a: "letter a",
|
|
125
123
|
b: "letter b",
|
|
126
124
|
};
|
|
127
|
-
const mapped = map(tree, uppercase);
|
|
125
|
+
const mapped = await map(tree, uppercase);
|
|
128
126
|
assert.deepEqual(await Tree.plain(mapped), {
|
|
129
127
|
_a: "LETTER A",
|
|
130
128
|
_b: "LETTER B",
|
|
@@ -138,7 +136,7 @@ describe("map", () => {
|
|
|
138
136
|
b: "letter b",
|
|
139
137
|
},
|
|
140
138
|
});
|
|
141
|
-
const uppercaseValues = map(tree, {
|
|
139
|
+
const uppercaseValues = await map(tree, {
|
|
142
140
|
deep: true,
|
|
143
141
|
value: (sourceValue, sourceKey, tree) => sourceValue.toUpperCase(),
|
|
144
142
|
});
|
|
@@ -157,7 +155,7 @@ describe("map", () => {
|
|
|
157
155
|
b: "letter b",
|
|
158
156
|
},
|
|
159
157
|
});
|
|
160
|
-
const underscoreKeys = map(tree, {
|
|
158
|
+
const underscoreKeys = await map(tree, {
|
|
161
159
|
deep: true,
|
|
162
160
|
key: addUnderscore,
|
|
163
161
|
inverseKey: removeUnderscore,
|
|
@@ -177,7 +175,7 @@ describe("map", () => {
|
|
|
177
175
|
b: "letter b",
|
|
178
176
|
},
|
|
179
177
|
});
|
|
180
|
-
const underscoreKeysUppercaseValues = map(tree, {
|
|
178
|
+
const underscoreKeysUppercaseValues = await map(tree, {
|
|
181
179
|
deep: true,
|
|
182
180
|
key: addUnderscore,
|
|
183
181
|
inverseKey: removeUnderscore,
|
|
@@ -191,6 +189,42 @@ describe("map", () => {
|
|
|
191
189
|
});
|
|
192
190
|
});
|
|
193
191
|
|
|
192
|
+
test("keyNeedsSourceValue can be set to false in cases where the value isn't necessary", async () => {
|
|
193
|
+
const tree = {
|
|
194
|
+
a: "letter a",
|
|
195
|
+
b: "letter b",
|
|
196
|
+
c: "letter c",
|
|
197
|
+
};
|
|
198
|
+
const mapped = await map(tree, {
|
|
199
|
+
keyNeedsSourceValue: false,
|
|
200
|
+
key: (value, key) => {
|
|
201
|
+
assert.equal(value, null);
|
|
202
|
+
return key.toUpperCase();
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
assert.deepEqual(await Tree.plain(mapped), {
|
|
206
|
+
A: "letter a",
|
|
207
|
+
B: "letter b",
|
|
208
|
+
C: "letter c",
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
test("can add an extension to a key", async () => {
|
|
213
|
+
const treelike = {
|
|
214
|
+
"file0.txt": 1,
|
|
215
|
+
file1: 2,
|
|
216
|
+
file2: 3,
|
|
217
|
+
};
|
|
218
|
+
const fixture = await map(treelike, {
|
|
219
|
+
extension: "->.data",
|
|
220
|
+
});
|
|
221
|
+
assert.deepEqual(await Tree.plain(fixture), {
|
|
222
|
+
"file0.txt.data": 1,
|
|
223
|
+
"file1.data": 2,
|
|
224
|
+
"file2.data": 3,
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
194
228
|
test("can change a key's extension", async () => {
|
|
195
229
|
const treelike = {
|
|
196
230
|
"file1.lower": "will be mapped",
|
|
@@ -224,26 +258,9 @@ describe("map", () => {
|
|
|
224
258
|
},
|
|
225
259
|
});
|
|
226
260
|
});
|
|
227
|
-
|
|
228
|
-
test("needsSourceValue can be set to false in cases where the value isn't necessary", async () => {
|
|
229
|
-
let flag = false;
|
|
230
|
-
const tree = new FunctionTree(() => {
|
|
231
|
-
flag = true;
|
|
232
|
-
}, ["a", "b", "c"]);
|
|
233
|
-
const mapped = map(tree, {
|
|
234
|
-
needsSourceValue: false,
|
|
235
|
-
value: () => "X",
|
|
236
|
-
});
|
|
237
|
-
assert.deepEqual(await Tree.plain(mapped), {
|
|
238
|
-
a: "X",
|
|
239
|
-
b: "X",
|
|
240
|
-
c: "X",
|
|
241
|
-
});
|
|
242
|
-
assert(!flag);
|
|
243
|
-
});
|
|
244
261
|
});
|
|
245
262
|
|
|
246
|
-
function addUnderscore(key) {
|
|
263
|
+
function addUnderscore(value, key) {
|
|
247
264
|
return `_${key}`;
|
|
248
265
|
}
|
|
249
266
|
|
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import DeepObjectTree from "../../src/drivers/DeepObjectTree.js";
|
|
4
|
+
import mapReduce from "../../src/operations/mapReduce.js";
|
|
5
|
+
|
|
6
|
+
describe("mapReduce", () => {
|
|
7
|
+
test("can map values and reduce them", async () => {
|
|
8
|
+
const tree = new DeepObjectTree({
|
|
9
|
+
a: 1,
|
|
10
|
+
b: 2,
|
|
11
|
+
more: {
|
|
12
|
+
c: 3,
|
|
13
|
+
},
|
|
14
|
+
d: 4,
|
|
15
|
+
});
|
|
16
|
+
const reduced = await mapReduce(
|
|
17
|
+
tree,
|
|
18
|
+
(value) => value,
|
|
19
|
+
async (values) => String.prototype.concat(...values)
|
|
20
|
+
);
|
|
21
|
+
assert.deepEqual(reduced, "1234");
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import { Tree } from "../../src/internal.js";
|
|
4
|
+
import match from "../../src/operations/match.js";
|
|
5
|
+
|
|
6
|
+
describe("match", () => {
|
|
7
|
+
test("matches keys against a simplified pattern", async () => {
|
|
8
|
+
function fn(matches) {
|
|
9
|
+
return `Hello, ${matches.name}!`;
|
|
10
|
+
}
|
|
11
|
+
const tree = match("[name].html", fn, [
|
|
12
|
+
"Alice.html",
|
|
13
|
+
"Bob.html",
|
|
14
|
+
"Carol.html",
|
|
15
|
+
]);
|
|
16
|
+
assert.deepEqual(await Tree.plain(tree), {
|
|
17
|
+
"Alice.html": "Hello, Alice!",
|
|
18
|
+
"Bob.html": "Hello, Bob!",
|
|
19
|
+
"Carol.html": "Hello, Carol!",
|
|
20
|
+
});
|
|
21
|
+
const value = await tree.get("David.html");
|
|
22
|
+
assert.equal(value, "Hello, David!");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("matches keys against a regular expression", async () => {
|
|
26
|
+
function fn(matches) {
|
|
27
|
+
return `Hello, ${matches.name}!`;
|
|
28
|
+
}
|
|
29
|
+
const tree = match(/^(?<name>.+)\.html$/, fn);
|
|
30
|
+
const value = await tree.get("Alice.html");
|
|
31
|
+
assert.equal(value, "Hello, Alice!");
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -2,26 +2,25 @@ import assert from "node:assert";
|
|
|
2
2
|
import { describe, test } from "node:test";
|
|
3
3
|
import { DeepObjectTree, ObjectTree, Tree } from "../../src/internal.js";
|
|
4
4
|
import merge from "../../src/operations/merge.js";
|
|
5
|
-
import * as symbols from "../../src/symbols.js";
|
|
6
5
|
|
|
7
6
|
describe("merge", () => {
|
|
8
7
|
test("performs a shallow merge", async () => {
|
|
9
8
|
const fixture = merge(
|
|
10
|
-
{
|
|
9
|
+
new ObjectTree({
|
|
11
10
|
a: 1,
|
|
12
11
|
// Will be obscured by `b` that follows
|
|
13
12
|
b: {
|
|
14
13
|
c: 2,
|
|
15
14
|
},
|
|
16
|
-
},
|
|
17
|
-
{
|
|
15
|
+
}),
|
|
16
|
+
new ObjectTree({
|
|
18
17
|
b: {
|
|
19
18
|
d: 3,
|
|
20
19
|
},
|
|
21
20
|
e: {
|
|
22
21
|
f: 4,
|
|
23
22
|
},
|
|
24
|
-
}
|
|
23
|
+
})
|
|
25
24
|
);
|
|
26
25
|
|
|
27
26
|
assert.deepEqual(await Tree.plain(fixture), {
|
|
@@ -37,10 +36,6 @@ describe("merge", () => {
|
|
|
37
36
|
// Merge is shallow, and last tree wins, so `b/c` doesn't exist
|
|
38
37
|
const c = await Tree.traverse(fixture, "b", "c");
|
|
39
38
|
assert.equal(c, undefined);
|
|
40
|
-
|
|
41
|
-
// Parent of a subvalue is the merged tree
|
|
42
|
-
const b = await fixture.get("b");
|
|
43
|
-
assert.equal(b[symbols.parent], fixture);
|
|
44
39
|
});
|
|
45
40
|
|
|
46
41
|
test("subtree can overwrite a leaf node", async () => {
|
|
@@ -61,4 +56,23 @@ describe("merge", () => {
|
|
|
61
56
|
},
|
|
62
57
|
});
|
|
63
58
|
});
|
|
59
|
+
|
|
60
|
+
test("if all arguments are plain objects, result is a plain object", async () => {
|
|
61
|
+
const result = await merge(
|
|
62
|
+
{
|
|
63
|
+
a: 1,
|
|
64
|
+
b: 2,
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
c: 3,
|
|
68
|
+
d: 4,
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
assert.deepEqual(result, {
|
|
72
|
+
a: 1,
|
|
73
|
+
b: 2,
|
|
74
|
+
c: 3,
|
|
75
|
+
d: 4,
|
|
76
|
+
});
|
|
77
|
+
});
|
|
64
78
|
});
|
|
@@ -13,7 +13,8 @@ describe("paginate", () => {
|
|
|
13
13
|
e: 5,
|
|
14
14
|
};
|
|
15
15
|
const paginated = await paginate.call(null, treelike, 2);
|
|
16
|
-
|
|
16
|
+
const plain = await Tree.plain(paginated);
|
|
17
|
+
assert.deepEqual(await plain, {
|
|
17
18
|
1: {
|
|
18
19
|
items: { a: 1, b: 2 },
|
|
19
20
|
nextPage: 2,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import { ObjectTree } from "../../src/internal.js";
|
|
4
|
+
import parent from "../../src/operations/parent.js";
|
|
5
|
+
|
|
6
|
+
describe("parent", () => {
|
|
7
|
+
test("returns a tree's parent", async () => {
|
|
8
|
+
const tree = new ObjectTree({
|
|
9
|
+
sub: new ObjectTree({}),
|
|
10
|
+
});
|
|
11
|
+
const sub = await tree.get("sub");
|
|
12
|
+
const result = await parent(sub);
|
|
13
|
+
assert.equal(result, tree);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import DeepObjectTree from "../../src/drivers/DeepObjectTree.js";
|
|
4
|
+
import ObjectTree from "../../src/drivers/ObjectTree.js";
|
|
5
|
+
import paths from "../../src/operations/paths.js";
|
|
6
|
+
|
|
7
|
+
describe("paths", () => {
|
|
8
|
+
test("returns an array of paths to the values in the tree", async () => {
|
|
9
|
+
const tree = new DeepObjectTree({
|
|
10
|
+
a: 1,
|
|
11
|
+
b: 2,
|
|
12
|
+
c: {
|
|
13
|
+
d: 3,
|
|
14
|
+
e: 4,
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
assert.deepEqual(await paths(tree), ["a", "b", "c/d", "c/e"]);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("can focus just on keys with trailing slashes", async () => {
|
|
21
|
+
const tree = new ObjectTree({
|
|
22
|
+
a: 1,
|
|
23
|
+
b: 2,
|
|
24
|
+
// This is a shallow ObjectTree, so `c` won't have a trailing slash
|
|
25
|
+
c: {
|
|
26
|
+
d: 3,
|
|
27
|
+
},
|
|
28
|
+
// Explicitly include a trailing slash to signal a subtree
|
|
29
|
+
"d/": new ObjectTree({
|
|
30
|
+
e: 4,
|
|
31
|
+
}),
|
|
32
|
+
});
|
|
33
|
+
assert.deepEqual(await paths(tree, { assumeSlashes: true }), [
|
|
34
|
+
"a",
|
|
35
|
+
"b",
|
|
36
|
+
"c",
|
|
37
|
+
"d/e",
|
|
38
|
+
]);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import ObjectTree from "../../src/drivers/ObjectTree.js";
|
|
4
|
+
import plain from "../../src/operations/plain.js";
|
|
5
|
+
|
|
6
|
+
describe("plain", () => {
|
|
7
|
+
test("produces a plain object version of a tree", async () => {
|
|
8
|
+
const tree = new ObjectTree({
|
|
9
|
+
a: 1,
|
|
10
|
+
// Slashes should be normalized
|
|
11
|
+
"sub1/": {
|
|
12
|
+
b: 2,
|
|
13
|
+
},
|
|
14
|
+
sub2: {
|
|
15
|
+
c: 3,
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
assert.deepEqual(await plain(tree), {
|
|
19
|
+
a: 1,
|
|
20
|
+
sub1: {
|
|
21
|
+
b: 2,
|
|
22
|
+
},
|
|
23
|
+
sub2: {
|
|
24
|
+
c: 3,
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("produces an array for an array-like tree", async () => {
|
|
30
|
+
const original = ["a", "b", "c"];
|
|
31
|
+
const tree = new ObjectTree(original);
|
|
32
|
+
assert.deepEqual(await plain(tree), original);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("leaves an array-like tree as an object if keys aren't consecutive", async () => {
|
|
36
|
+
const original = {
|
|
37
|
+
0: "a",
|
|
38
|
+
1: "b",
|
|
39
|
+
// missing
|
|
40
|
+
3: "c",
|
|
41
|
+
};
|
|
42
|
+
const tree = new ObjectTree(original);
|
|
43
|
+
assert.deepEqual(await plain(tree), original);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("returns empty array or object for ObjectTree as necessary", async () => {
|
|
47
|
+
const tree = new ObjectTree({});
|
|
48
|
+
assert.deepEqual(await plain(tree), {});
|
|
49
|
+
const arrayTree = new ObjectTree([]);
|
|
50
|
+
assert.deepEqual(await plain(arrayTree), []);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("awaits async properties", async () => {
|
|
54
|
+
const object = {
|
|
55
|
+
get name() {
|
|
56
|
+
return Promise.resolve("Alice");
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
assert.deepEqual(await plain(object), { name: "Alice" });
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("coerces TypedArray values to strings", async () => {
|
|
63
|
+
const tree = new ObjectTree({
|
|
64
|
+
a: new TextEncoder().encode("Hello, world."),
|
|
65
|
+
});
|
|
66
|
+
const result = await plain(tree);
|
|
67
|
+
assert.equal(result.a, "Hello, world.");
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -10,7 +10,7 @@ describe("reverse", () => {
|
|
|
10
10
|
b: "B",
|
|
11
11
|
c: "C",
|
|
12
12
|
};
|
|
13
|
-
const reversed = reverse.call(null, tree);
|
|
13
|
+
const reversed = await reverse.call(null, tree);
|
|
14
14
|
// @ts-ignore
|
|
15
15
|
assert.deepEqual(Array.from(await reversed.keys()), ["c", "b", "a"]);
|
|
16
16
|
// @ts-ignore
|
|
@@ -13,7 +13,7 @@ describe("scope", () => {
|
|
|
13
13
|
a: 3,
|
|
14
14
|
});
|
|
15
15
|
inner.parent = outer;
|
|
16
|
-
const innerScope = scope(inner);
|
|
16
|
+
const innerScope = await scope(inner);
|
|
17
17
|
assert.deepEqual([...(await innerScope.keys())], ["a", "b"]);
|
|
18
18
|
// Inner tree has precedence
|
|
19
19
|
assert.equal(await innerScope.get("a"), 3);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import { DeepObjectTree, ObjectTree, Tree } from "../../src/internal.js";
|
|
4
|
+
import setDeep from "../../src/operations/setDeep.js";
|
|
5
|
+
|
|
6
|
+
describe("tree/setDeep", () => {
|
|
7
|
+
test("can apply updates with a single argument to set", async () => {
|
|
8
|
+
const tree = new DeepObjectTree({
|
|
9
|
+
a: 1,
|
|
10
|
+
b: 2,
|
|
11
|
+
more: {
|
|
12
|
+
d: 3,
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// Apply changes.
|
|
17
|
+
await setDeep.call(
|
|
18
|
+
null,
|
|
19
|
+
tree,
|
|
20
|
+
new DeepObjectTree({
|
|
21
|
+
a: 4, // Overwrite existing value
|
|
22
|
+
b: undefined, // Delete
|
|
23
|
+
c: 5, // Add
|
|
24
|
+
more: {
|
|
25
|
+
// Should leave existing `more` keys alone.
|
|
26
|
+
e: 6, // Add
|
|
27
|
+
},
|
|
28
|
+
// Add new subtree
|
|
29
|
+
extra: {
|
|
30
|
+
f: 7,
|
|
31
|
+
},
|
|
32
|
+
})
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
assert.deepEqual(await Tree.plain(tree), {
|
|
36
|
+
a: 4,
|
|
37
|
+
c: 5,
|
|
38
|
+
more: {
|
|
39
|
+
d: 3,
|
|
40
|
+
e: 6,
|
|
41
|
+
},
|
|
42
|
+
extra: {
|
|
43
|
+
f: 7,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("can apply updates to an array", async () => {
|
|
49
|
+
const tree = new ObjectTree(["a", "b", "c"]);
|
|
50
|
+
await setDeep.call(null, tree, ["d", "e"]);
|
|
51
|
+
assert.deepEqual(await Tree.plain(tree), ["d", "e", "c"]);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import shuffle from "../../src/operations/shuffle.js";
|
|
4
|
+
|
|
5
|
+
describe("shuffle", () => {
|
|
6
|
+
test("shuffles the keys of a tree", async () => {
|
|
7
|
+
const obj = {
|
|
8
|
+
a: 1,
|
|
9
|
+
b: 2,
|
|
10
|
+
c: 3,
|
|
11
|
+
d: 4,
|
|
12
|
+
e: 5,
|
|
13
|
+
};
|
|
14
|
+
const result = await shuffle(obj);
|
|
15
|
+
const keys = Array.from(await result.keys());
|
|
16
|
+
assert.deepEqual(keys.sort(), Object.keys(obj).sort());
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -10,7 +10,7 @@ describe("sort", () => {
|
|
|
10
10
|
file1: null,
|
|
11
11
|
file9: null,
|
|
12
12
|
});
|
|
13
|
-
const sorted = sort(tree);
|
|
13
|
+
const sorted = await sort(tree);
|
|
14
14
|
assert.deepEqual(Array.from(await sorted.keys()), [
|
|
15
15
|
"file1",
|
|
16
16
|
"file10",
|
|
@@ -26,7 +26,7 @@ describe("sort", () => {
|
|
|
26
26
|
});
|
|
27
27
|
// Reverse order
|
|
28
28
|
const compare = (a, b) => (a > b ? -1 : a < b ? 1 : 0);
|
|
29
|
-
const sorted = sort(tree, { compare });
|
|
29
|
+
const sorted = await sort(tree, { compare });
|
|
30
30
|
assert.deepEqual(Array.from(await sorted.keys()), ["c", "b", "a"]);
|
|
31
31
|
});
|
|
32
32
|
|
|
@@ -37,7 +37,7 @@ describe("sort", () => {
|
|
|
37
37
|
Carol: { age: 42 },
|
|
38
38
|
};
|
|
39
39
|
const sorted = await sort(tree, {
|
|
40
|
-
sortKey: async (key, tree) =>
|
|
40
|
+
sortKey: async (value, key, tree) => value.age,
|
|
41
41
|
});
|
|
42
42
|
assert.deepEqual(Array.from(await sorted.keys()), [
|
|
43
43
|
"Bob",
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import ObjectTree from "../../src/drivers/ObjectTree.js";
|
|
4
|
+
import toFunction from "../../src/operations/toFunction.js";
|
|
5
|
+
|
|
6
|
+
describe("toFunction", () => {
|
|
7
|
+
test("returns a function that invokes a tree's get() method", async () => {
|
|
8
|
+
const tree = new ObjectTree({
|
|
9
|
+
a: 1,
|
|
10
|
+
b: 2,
|
|
11
|
+
});
|
|
12
|
+
const fn = await toFunction(tree);
|
|
13
|
+
assert.equal(await fn("a"), 1);
|
|
14
|
+
assert.equal(await fn("b"), 2);
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import MapTree from "../../src/drivers/MapTree.js";
|
|
4
|
+
import ObjectTree from "../../src/drivers/ObjectTree.js";
|
|
5
|
+
import traverse from "../../src/operations/traverse.js";
|
|
6
|
+
|
|
7
|
+
describe("traverse", () => {
|
|
8
|
+
test("traverses a path of keys", async () => {
|
|
9
|
+
const tree = new ObjectTree({
|
|
10
|
+
a1: 1,
|
|
11
|
+
a2: {
|
|
12
|
+
b1: 2,
|
|
13
|
+
b2: {
|
|
14
|
+
c1: 3,
|
|
15
|
+
c2: 4,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
assert.equal(await traverse(tree), tree);
|
|
20
|
+
assert.equal(await traverse(tree, "a1"), 1);
|
|
21
|
+
assert.equal(await traverse(tree, "a2", "b2", "c2"), 4);
|
|
22
|
+
assert.equal(await traverse(tree, "a2", "doesntexist", "c2"), undefined);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("traverses a function with fixed number of arguments", async () => {
|
|
26
|
+
const tree = (a, b) => ({
|
|
27
|
+
c: "Result",
|
|
28
|
+
});
|
|
29
|
+
assert.equal(await traverse(tree, "a", "b", "c"), "Result");
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("traverses from one tree into another", async () => {
|
|
33
|
+
const tree = new ObjectTree({
|
|
34
|
+
a: {
|
|
35
|
+
b: new MapTree([
|
|
36
|
+
["c", "Hello"],
|
|
37
|
+
["d", "Goodbye"],
|
|
38
|
+
]),
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
assert.equal(await traverse(tree, "a", "b", "c"), "Hello");
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import traversePath from "../../src/operations/traversePath.js";
|
|
4
|
+
|
|
5
|
+
describe("traversePath", () => {
|
|
6
|
+
test("traversePath() traverses a slash-separated path", async () => {
|
|
7
|
+
const tree = {
|
|
8
|
+
a: {
|
|
9
|
+
b: {
|
|
10
|
+
c: "Hello",
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
assert.equal(await traversePath(tree, "a/b/c"), "Hello");
|
|
15
|
+
});
|
|
16
|
+
});
|