@weborigami/async-tree 0.0.38 → 0.0.40
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 +5 -5
- package/src/DeepObjectTree.js +27 -0
- package/src/MapTree.js +1 -5
- package/src/ObjectTree.js +2 -9
- package/src/SetTree.js +1 -5
- package/src/Tree.js +6 -3
- package/src/operations/cache.js +3 -3
- package/src/transforms/groupBy.js +1 -0
- package/src/transforms/map.js +22 -5
- 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 +9 -8
- package/test/operations/mergeDeep.test.js +3 -2
- package/test/transforms/groupBy.test.js +1 -3
- package/test/transforms/map.test.js +37 -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.40",
|
|
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
|
-
"typescript": "5.
|
|
10
|
+
"@types/node": "20.11.7",
|
|
11
|
+
"typescript": "5.3.3"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@weborigami/types": "
|
|
14
|
+
"@weborigami/types": "0.0.40"
|
|
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/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
|
@@ -111,9 +111,12 @@ export function from(obj) {
|
|
|
111
111
|
} else if (obj instanceof Set) {
|
|
112
112
|
return new SetTree(obj);
|
|
113
113
|
} else if (obj && typeof obj === "object" && "unpack" in obj) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
async function AsyncFunction() {} // Sample async function
|
|
115
|
+
return obj.unpack instanceof AsyncFunction.constructor
|
|
116
|
+
? // Async unpack: return a deferred tree.
|
|
117
|
+
new DeferredTree(obj.unpack)
|
|
118
|
+
: // Synchronous unpack: cast the result of unpack() to a tree.
|
|
119
|
+
from(obj.unpack());
|
|
117
120
|
} else if (obj && typeof obj === "object") {
|
|
118
121
|
// An instance of some class.
|
|
119
122
|
return new ObjectTree(obj);
|
package/src/operations/cache.js
CHANGED
|
@@ -32,9 +32,9 @@ export default function treeCache(source, cacheTree, filter) {
|
|
|
32
32
|
// Cache miss or interior node cache hit.
|
|
33
33
|
let value = await source.get(key);
|
|
34
34
|
if (value !== undefined) {
|
|
35
|
-
//
|
|
36
|
-
const filterValue =
|
|
37
|
-
const filterMatch = filterValue !== undefined;
|
|
35
|
+
// If a filter is defined, does the key match the filter?
|
|
36
|
+
const filterValue = await filter?.get(key);
|
|
37
|
+
const filterMatch = !filter || filterValue !== undefined;
|
|
38
38
|
if (filterMatch) {
|
|
39
39
|
if (Tree.isAsyncTree(value)) {
|
|
40
40
|
// Construct merged tree for a tree result.
|
package/src/transforms/map.js
CHANGED
|
@@ -6,25 +6,35 @@ import * as Tree from "../Tree.js";
|
|
|
6
6
|
* @typedef {import("../../index.ts").KeyFn} KeyFn
|
|
7
7
|
* @typedef {import("../../index.ts").ValueKeyFn} ValueKeyFn
|
|
8
8
|
*
|
|
9
|
-
* @param {ValueKeyFn|{ deep?: boolean, description?: string, inverseKeyMap?: KeyFn, keyMap?: KeyFn, valueMap?: ValueKeyFn }} options
|
|
9
|
+
* @param {ValueKeyFn|{ deep?: boolean, description?: string, needsSourceValue?: boolean, inverseKeyMap?: KeyFn, keyMap?: KeyFn, valueMap?: ValueKeyFn }} options
|
|
10
10
|
*/
|
|
11
11
|
export default function createMapTransform(options) {
|
|
12
12
|
let deep;
|
|
13
13
|
let description;
|
|
14
14
|
let inverseKeyMap;
|
|
15
15
|
let keyMap;
|
|
16
|
+
let needsSourceValue;
|
|
16
17
|
let valueMap;
|
|
17
18
|
if (typeof options === "function") {
|
|
18
19
|
// Take the single function argument as the valueMap
|
|
19
20
|
valueMap = options;
|
|
20
21
|
} else {
|
|
21
|
-
deep = options.deep
|
|
22
|
-
description = options.description
|
|
22
|
+
deep = options.deep;
|
|
23
|
+
description = options.description;
|
|
23
24
|
inverseKeyMap = options.inverseKeyMap;
|
|
24
25
|
keyMap = options.keyMap;
|
|
26
|
+
needsSourceValue = options.needsSourceValue;
|
|
25
27
|
valueMap = options.valueMap;
|
|
26
28
|
}
|
|
27
29
|
|
|
30
|
+
deep ??= false;
|
|
31
|
+
description ??= "key/value map";
|
|
32
|
+
// @ts-ignore
|
|
33
|
+
inverseKeyMap ??= valueMap?.inverseKeyMap;
|
|
34
|
+
// @ts-ignore
|
|
35
|
+
keyMap ??= valueMap?.keyMap;
|
|
36
|
+
needsSourceValue ??= true;
|
|
37
|
+
|
|
28
38
|
if ((keyMap && !inverseKeyMap) || (!keyMap && inverseKeyMap)) {
|
|
29
39
|
throw new TypeError(
|
|
30
40
|
`map: You must specify both keyMap and inverseKeyMap, or neither.`
|
|
@@ -58,11 +68,18 @@ export default function createMapTransform(options) {
|
|
|
58
68
|
}
|
|
59
69
|
|
|
60
70
|
// Step 2: Get the source value.
|
|
61
|
-
|
|
71
|
+
let sourceValue;
|
|
72
|
+
if (needsSourceValue) {
|
|
73
|
+
// Normal case: get the value from the source tree.
|
|
74
|
+
sourceValue = await tree.get(sourceKey);
|
|
75
|
+
} else if (deep && (await Tree.isKeyForSubtree(tree, sourceKey))) {
|
|
76
|
+
// Only get the source value if it's a subtree.
|
|
77
|
+
sourceValue = tree;
|
|
78
|
+
}
|
|
62
79
|
|
|
63
80
|
// Step 3: Map the source value to the result value.
|
|
64
81
|
let resultValue;
|
|
65
|
-
if (sourceValue === undefined) {
|
|
82
|
+
if (needsSourceValue && sourceValue === undefined) {
|
|
66
83
|
// No source value means no result value.
|
|
67
84
|
resultValue = undefined;
|
|
68
85
|
} else if (deep && Tree.isAsyncTree(sourceValue)) {
|
|
@@ -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,
|
|
@@ -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,7 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import { describe, test } from "node:test";
|
|
3
|
+
import DeepObjectTree from "../../src/DeepObjectTree.js";
|
|
4
|
+
import FunctionTree from "../../src/FunctionTree.js";
|
|
3
5
|
import ObjectTree from "../../src/ObjectTree.js";
|
|
4
6
|
import * as Tree from "../../src/Tree.js";
|
|
5
7
|
import map from "../../src/transforms/map.js";
|
|
@@ -108,8 +110,23 @@ describe("map", () => {
|
|
|
108
110
|
});
|
|
109
111
|
});
|
|
110
112
|
|
|
111
|
-
test("
|
|
113
|
+
test("valueMap can provide a default keyMap and inverseKeyMap", async () => {
|
|
114
|
+
const uppercase = (s) => s.toUpperCase();
|
|
115
|
+
uppercase.keyMap = (sourceKey) => `_${sourceKey}`;
|
|
116
|
+
uppercase.inverseKeyMap = (resultKey) => resultKey.slice(1);
|
|
112
117
|
const tree = new ObjectTree({
|
|
118
|
+
a: "letter a",
|
|
119
|
+
b: "letter b",
|
|
120
|
+
});
|
|
121
|
+
const mapped = map(uppercase)(tree);
|
|
122
|
+
assert.deepEqual(await Tree.plain(mapped), {
|
|
123
|
+
_a: "LETTER A",
|
|
124
|
+
_b: "LETTER B",
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test("deep maps values", async () => {
|
|
129
|
+
const tree = new DeepObjectTree({
|
|
113
130
|
a: "letter a",
|
|
114
131
|
more: {
|
|
115
132
|
b: "letter b",
|
|
@@ -129,7 +146,7 @@ describe("map", () => {
|
|
|
129
146
|
});
|
|
130
147
|
|
|
131
148
|
test("deep maps leaf keys", async () => {
|
|
132
|
-
const tree = new
|
|
149
|
+
const tree = new DeepObjectTree({
|
|
133
150
|
a: "letter a",
|
|
134
151
|
more: {
|
|
135
152
|
b: "letter b",
|
|
@@ -150,7 +167,7 @@ describe("map", () => {
|
|
|
150
167
|
});
|
|
151
168
|
|
|
152
169
|
test("deep maps leaf keys and values", async () => {
|
|
153
|
-
const tree = new
|
|
170
|
+
const tree = new DeepObjectTree({
|
|
154
171
|
a: "letter a",
|
|
155
172
|
more: {
|
|
156
173
|
b: "letter b",
|
|
@@ -171,4 +188,21 @@ describe("map", () => {
|
|
|
171
188
|
},
|
|
172
189
|
});
|
|
173
190
|
});
|
|
191
|
+
|
|
192
|
+
test("needsSourceValue can be set to false in cases where the value isn't necessary", async () => {
|
|
193
|
+
let flag = false;
|
|
194
|
+
const tree = new FunctionTree(() => {
|
|
195
|
+
flag = true;
|
|
196
|
+
}, ["a", "b", "c"]);
|
|
197
|
+
const mapped = map({
|
|
198
|
+
needsSourceValue: false,
|
|
199
|
+
valueMap: () => "X",
|
|
200
|
+
})(tree);
|
|
201
|
+
assert.deepEqual(await Tree.plain(mapped), {
|
|
202
|
+
a: "X",
|
|
203
|
+
b: "X",
|
|
204
|
+
c: "X",
|
|
205
|
+
});
|
|
206
|
+
assert(!flag);
|
|
207
|
+
});
|
|
174
208
|
});
|
|
@@ -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: {
|