@weborigami/async-tree 0.6.14 → 0.6.15
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/package.json +1 -1
- package/src/Tree.js +2 -0
- package/src/drivers/SetMap.js +5 -2
- package/src/operations/deflatePaths.js +38 -0
- package/src/operations/inflatePaths.js +27 -0
- package/test/drivers/SetMap.test.js +3 -3
- package/test/operations/deflatePaths.test.js +23 -0
- package/test/operations/inflatePaths.test.js +24 -0
package/package.json
CHANGED
package/src/Tree.js
CHANGED
|
@@ -20,6 +20,7 @@ export { default as deepTake } from "./operations/deepTake.js";
|
|
|
20
20
|
export { default as deepText } from "./operations/deepText.js";
|
|
21
21
|
export { default as deepValues } from "./operations/deepValues.js";
|
|
22
22
|
export { default as deepValuesIterator } from "./operations/deepValuesIterator.js";
|
|
23
|
+
export { default as deflatePaths } from "./operations/deflatePaths.js";
|
|
23
24
|
export { default as delete } from "./operations/delete.js";
|
|
24
25
|
export { default as entries } from "./operations/entries.js";
|
|
25
26
|
export { default as filter } from "./operations/filter.js";
|
|
@@ -32,6 +33,7 @@ export { default as group } from "./operations/group.js";
|
|
|
32
33
|
export { default as groupBy } from "./operations/groupBy.js";
|
|
33
34
|
export { default as has } from "./operations/has.js";
|
|
34
35
|
export { default as indent } from "./operations/indent.js";
|
|
36
|
+
export { default as inflatePaths } from "./operations/inflatePaths.js";
|
|
35
37
|
export { default as inners } from "./operations/inners.js";
|
|
36
38
|
export { default as invokeFunctions } from "./operations/invokeFunctions.js";
|
|
37
39
|
export { default as isAsyncMutableTree } from "./operations/isAsyncMutableTree.js";
|
package/src/drivers/SetMap.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import SyncMap from "./SyncMap.js";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* A
|
|
4
|
+
* A standard `Set` represented as a `Map`. The keys are integer indices; the
|
|
5
|
+
* values are the set's values.
|
|
5
6
|
*/
|
|
6
7
|
export default class SetMap extends SyncMap {
|
|
7
8
|
/**
|
|
8
9
|
* @param {Set} set
|
|
9
10
|
*/
|
|
10
11
|
constructor(set) {
|
|
11
|
-
|
|
12
|
+
// Treat the set as an array-like map
|
|
13
|
+
const entries = Array.from(set).map((value, index) => [index, value]);
|
|
14
|
+
super(entries);
|
|
12
15
|
}
|
|
13
16
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import SyncMap from "../drivers/SyncMap.js";
|
|
2
|
+
import * as trailingSlash from "../trailingSlash.js";
|
|
3
|
+
import * as args from "../utilities/args.js";
|
|
4
|
+
import isMap from "./isMap.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Given a tree, return a flat mapping of string paths to values.
|
|
8
|
+
*
|
|
9
|
+
* If a `basePath` is provided, it will be prepended to all paths in the result.
|
|
10
|
+
*
|
|
11
|
+
* @typedef {import("../../index.ts").Maplike} Maplike
|
|
12
|
+
*
|
|
13
|
+
* @param {Maplike} maplike
|
|
14
|
+
* @param {string} [basePath]
|
|
15
|
+
*/
|
|
16
|
+
export default async function deflatePaths(maplike, basePath = "") {
|
|
17
|
+
const tree = await args.map(maplike, "Tree.deflatePaths", { deep: true });
|
|
18
|
+
const result = new SyncMap();
|
|
19
|
+
for await (let [key, value] of tree) {
|
|
20
|
+
const normalizedKey = trailingSlash.remove(key);
|
|
21
|
+
let path = basePath;
|
|
22
|
+
if (path && !path.endsWith("/")) {
|
|
23
|
+
path += "/";
|
|
24
|
+
}
|
|
25
|
+
path += normalizedKey;
|
|
26
|
+
value = await value;
|
|
27
|
+
if (isMap(value)) {
|
|
28
|
+
const subResult = await deflatePaths(value, path);
|
|
29
|
+
for await (let [subPath, subValue] of subResult) {
|
|
30
|
+
subValue = await subValue;
|
|
31
|
+
result.set(subPath, subValue);
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
result.set(path, value);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import SyncMap from "../drivers/SyncMap.js";
|
|
2
|
+
import * as args from "../utilities/args.js";
|
|
3
|
+
import keysFromPath from "../utilities/keysFromPath.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Given a mapping of string paths to values, return the described tree.
|
|
7
|
+
*/
|
|
8
|
+
export default async function inflatePaths(maplike) {
|
|
9
|
+
const map = await args.map(maplike, "Tree.inflatePaths", { deep: true });
|
|
10
|
+
|
|
11
|
+
const result = new SyncMap();
|
|
12
|
+
for await (const [path, value] of map) {
|
|
13
|
+
const keys = keysFromPath(path);
|
|
14
|
+
setValue(result, keys, value);
|
|
15
|
+
}
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Add the value to the tree at the given path of keys
|
|
20
|
+
function setValue(map, keys, value) {
|
|
21
|
+
let node = map;
|
|
22
|
+
for (const key of keys.slice(0, -1)) {
|
|
23
|
+
// Create a new node if one doesn't exist yet
|
|
24
|
+
node = node.getOrInsertComputed(key, () => new SyncMap());
|
|
25
|
+
}
|
|
26
|
+
node.set(keys[keys.length - 1], value);
|
|
27
|
+
}
|
|
@@ -6,20 +6,20 @@ describe("SetMap", () => {
|
|
|
6
6
|
test("can get the keys of the map", async () => {
|
|
7
7
|
const set = new Set(["a", "b", "c"]);
|
|
8
8
|
const fixture = new SetMap(set);
|
|
9
|
-
assert.deepEqual(Array.from(await fixture.keys()), [
|
|
9
|
+
assert.deepEqual(Array.from(await fixture.keys()), [0, 1, 2]);
|
|
10
10
|
});
|
|
11
11
|
|
|
12
12
|
test("can get the value for a key", async () => {
|
|
13
13
|
const set = new Set(["a", "b", "c"]);
|
|
14
14
|
const fixture = new SetMap(set);
|
|
15
|
-
const a = await fixture.get(
|
|
15
|
+
const a = await fixture.get(0);
|
|
16
16
|
assert.equal(a, "a");
|
|
17
17
|
});
|
|
18
18
|
|
|
19
19
|
test("getting an unsupported key returns undefined", async () => {
|
|
20
20
|
const set = new Set(["a", "b", "c"]);
|
|
21
21
|
const fixture = new SetMap(set);
|
|
22
|
-
assert.equal(await fixture.get(
|
|
22
|
+
assert.equal(await fixture.get(3), undefined);
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
test("getting a null/undefined key throws an exception", async () => {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import deflatePaths from "../../src/operations/deflatePaths.js";
|
|
4
|
+
|
|
5
|
+
describe("deflatePaths", () => {
|
|
6
|
+
test("flattens a tree into a map of string paths to values", async () => {
|
|
7
|
+
const maplike = {
|
|
8
|
+
foo: {
|
|
9
|
+
bar: {
|
|
10
|
+
"baz.json": 123,
|
|
11
|
+
"qux.json": 456,
|
|
12
|
+
},
|
|
13
|
+
"quux.json": 789,
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
const result = await deflatePaths(maplike);
|
|
17
|
+
assert.deepStrictEqual(Object.fromEntries(result), {
|
|
18
|
+
"foo/bar/baz.json": 123,
|
|
19
|
+
"foo/bar/qux.json": 456,
|
|
20
|
+
"foo/quux.json": 789,
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import inflatePaths from "../../src/operations/inflatePaths.js";
|
|
4
|
+
import plain from "../../src/operations/plain.js";
|
|
5
|
+
|
|
6
|
+
describe("inflatePaths", () => {
|
|
7
|
+
test("given a flat mapping of paths to values, returns the described tree", async () => {
|
|
8
|
+
const maplike = {
|
|
9
|
+
"foo/bar/baz.json": 123,
|
|
10
|
+
"foo/bar/qux.json": 456,
|
|
11
|
+
"foo/quux.json": 789,
|
|
12
|
+
};
|
|
13
|
+
const result = await inflatePaths(maplike);
|
|
14
|
+
assert.deepStrictEqual(await plain(result), {
|
|
15
|
+
foo: {
|
|
16
|
+
bar: {
|
|
17
|
+
"baz.json": 123,
|
|
18
|
+
"qux.json": 456,
|
|
19
|
+
},
|
|
20
|
+
"quux.json": 789,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
});
|