@weborigami/async-tree 0.0.39 → 0.0.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/main.js +1 -0
- package/package.json +4 -4
- package/src/DeepObjectTree.js +27 -0
- package/src/FunctionTree.js +2 -1
- package/src/MapTree.js +1 -5
- package/src/ObjectTree.js +2 -9
- package/src/SetTree.js +1 -5
- package/src/Tree.js +43 -17
- package/src/transforms/groupBy.js +1 -0
- package/test/DeepObjectTree.test.js +24 -0
- package/test/ObjectTree.test.js +8 -41
- package/test/SetTree.test.js +2 -1
- package/test/Tree.test.js +23 -17
- package/test/operations/mergeDeep.test.js +3 -2
- package/test/transforms/groupBy.test.js +1 -3
- package/test/transforms/map.test.js +4 -3
- package/test/transforms/regExpKeys.test.js +2 -1
package/main.js
CHANGED
|
@@ -6,6 +6,7 @@ export { default as FunctionTree } from "./src/FunctionTree.js";
|
|
|
6
6
|
export { default as MapTree } from "./src/MapTree.js";
|
|
7
7
|
export { default as ObjectTree } from "./src/ObjectTree.js";
|
|
8
8
|
// Skip BrowserFileTree.js, which is browser-only.
|
|
9
|
+
export { default as DeepObjectTree } from "./src/DeepObjectTree.js";
|
|
9
10
|
export { default as SetTree } from "./src/SetTree.js";
|
|
10
11
|
export { default as SiteTree } from "./src/SiteTree.js";
|
|
11
12
|
export * as Tree from "./src/Tree.js";
|
package/package.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/async-tree",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.41",
|
|
4
4
|
"description": "Asynchronous tree drivers based on standard JavaScript classes",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./main.js",
|
|
7
7
|
"browser": "./browser.js",
|
|
8
8
|
"types": "./index.ts",
|
|
9
9
|
"devDependencies": {
|
|
10
|
-
"@types/node": "20.11.
|
|
10
|
+
"@types/node": "20.11.7",
|
|
11
11
|
"typescript": "5.3.3"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@weborigami/types": "
|
|
14
|
+
"@weborigami/types": "0.0.41"
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
|
-
"test": "node --test",
|
|
17
|
+
"test": "node --test --test-reporter=spec",
|
|
18
18
|
"typecheck": "tsc"
|
|
19
19
|
}
|
|
20
20
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import ObjectTree from "./ObjectTree.js";
|
|
2
|
+
import * as Tree from "./Tree.js";
|
|
3
|
+
import { isPlainObject } from "./utilities.js";
|
|
4
|
+
|
|
5
|
+
export default class DeepObjectTree extends ObjectTree {
|
|
6
|
+
async get(key) {
|
|
7
|
+
let value = await super.get(key);
|
|
8
|
+
|
|
9
|
+
const isPlain =
|
|
10
|
+
value instanceof Array ||
|
|
11
|
+
(isPlainObject(value) && !Tree.isAsyncTree(value));
|
|
12
|
+
if (isPlain) {
|
|
13
|
+
value = Reflect.construct(this.constructor, [value]);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (Tree.isAsyncTree(value) && !value.parent) {
|
|
17
|
+
value.parent = this;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async isKeyForSubtree(key) {
|
|
24
|
+
const value = this.object[key];
|
|
25
|
+
return isPlainObject(value) || Tree.isAsyncTree(value);
|
|
26
|
+
}
|
|
27
|
+
}
|
package/src/FunctionTree.js
CHANGED
|
@@ -23,7 +23,8 @@ export default class FunctionTree {
|
|
|
23
23
|
async get(key) {
|
|
24
24
|
const value =
|
|
25
25
|
this.fn.length <= 1
|
|
26
|
-
? // Function takes no arguments or
|
|
26
|
+
? // Function takes no arguments, one argument, or a variable number of
|
|
27
|
+
// arguments: invoke it.
|
|
27
28
|
await this.fn.call(null, key)
|
|
28
29
|
: // Bind the key to the first parameter. Subsequent get calls will
|
|
29
30
|
// eventually bind all parameters until only one remains. At that point,
|
package/src/MapTree.js
CHANGED
|
@@ -24,10 +24,6 @@ export default class MapTree {
|
|
|
24
24
|
async get(key) {
|
|
25
25
|
let value = this.map.get(key);
|
|
26
26
|
|
|
27
|
-
if (value instanceof Map) {
|
|
28
|
-
value = Reflect.construct(this.constructor, [value]);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
27
|
if (Tree.isAsyncTree(value) && !value.parent) {
|
|
32
28
|
value.parent = this;
|
|
33
29
|
}
|
|
@@ -37,7 +33,7 @@ export default class MapTree {
|
|
|
37
33
|
|
|
38
34
|
async isKeyForSubtree(key) {
|
|
39
35
|
const value = this.map.get(key);
|
|
40
|
-
return
|
|
36
|
+
return Tree.isAsyncTree(value);
|
|
41
37
|
}
|
|
42
38
|
|
|
43
39
|
async keys() {
|
package/src/ObjectTree.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as Tree from "./Tree.js";
|
|
2
|
-
import { getRealmObjectPrototype
|
|
2
|
+
import { getRealmObjectPrototype } from "./utilities.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* A tree defined by a plain object or array.
|
|
@@ -37,13 +37,6 @@ export default class ObjectTree {
|
|
|
37
37
|
|
|
38
38
|
let value = this.object[key];
|
|
39
39
|
|
|
40
|
-
const isPlain =
|
|
41
|
-
value instanceof Array ||
|
|
42
|
-
(isPlainObject(value) && !Tree.isAsyncTree(value));
|
|
43
|
-
if (isPlain) {
|
|
44
|
-
value = Reflect.construct(this.constructor, [value]);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
40
|
if (Tree.isAsyncTree(value) && !value.parent) {
|
|
48
41
|
value.parent = this;
|
|
49
42
|
}
|
|
@@ -53,7 +46,7 @@ export default class ObjectTree {
|
|
|
53
46
|
|
|
54
47
|
async isKeyForSubtree(key) {
|
|
55
48
|
const value = this.object[key];
|
|
56
|
-
return
|
|
49
|
+
return Tree.isAsyncTree(value);
|
|
57
50
|
}
|
|
58
51
|
|
|
59
52
|
/**
|
package/src/SetTree.js
CHANGED
|
@@ -18,10 +18,6 @@ export default class SetTree {
|
|
|
18
18
|
async get(key) {
|
|
19
19
|
let value = this.values[key];
|
|
20
20
|
|
|
21
|
-
if (value instanceof Set) {
|
|
22
|
-
value = Reflect.construct(this.constructor, [value]);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
21
|
if (Tree.isAsyncTree(value) && !value.parent) {
|
|
26
22
|
value.parent = this;
|
|
27
23
|
}
|
|
@@ -31,7 +27,7 @@ export default class SetTree {
|
|
|
31
27
|
|
|
32
28
|
async isKeyForSubtree(key) {
|
|
33
29
|
const value = this.values[key];
|
|
34
|
-
return
|
|
30
|
+
return Tree.isAsyncTree(value);
|
|
35
31
|
}
|
|
36
32
|
|
|
37
33
|
async keys() {
|
package/src/Tree.js
CHANGED
|
@@ -18,6 +18,8 @@ import { castArrayLike, isPlainObject } from "./utilities.js";
|
|
|
18
18
|
* @typedef {import("@weborigami/types").AsyncTree} AsyncTree
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
+
const treeModule = this;
|
|
22
|
+
|
|
21
23
|
/**
|
|
22
24
|
* Apply the key/values pairs from the source tree to the target tree.
|
|
23
25
|
*
|
|
@@ -111,9 +113,12 @@ export function from(obj) {
|
|
|
111
113
|
} else if (obj instanceof Set) {
|
|
112
114
|
return new SetTree(obj);
|
|
113
115
|
} else if (obj && typeof obj === "object" && "unpack" in obj) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
async function AsyncFunction() {} // Sample async function
|
|
117
|
+
return obj.unpack instanceof AsyncFunction.constructor
|
|
118
|
+
? // Async unpack: return a deferred tree.
|
|
119
|
+
new DeferredTree(obj.unpack)
|
|
120
|
+
: // Synchronous unpack: cast the result of unpack() to a tree.
|
|
121
|
+
from(obj.unpack());
|
|
117
122
|
} else if (obj && typeof obj === "object") {
|
|
118
123
|
// An instance of some class.
|
|
119
124
|
return new ObjectTree(obj);
|
|
@@ -328,6 +333,7 @@ export async function traverse(treelike, ...keys) {
|
|
|
328
333
|
* Return the value at the corresponding path of keys. Throw if any interior
|
|
329
334
|
* step of the path doesn't lead to a result.
|
|
330
335
|
*
|
|
336
|
+
* @this {AsyncTree|null|undefined}
|
|
331
337
|
* @param {Treelike} treelike
|
|
332
338
|
* @param {...any} keys
|
|
333
339
|
*/
|
|
@@ -336,11 +342,15 @@ export async function traverseOrThrow(treelike, ...keys) {
|
|
|
336
342
|
/** @type {any} */
|
|
337
343
|
let value = treelike;
|
|
338
344
|
|
|
339
|
-
//
|
|
340
|
-
//
|
|
345
|
+
// If traversal operation was called with a `this` context, use that as the
|
|
346
|
+
// target for function calls.
|
|
347
|
+
const target = this === treeModule ? undefined : this;
|
|
348
|
+
|
|
349
|
+
// Process all the keys.
|
|
341
350
|
const remainingKeys = keys.slice();
|
|
342
351
|
while (remainingKeys.length > 0) {
|
|
343
352
|
if (value === undefined) {
|
|
353
|
+
// Attempted to traverse an undefined value
|
|
344
354
|
const keyStrings = keys.map((key) => String(key));
|
|
345
355
|
throw new TraverseError(
|
|
346
356
|
`Couldn't traverse the path: ${keyStrings.join("/")}`,
|
|
@@ -349,24 +359,40 @@ export async function traverseOrThrow(treelike, ...keys) {
|
|
|
349
359
|
);
|
|
350
360
|
}
|
|
351
361
|
|
|
352
|
-
//
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
// An empty string as the last key is a special case.
|
|
356
|
-
if (key === "" && remainingKeys.length === 0) {
|
|
362
|
+
// Special case: one key left that's an empty string
|
|
363
|
+
if (remainingKeys.length === 1 && remainingKeys[0] === "") {
|
|
357
364
|
// Unpack the value if it defines an `unpack` function, otherwise return
|
|
358
365
|
// the value itself.
|
|
359
|
-
|
|
360
|
-
continue;
|
|
366
|
+
return typeof value.unpack === "function" ? await value.unpack() : value;
|
|
361
367
|
}
|
|
362
368
|
|
|
363
|
-
//
|
|
364
|
-
//
|
|
365
|
-
|
|
369
|
+
// If the value is not a function or async tree already, but can be
|
|
370
|
+
// unpacked, unpack it.
|
|
371
|
+
if (
|
|
372
|
+
!(value instanceof Function) &&
|
|
373
|
+
!isAsyncTree(value) &&
|
|
374
|
+
value.unpack instanceof Function
|
|
375
|
+
) {
|
|
376
|
+
value = await value.unpack();
|
|
377
|
+
}
|
|
366
378
|
|
|
367
|
-
|
|
368
|
-
|
|
379
|
+
if (value instanceof Function) {
|
|
380
|
+
// Value is a function: call it with the remaining keys.
|
|
381
|
+
const fn = value;
|
|
382
|
+
// We'll take as many keys as the function's length, but at least one.
|
|
383
|
+
let fnKeyCount = Math.max(fn.length, 1);
|
|
384
|
+
const args = remainingKeys.splice(0, fnKeyCount);
|
|
385
|
+
value = await fn.call(target, ...args);
|
|
386
|
+
} else {
|
|
387
|
+
// Value is some other treelike object: cast it to a tree.
|
|
388
|
+
const tree = from(value);
|
|
389
|
+
// Get the next key.
|
|
390
|
+
const key = remainingKeys.shift();
|
|
391
|
+
// Get the value for the key.
|
|
392
|
+
value = await tree.get(key);
|
|
393
|
+
}
|
|
369
394
|
}
|
|
395
|
+
|
|
370
396
|
return value;
|
|
371
397
|
}
|
|
372
398
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import DeepObjectTree from "../src/DeepObjectTree.js";
|
|
4
|
+
import * as Tree from "../src/Tree.js";
|
|
5
|
+
|
|
6
|
+
describe("DeepObjectTree", () => {
|
|
7
|
+
test("returns an ObjectTree for value that's a plain sub-object or sub-array", async () => {
|
|
8
|
+
const tree = new DeepObjectTree({
|
|
9
|
+
a: 1,
|
|
10
|
+
object: {
|
|
11
|
+
b: 2,
|
|
12
|
+
},
|
|
13
|
+
array: [3],
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const object = await tree.get("object");
|
|
17
|
+
assert.equal(object instanceof DeepObjectTree, true);
|
|
18
|
+
assert.deepEqual(await Tree.plain(object), { b: 2 });
|
|
19
|
+
|
|
20
|
+
const array = await tree.get("array");
|
|
21
|
+
assert.equal(array instanceof DeepObjectTree, true);
|
|
22
|
+
assert.deepEqual(await Tree.plain(array), [3]);
|
|
23
|
+
});
|
|
24
|
+
});
|
package/test/ObjectTree.test.js
CHANGED
|
@@ -76,28 +76,13 @@ describe("ObjectTree", () => {
|
|
|
76
76
|
assert.equal(await fixture.get("prop"), "Goodbye");
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
-
test("creates an ObjectTree for subtrees", async () => {
|
|
80
|
-
const object = {
|
|
81
|
-
a: 1,
|
|
82
|
-
more: {
|
|
83
|
-
b: 2,
|
|
84
|
-
},
|
|
85
|
-
};
|
|
86
|
-
const fixture = new ObjectTree(object);
|
|
87
|
-
const more = await fixture.get("more");
|
|
88
|
-
assert.equal(more.constructor, ObjectTree);
|
|
89
|
-
const b = await more.get("b");
|
|
90
|
-
assert.equal(b, 2);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
79
|
test("sets parent on subtrees", async () => {
|
|
94
|
-
const
|
|
80
|
+
const fixture = new ObjectTree({
|
|
95
81
|
a: 1,
|
|
96
|
-
more: {
|
|
82
|
+
more: new ObjectTree({
|
|
97
83
|
b: 2,
|
|
98
|
-
},
|
|
99
|
-
};
|
|
100
|
-
const fixture = new ObjectTree(object);
|
|
84
|
+
}),
|
|
85
|
+
});
|
|
101
86
|
const more = await fixture.get("more");
|
|
102
87
|
assert.equal(more.parent, fixture);
|
|
103
88
|
});
|
|
@@ -105,13 +90,13 @@ describe("ObjectTree", () => {
|
|
|
105
90
|
test("isKeyForSubtree() indicates which values are subtrees", async () => {
|
|
106
91
|
const tree = new ObjectTree({
|
|
107
92
|
a1: 1,
|
|
108
|
-
a2: {
|
|
93
|
+
a2: new ObjectTree({
|
|
109
94
|
b1: 2,
|
|
110
|
-
},
|
|
95
|
+
}),
|
|
111
96
|
a3: 3,
|
|
112
|
-
a4: {
|
|
97
|
+
a4: new ObjectTree({
|
|
113
98
|
b2: 4,
|
|
114
|
-
},
|
|
99
|
+
}),
|
|
115
100
|
});
|
|
116
101
|
const keys = Array.from(await tree.keys());
|
|
117
102
|
const subtrees = await Promise.all(
|
|
@@ -120,24 +105,6 @@ describe("ObjectTree", () => {
|
|
|
120
105
|
assert.deepEqual(subtrees, [false, true, false, true]);
|
|
121
106
|
});
|
|
122
107
|
|
|
123
|
-
test("returns an ObjectTree for value that's a plain sub-object or sub-array", async () => {
|
|
124
|
-
const tree = new ObjectTree({
|
|
125
|
-
a: 1,
|
|
126
|
-
object: {
|
|
127
|
-
b: 2,
|
|
128
|
-
},
|
|
129
|
-
array: [3],
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
const object = await tree.get("object");
|
|
133
|
-
assert.equal(object instanceof ObjectTree, true);
|
|
134
|
-
assert.deepEqual(await Tree.plain(object), { b: 2 });
|
|
135
|
-
|
|
136
|
-
const array = await tree.get("array");
|
|
137
|
-
assert.equal(array instanceof ObjectTree, true);
|
|
138
|
-
assert.deepEqual(await Tree.plain(array), [3]);
|
|
139
|
-
});
|
|
140
|
-
|
|
141
108
|
test("returns an async tree value as is", async () => {
|
|
142
109
|
const subtree = {
|
|
143
110
|
async get(key) {},
|
package/test/SetTree.test.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import { describe, test } from "node:test";
|
|
3
|
+
import ObjectTree from "../src/ObjectTree.js";
|
|
3
4
|
import SetTree from "../src/SetTree.js";
|
|
4
5
|
|
|
5
6
|
describe("SetTree", () => {
|
|
@@ -24,7 +25,7 @@ describe("SetTree", () => {
|
|
|
24
25
|
|
|
25
26
|
test("sets parent on subtrees", async () => {
|
|
26
27
|
const set = new Set();
|
|
27
|
-
set.add(new
|
|
28
|
+
set.add(new ObjectTree({}));
|
|
28
29
|
const fixture = new SetTree(set);
|
|
29
30
|
const subtree = await fixture.get(0);
|
|
30
31
|
assert.equal(subtree.parent, fixture);
|
package/test/Tree.test.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import { describe, test } from "node:test";
|
|
3
|
+
import { DeepObjectTree } from "../main.js";
|
|
3
4
|
import MapTree from "../src/MapTree.js";
|
|
4
5
|
import ObjectTree from "../src/ObjectTree.js";
|
|
5
6
|
import * as Tree from "../src/Tree.js";
|
|
6
7
|
|
|
7
8
|
describe("Tree", () => {
|
|
8
9
|
test("assign applies one tree to another", async () => {
|
|
9
|
-
const target = new
|
|
10
|
+
const target = new DeepObjectTree({
|
|
10
11
|
a: 1,
|
|
11
12
|
b: 2,
|
|
12
13
|
more: {
|
|
@@ -14,7 +15,7 @@ describe("Tree", () => {
|
|
|
14
15
|
},
|
|
15
16
|
});
|
|
16
17
|
|
|
17
|
-
const source = {
|
|
18
|
+
const source = new DeepObjectTree({
|
|
18
19
|
a: 4, // Overwrite existing value
|
|
19
20
|
b: undefined, // Delete
|
|
20
21
|
c: 5, // Add
|
|
@@ -26,7 +27,7 @@ describe("Tree", () => {
|
|
|
26
27
|
extra: {
|
|
27
28
|
f: 7,
|
|
28
29
|
},
|
|
29
|
-
};
|
|
30
|
+
});
|
|
30
31
|
|
|
31
32
|
// Apply changes.
|
|
32
33
|
const result = await Tree.assign(target, source);
|
|
@@ -165,7 +166,7 @@ describe("Tree", () => {
|
|
|
165
166
|
});
|
|
166
167
|
|
|
167
168
|
test("isKeyForSubtree() returns true if the key is for a subtree", async () => {
|
|
168
|
-
const tree = new
|
|
169
|
+
const tree = new DeepObjectTree({
|
|
169
170
|
a: 1,
|
|
170
171
|
more: {
|
|
171
172
|
b: 2,
|
|
@@ -176,12 +177,12 @@ describe("Tree", () => {
|
|
|
176
177
|
});
|
|
177
178
|
|
|
178
179
|
test("map() maps values", async () => {
|
|
179
|
-
const tree = {
|
|
180
|
+
const tree = new DeepObjectTree({
|
|
180
181
|
a: "Alice",
|
|
181
182
|
more: {
|
|
182
183
|
b: "Bob",
|
|
183
184
|
},
|
|
184
|
-
};
|
|
185
|
+
});
|
|
185
186
|
const mapped = Tree.map(tree, (value) => value.toUpperCase());
|
|
186
187
|
assert.deepEqual(await Tree.plain(mapped), {
|
|
187
188
|
a: "ALICE",
|
|
@@ -192,14 +193,14 @@ describe("Tree", () => {
|
|
|
192
193
|
});
|
|
193
194
|
|
|
194
195
|
test("mapReduce() can map values and reduce them", async () => {
|
|
195
|
-
const tree = {
|
|
196
|
+
const tree = new DeepObjectTree({
|
|
196
197
|
a: 1,
|
|
197
198
|
b: 2,
|
|
198
199
|
more: {
|
|
199
200
|
c: 3,
|
|
200
201
|
},
|
|
201
202
|
d: 4,
|
|
202
|
-
};
|
|
203
|
+
});
|
|
203
204
|
const reduced = await Tree.mapReduce(
|
|
204
205
|
tree,
|
|
205
206
|
(value) => value,
|
|
@@ -284,6 +285,13 @@ describe("Tree", () => {
|
|
|
284
285
|
);
|
|
285
286
|
});
|
|
286
287
|
|
|
288
|
+
test("traverse() a function with fixed number of arguments", async () => {
|
|
289
|
+
const tree = (a, b) => ({
|
|
290
|
+
c: "Result",
|
|
291
|
+
});
|
|
292
|
+
assert.equal(await Tree.traverse(tree, "a", "b", "c"), "Result");
|
|
293
|
+
});
|
|
294
|
+
|
|
287
295
|
test("traverse() from one tree into another", async () => {
|
|
288
296
|
const tree = new ObjectTree({
|
|
289
297
|
a: {
|
|
@@ -297,15 +305,13 @@ describe("Tree", () => {
|
|
|
297
305
|
});
|
|
298
306
|
|
|
299
307
|
test("traversing a final empty string can unpack the last value", async () => {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
unpackable,
|
|
308
|
-
});
|
|
308
|
+
const tree = {
|
|
309
|
+
unpackable: {
|
|
310
|
+
unpack() {
|
|
311
|
+
return "Content";
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
};
|
|
309
315
|
const result = await Tree.traverse(tree, "unpackable", "");
|
|
310
316
|
assert.equal(result, "Content");
|
|
311
317
|
});
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import { describe, test } from "node:test";
|
|
3
|
+
import DeepObjectTree from "../../src/DeepObjectTree.js";
|
|
3
4
|
import * as Tree from "../../src/Tree.js";
|
|
4
5
|
import mergeDeep from "../../src/operations/mergeDeep.js";
|
|
5
6
|
|
|
6
7
|
describe("mergeDeep", () => {
|
|
7
8
|
test("can merge deep", async () => {
|
|
8
9
|
const fixture = mergeDeep(
|
|
9
|
-
|
|
10
|
+
new DeepObjectTree({
|
|
10
11
|
a: {
|
|
11
12
|
b: 1,
|
|
12
13
|
c: {
|
|
@@ -14,7 +15,7 @@ describe("mergeDeep", () => {
|
|
|
14
15
|
},
|
|
15
16
|
},
|
|
16
17
|
}),
|
|
17
|
-
|
|
18
|
+
new DeepObjectTree({
|
|
18
19
|
a: {
|
|
19
20
|
b: 0, // Will be obscured by `b` above
|
|
20
21
|
c: {
|
|
@@ -12,9 +12,7 @@ describe("groupBy transform", () => {
|
|
|
12
12
|
{ name: "Work Sans", tags: ["Grotesque", "Sans Serif"] },
|
|
13
13
|
];
|
|
14
14
|
const tree = Tree.from(fonts);
|
|
15
|
-
const grouped = await groupBy((value, key, tree) => value.
|
|
16
|
-
tree
|
|
17
|
-
);
|
|
15
|
+
const grouped = await groupBy((value, key, tree) => value.tags)(tree);
|
|
18
16
|
assert.deepEqual(await Tree.plain(grouped), {
|
|
19
17
|
Geometric: [{ name: "Albert Sans", tags: ["Geometric", "Sans Serif"] }],
|
|
20
18
|
Grotesque: [{ name: "Work Sans", tags: ["Grotesque", "Sans Serif"] }],
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import { describe, test } from "node:test";
|
|
3
|
+
import DeepObjectTree from "../../src/DeepObjectTree.js";
|
|
3
4
|
import FunctionTree from "../../src/FunctionTree.js";
|
|
4
5
|
import ObjectTree from "../../src/ObjectTree.js";
|
|
5
6
|
import * as Tree from "../../src/Tree.js";
|
|
@@ -125,7 +126,7 @@ describe("map", () => {
|
|
|
125
126
|
});
|
|
126
127
|
|
|
127
128
|
test("deep maps values", async () => {
|
|
128
|
-
const tree = new
|
|
129
|
+
const tree = new DeepObjectTree({
|
|
129
130
|
a: "letter a",
|
|
130
131
|
more: {
|
|
131
132
|
b: "letter b",
|
|
@@ -145,7 +146,7 @@ describe("map", () => {
|
|
|
145
146
|
});
|
|
146
147
|
|
|
147
148
|
test("deep maps leaf keys", async () => {
|
|
148
|
-
const tree = new
|
|
149
|
+
const tree = new DeepObjectTree({
|
|
149
150
|
a: "letter a",
|
|
150
151
|
more: {
|
|
151
152
|
b: "letter b",
|
|
@@ -166,7 +167,7 @@ describe("map", () => {
|
|
|
166
167
|
});
|
|
167
168
|
|
|
168
169
|
test("deep maps leaf keys and values", async () => {
|
|
169
|
-
const tree = new
|
|
170
|
+
const tree = new DeepObjectTree({
|
|
170
171
|
a: "letter a",
|
|
171
172
|
more: {
|
|
172
173
|
b: "letter b",
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import { describe, test } from "node:test";
|
|
3
|
+
import DeepObjectTree from "../../src/DeepObjectTree.js";
|
|
3
4
|
import * as Tree from "../../src/Tree.js";
|
|
4
5
|
import regExpKeys from "../../src/transforms/regExpKeys.js";
|
|
5
6
|
|
|
6
7
|
describe("regExpKeys", () => {
|
|
7
8
|
test("matches keys using regular expressions", async () => {
|
|
8
9
|
const fixture = await regExpKeys(
|
|
9
|
-
|
|
10
|
+
new DeepObjectTree({
|
|
10
11
|
a: true,
|
|
11
12
|
"b.*": true,
|
|
12
13
|
c: {
|