@weborigami/async-tree 0.5.8 → 0.6.1
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/browser.js +1 -1
- package/index.ts +43 -35
- package/main.js +1 -2
- package/package.json +4 -7
- package/shared.js +74 -12
- package/src/Tree.js +11 -2
- package/src/drivers/AsyncMap.js +237 -0
- package/src/drivers/{BrowserFileTree.js → BrowserFileMap.js} +54 -38
- package/src/drivers/{calendarTree.js → CalendarMap.js} +80 -63
- package/src/drivers/ConstantMap.js +28 -0
- package/src/drivers/{ExplorableSiteTree.js → ExplorableSiteMap.js} +7 -7
- package/src/drivers/FileMap.js +238 -0
- package/src/drivers/{FunctionTree.js → FunctionMap.js} +19 -22
- package/src/drivers/ObjectMap.js +151 -0
- package/src/drivers/SetMap.js +13 -0
- package/src/drivers/{SiteTree.js → SiteMap.js} +17 -20
- package/src/drivers/SyncMap.js +260 -0
- package/src/jsonKeys.d.ts +2 -2
- package/src/jsonKeys.js +20 -5
- package/src/operations/addNextPrevious.js +35 -36
- package/src/operations/assign.js +27 -23
- package/src/operations/cache.js +30 -36
- package/src/operations/cachedKeyFunctions.js +1 -1
- package/src/operations/calendar.js +5 -0
- package/src/operations/child.js +35 -0
- package/src/operations/clear.js +13 -12
- package/src/operations/constant.js +5 -0
- package/src/operations/deepEntries.js +23 -0
- package/src/operations/deepMap.js +9 -9
- package/src/operations/deepMerge.js +36 -25
- package/src/operations/deepReverse.js +23 -16
- package/src/operations/deepTake.js +7 -7
- package/src/operations/deepText.js +4 -4
- package/src/operations/deepValues.js +3 -6
- package/src/operations/deepValuesIterator.js +11 -11
- package/src/operations/delete.js +8 -12
- package/src/operations/entries.js +17 -10
- package/src/operations/filter.js +9 -7
- package/src/operations/first.js +12 -10
- package/src/operations/forEach.js +10 -13
- package/src/operations/from.js +30 -39
- package/src/operations/globKeys.js +22 -17
- package/src/operations/group.js +2 -2
- package/src/operations/groupBy.js +24 -22
- package/src/operations/has.js +7 -9
- package/src/operations/indent.js +2 -2
- package/src/operations/inners.js +19 -15
- package/src/operations/invokeFunctions.js +22 -10
- package/src/operations/isAsyncMutableTree.js +5 -12
- package/src/operations/isAsyncTree.js +5 -20
- package/src/operations/isMap.js +39 -0
- package/src/operations/isMaplike.js +34 -0
- package/src/operations/isReadOnlyMap.js +14 -0
- package/src/operations/isTraversable.js +3 -3
- package/src/operations/isTreelike.js +5 -30
- package/src/operations/json.js +4 -12
- package/src/operations/keys.js +17 -8
- package/src/operations/length.js +9 -8
- package/src/operations/map.js +28 -30
- package/src/operations/mapExtension.js +20 -16
- package/src/operations/mapReduce.js +38 -24
- package/src/operations/mask.js +54 -29
- package/src/operations/match.js +13 -9
- package/src/operations/merge.js +43 -35
- package/src/operations/paginate.js +26 -18
- package/src/operations/parent.js +7 -7
- package/src/operations/paths.js +20 -22
- package/src/operations/plain.js +6 -6
- package/src/operations/reduce.js +16 -0
- package/src/operations/regExpKeys.js +21 -12
- package/src/operations/reverse.js +21 -15
- package/src/operations/root.js +6 -5
- package/src/operations/scope.js +31 -26
- package/src/operations/set.js +20 -0
- package/src/operations/shuffle.js +23 -16
- package/src/operations/size.js +13 -0
- package/src/operations/sort.js +55 -40
- package/src/operations/sync.js +14 -0
- package/src/operations/take.js +23 -11
- package/src/operations/text.js +4 -4
- package/src/operations/toFunction.js +7 -7
- package/src/operations/traverse.js +4 -4
- package/src/operations/traverseOrThrow.js +18 -9
- package/src/operations/traversePath.js +2 -2
- package/src/operations/values.js +18 -9
- package/src/operations/withKeys.js +22 -16
- package/src/symbols.js +1 -0
- package/src/utilities/castArraylike.js +24 -13
- package/src/utilities/getMapArgument.js +38 -0
- package/src/utilities/getParent.js +2 -2
- package/src/utilities/isStringlike.js +7 -5
- package/src/utilities/setParent.js +7 -7
- package/src/utilities/toFunction.js +2 -2
- package/src/utilities/toPlainValue.js +21 -19
- package/test/SampleAsyncMap.js +34 -0
- package/test/browser/assert.js +20 -0
- package/test/browser/index.html +53 -21
- package/test/drivers/AsyncMap.test.js +119 -0
- package/test/drivers/{BrowserFileTree.test.js → BrowserFileMap.test.js} +50 -33
- package/test/drivers/{calendarTree.test.js → CalendarMap.test.js} +17 -19
- package/test/drivers/ConstantMap.test.js +15 -0
- package/test/drivers/{ExplorableSiteTree.test.js → ExplorableSiteMap.test.js} +29 -14
- package/test/drivers/FileMap.test.js +156 -0
- package/test/drivers/FunctionMap.test.js +56 -0
- package/test/drivers/ObjectMap.test.js +194 -0
- package/test/drivers/SetMap.test.js +35 -0
- package/test/drivers/{SiteTree.test.js → SiteMap.test.js} +14 -10
- package/test/drivers/SyncMap.test.js +335 -0
- package/test/jsonKeys.test.js +18 -6
- package/test/operations/addNextPrevious.test.js +3 -2
- package/test/operations/assign.test.js +30 -35
- package/test/operations/cache.test.js +17 -12
- package/test/operations/cachedKeyFunctions.test.js +12 -9
- package/test/operations/child.test.js +34 -0
- package/test/operations/clear.test.js +6 -27
- package/test/operations/deepEntries.test.js +32 -0
- package/test/operations/deepMerge.test.js +23 -16
- package/test/operations/deepReverse.test.js +2 -2
- package/test/operations/deepTake.test.js +2 -2
- package/test/operations/deepText.test.js +4 -4
- package/test/operations/deepValuesIterator.test.js +2 -2
- package/test/operations/delete.test.js +2 -2
- package/test/operations/extensionKeyFunctions.test.js +6 -5
- package/test/operations/filter.test.js +3 -3
- package/test/operations/from.test.js +25 -31
- package/test/operations/globKeys.test.js +9 -9
- package/test/operations/groupBy.test.js +6 -5
- package/test/operations/inners.test.js +17 -14
- package/test/operations/invokeFunctions.test.js +2 -2
- package/test/operations/isMap.test.js +15 -0
- package/test/operations/isMaplike.test.js +15 -0
- package/test/operations/json.test.js +2 -2
- package/test/operations/keys.test.js +16 -3
- package/test/operations/map.test.js +40 -30
- package/test/operations/mapExtension.test.js +6 -6
- package/test/operations/mapReduce.test.js +14 -12
- package/test/operations/mask.test.js +16 -3
- package/test/operations/match.test.js +2 -2
- package/test/operations/merge.test.js +20 -14
- package/test/operations/paginate.test.js +5 -5
- package/test/operations/parent.test.js +3 -3
- package/test/operations/paths.test.js +20 -27
- package/test/operations/plain.test.js +8 -8
- package/test/operations/regExpKeys.test.js +22 -18
- package/test/operations/reverse.test.js +4 -3
- package/test/operations/scope.test.js +6 -5
- package/test/operations/set.test.js +11 -0
- package/test/operations/shuffle.test.js +3 -2
- package/test/operations/sort.test.js +7 -10
- package/test/operations/sync.test.js +43 -0
- package/test/operations/take.test.js +2 -2
- package/test/operations/toFunction.test.js +2 -2
- package/test/operations/traverse.test.js +17 -5
- package/test/operations/withKeys.test.js +2 -2
- package/test/utilities/castArrayLike.test.js +53 -0
- package/test/utilities/setParent.test.js +6 -6
- package/test/utilities/toFunction.test.js +2 -2
- package/test/utilities/toPlainValue.test.js +51 -12
- package/src/drivers/DeepMapTree.js +0 -23
- package/src/drivers/DeepObjectTree.js +0 -18
- package/src/drivers/DeferredTree.js +0 -81
- package/src/drivers/FileTree.js +0 -276
- package/src/drivers/MapTree.js +0 -70
- package/src/drivers/ObjectTree.js +0 -158
- package/src/drivers/SetTree.js +0 -34
- package/src/drivers/constantTree.js +0 -19
- package/src/drivers/limitConcurrency.js +0 -63
- package/src/internal.js +0 -16
- package/src/utilities/getTreeArgument.js +0 -43
- package/test/drivers/DeepMapTree.test.js +0 -17
- package/test/drivers/DeepObjectTree.test.js +0 -35
- package/test/drivers/DeferredTree.test.js +0 -22
- package/test/drivers/FileTree.test.js +0 -192
- package/test/drivers/FunctionTree.test.js +0 -46
- package/test/drivers/MapTree.test.js +0 -59
- package/test/drivers/ObjectTree.test.js +0 -163
- package/test/drivers/SetTree.test.js +0 -44
- package/test/drivers/constantTree.test.js +0 -13
- package/test/drivers/limitConcurrency.test.js +0 -41
- package/test/operations/isAsyncMutableTree.test.js +0 -17
- package/test/operations/isAsyncTree.test.js +0 -26
- package/test/operations/isTreelike.test.js +0 -13
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import getMapArgument from "../utilities/getMapArgument.js";
|
|
2
|
+
import isMap from "./isMap.js";
|
|
3
|
+
import isMaplike from "./isMaplike.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Return an iterator that yields all values in a tree, including nested trees.
|
|
7
7
|
*
|
|
8
|
-
* If the `expand` option is true,
|
|
8
|
+
* If the `expand` option is true, maplike values (but not functions) will be
|
|
9
9
|
* expanded into nested trees and their values will be yielded.
|
|
10
10
|
*
|
|
11
|
-
* @param {import("../../index.ts").
|
|
11
|
+
* @param {import("../../index.ts").Maplike} maplike
|
|
12
12
|
* @param {{ expand?: boolean }} [options]
|
|
13
13
|
* @returns {AsyncGenerator<any, void, undefined>}
|
|
14
14
|
*/
|
|
15
15
|
export default async function* deepValuesIterator(
|
|
16
|
-
|
|
16
|
+
maplike,
|
|
17
17
|
options = { expand: false }
|
|
18
18
|
) {
|
|
19
|
-
const tree = await
|
|
19
|
+
const tree = await getMapArgument(maplike, "deepValuesIterator", {
|
|
20
20
|
deep: true,
|
|
21
21
|
});
|
|
22
22
|
|
|
23
|
-
for (const key of
|
|
24
|
-
|
|
23
|
+
for await (const key of tree.keys()) {
|
|
24
|
+
const value = await tree.get(key);
|
|
25
25
|
|
|
26
26
|
// Recurse into child trees, but don't expand functions.
|
|
27
27
|
const recurse =
|
|
28
|
-
|
|
29
|
-
(options.expand && typeof value !== "function" &&
|
|
28
|
+
isMap(value) ||
|
|
29
|
+
(options.expand && typeof value !== "function" && isMaplike(value));
|
|
30
30
|
if (recurse) {
|
|
31
31
|
yield* deepValuesIterator(value, options);
|
|
32
32
|
} else {
|
package/src/operations/delete.js
CHANGED
|
@@ -1,20 +1,16 @@
|
|
|
1
|
-
import has from "./has.js";
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Removes the value for the given key from the specific node of the tree.
|
|
5
3
|
*
|
|
6
|
-
* @typedef {import("
|
|
4
|
+
* @typedef {import("../../index.ts").Maplike} Maplike
|
|
7
5
|
*
|
|
8
|
-
* @param {
|
|
6
|
+
* @param {Maplike} maplike
|
|
9
7
|
* @param {any} key
|
|
10
8
|
*/
|
|
9
|
+
|
|
10
|
+
import getMapArgument from "../utilities/getMapArgument.js";
|
|
11
|
+
|
|
11
12
|
// `delete` is a reserved word in JavaScript, so we use `del` instead.
|
|
12
|
-
export default async function del(
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
await tree.set(key, undefined);
|
|
16
|
-
return true;
|
|
17
|
-
} else {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
13
|
+
export default async function del(maplike, key) {
|
|
14
|
+
const map = await getMapArgument(maplike, "delete");
|
|
15
|
+
return map.delete(key);
|
|
20
16
|
}
|
|
@@ -1,16 +1,23 @@
|
|
|
1
|
-
import
|
|
1
|
+
import getMapArgument from "../utilities/getMapArgument.js";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Returns
|
|
5
|
-
* value]` for each element in the specific node of the tree.
|
|
4
|
+
* Returns an array of `[key, value]` for each entry in the map.
|
|
6
5
|
*
|
|
7
|
-
* @typedef {import("../../index.ts").
|
|
6
|
+
* @typedef {import("../../index.ts").Maplike} Maplike
|
|
8
7
|
*
|
|
9
|
-
* @param {
|
|
8
|
+
* @param {Maplike} maplike
|
|
9
|
+
* @returns {Promise<Array<[any, any]>>}
|
|
10
10
|
*/
|
|
11
|
-
export default async function entries(
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
export default async function entries(maplike) {
|
|
12
|
+
const map = await getMapArgument(maplike, "entries");
|
|
13
|
+
if (map instanceof Map) {
|
|
14
|
+
return Array.from(map.entries());
|
|
15
|
+
} else {
|
|
16
|
+
// AsyncMap
|
|
17
|
+
const result = [];
|
|
18
|
+
for await (const entry of map) {
|
|
19
|
+
result.push(entry);
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
16
23
|
}
|
package/src/operations/filter.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import
|
|
1
|
+
import getMapArgument from "../utilities/getMapArgument.js";
|
|
2
2
|
import map from "./map.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Given a tree an a test function, return a new tree whose keys correspond to
|
|
6
6
|
* the values that pass the test function.
|
|
7
7
|
*
|
|
8
|
-
* @typedef {import("
|
|
9
|
-
* @typedef {import("../../index.ts").
|
|
8
|
+
* @typedef {import("../../index.ts").Maplike} Maplike
|
|
9
|
+
* @typedef {import("../../index.ts").AsyncMap} AsyncMap
|
|
10
10
|
*
|
|
11
|
-
* @param {
|
|
11
|
+
* @param {Maplike} maplike
|
|
12
12
|
* @param {function|any} options
|
|
13
|
-
* @returns {Promise<
|
|
13
|
+
* @returns {Promise<AsyncMap>}
|
|
14
14
|
*/
|
|
15
|
-
export default async function filter(
|
|
15
|
+
export default async function filter(maplike, options) {
|
|
16
16
|
let testFn;
|
|
17
17
|
let deep;
|
|
18
18
|
if (typeof options === "function") {
|
|
@@ -23,10 +23,12 @@ export default async function filter(treelike, options) {
|
|
|
23
23
|
deep = options.deep ?? false;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
const tree = await
|
|
26
|
+
const tree = await getMapArgument(maplike, "filter", { deep });
|
|
27
27
|
return map(tree, {
|
|
28
28
|
deep,
|
|
29
29
|
|
|
30
|
+
description: "filter",
|
|
31
|
+
|
|
30
32
|
// Assume source key is the same as result key
|
|
31
33
|
inverseKey: async (resultKey) => resultKey,
|
|
32
34
|
|
package/src/operations/first.js
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
import
|
|
1
|
+
import getMapArgument from "../utilities/getMapArgument.js";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Return the first value in the tree.
|
|
5
5
|
*
|
|
6
|
-
* @typedef {import("../../index.ts").
|
|
6
|
+
* @typedef {import("../../index.ts").Maplike} Maplike
|
|
7
7
|
*
|
|
8
|
-
* @param {
|
|
8
|
+
* @param {Maplike} maplike
|
|
9
9
|
*/
|
|
10
|
-
export default async function first(
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
export default async function first(maplike) {
|
|
11
|
+
const map = await getMapArgument(maplike, "first");
|
|
12
|
+
let firstKey;
|
|
13
|
+
for await (const key of map.keys()) {
|
|
14
|
+
// Just needed to get first key
|
|
15
|
+
firstKey = key;
|
|
16
|
+
break;
|
|
16
17
|
}
|
|
17
|
-
|
|
18
|
+
const value = firstKey ? await map.get(firstKey) : undefined;
|
|
19
|
+
return value;
|
|
18
20
|
}
|
|
@@ -1,20 +1,17 @@
|
|
|
1
|
-
import
|
|
1
|
+
import getMapArgument from "../utilities/getMapArgument.js";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Calls callbackFn once for each key-value pair present in the
|
|
5
|
-
* the tree.
|
|
4
|
+
* Calls callbackFn once for each key-value pair present in the map.
|
|
6
5
|
*
|
|
7
|
-
* @typedef {import("../../index.ts").
|
|
6
|
+
* @typedef {import("../../index.ts").Maplike} Maplike
|
|
8
7
|
*
|
|
9
|
-
* @param {
|
|
8
|
+
* @param {Maplike} maplike
|
|
10
9
|
* @param {Function} callbackFn
|
|
11
10
|
*/
|
|
12
|
-
export default async function forEach(
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
});
|
|
19
|
-
await Promise.all(promises);
|
|
11
|
+
export default async function forEach(maplike, callbackFn) {
|
|
12
|
+
const map = await getMapArgument(maplike, "forEach");
|
|
13
|
+
for await (const key of map.keys()) {
|
|
14
|
+
const value = await map.get(key);
|
|
15
|
+
await callbackFn(value, key, map);
|
|
16
|
+
}
|
|
20
17
|
}
|
package/src/operations/from.js
CHANGED
|
@@ -1,33 +1,30 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import ObjectTree from "../drivers/ObjectTree.js";
|
|
6
|
-
import SetTree from "../drivers/SetTree.js";
|
|
1
|
+
import AsyncMap from "../drivers/AsyncMap.js";
|
|
2
|
+
import FunctionMap from "../drivers/FunctionMap.js";
|
|
3
|
+
import ObjectMap from "../drivers/ObjectMap.js";
|
|
4
|
+
import SetMap from "../drivers/SetMap.js";
|
|
7
5
|
import * as symbols from "../symbols.js";
|
|
8
6
|
import box from "../utilities/box.js";
|
|
9
7
|
import isPlainObject from "../utilities/isPlainObject.js";
|
|
10
|
-
import
|
|
11
|
-
import
|
|
8
|
+
import setParent from "../utilities/setParent.js";
|
|
9
|
+
import isMap from "./isMap.js";
|
|
12
10
|
|
|
13
11
|
/**
|
|
14
|
-
* Attempts to cast the indicated object to
|
|
12
|
+
* Attempts to cast the indicated object to a map.
|
|
15
13
|
*
|
|
16
|
-
* If the object is a plain object, it will be converted to an
|
|
14
|
+
* If the object is a plain object, it will be converted to an ObjectMap. The
|
|
17
15
|
* optional `deep` option can be set to `true` to convert a plain object to a
|
|
18
|
-
*
|
|
16
|
+
* deep ObjectMap. The optional `parent` parameter will be used as the default
|
|
19
17
|
* parent of the new tree.
|
|
20
18
|
*
|
|
21
|
-
* @typedef {import("../../index.ts").
|
|
22
|
-
* @typedef {import("@weborigami/types").AsyncTree} AsyncTree
|
|
19
|
+
* @typedef {import("../../index.ts").Maplike} Maplike
|
|
23
20
|
*
|
|
24
|
-
* @param {
|
|
25
|
-
* @param {{ deep?: boolean, parent?:
|
|
26
|
-
* @returns {
|
|
21
|
+
* @param {Maplike | Object} object
|
|
22
|
+
* @param {{ deep?: boolean, parent?: Map|AsyncMap|null }} [options]
|
|
23
|
+
* @returns {Map|AsyncMap}
|
|
27
24
|
*/
|
|
28
25
|
export default function from(object, options = {}) {
|
|
29
26
|
const deep = options.deep ?? object[symbols.deep];
|
|
30
|
-
let
|
|
27
|
+
let map;
|
|
31
28
|
if (object == null) {
|
|
32
29
|
throw new TypeError("The tree argument wasn't defined.");
|
|
33
30
|
} else if (object instanceof Promise) {
|
|
@@ -35,29 +32,22 @@ export default function from(object, options = {}) {
|
|
|
35
32
|
throw new TypeError(
|
|
36
33
|
"The tree argument was a Promise. Did you mean to use await?"
|
|
37
34
|
);
|
|
38
|
-
} else if (
|
|
39
|
-
//
|
|
40
|
-
// @ts-ignore
|
|
35
|
+
} else if (isMap(object)) {
|
|
36
|
+
// Already a map
|
|
41
37
|
return object;
|
|
42
38
|
} else if (typeof object === "function") {
|
|
43
|
-
|
|
44
|
-
} else if (object instanceof Map) {
|
|
45
|
-
tree = new MapTree(object);
|
|
39
|
+
map = new FunctionMap(object);
|
|
46
40
|
} else if (object instanceof Set) {
|
|
47
|
-
|
|
41
|
+
map = new SetMap(object);
|
|
48
42
|
} else if (isPlainObject(object) || object instanceof Array) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
? // Async unpack: return a deferred tree.
|
|
55
|
-
new DeferredTree(object.unpack, { deep })
|
|
56
|
-
: // Synchronous unpack: cast the result of unpack() to a tree.
|
|
57
|
-
from(object.unpack());
|
|
43
|
+
map = new ObjectMap(object, { deep });
|
|
44
|
+
// @ts-ignore
|
|
45
|
+
} else if (globalThis.Iterator && object instanceof Iterator) {
|
|
46
|
+
const array = Array.from(object);
|
|
47
|
+
map = new ObjectMap(array, { deep });
|
|
58
48
|
} else if (object && typeof object === "object") {
|
|
59
49
|
// An instance of some class.
|
|
60
|
-
|
|
50
|
+
map = new ObjectMap(object, { deep });
|
|
61
51
|
} else if (
|
|
62
52
|
typeof object === "string" ||
|
|
63
53
|
typeof object === "number" ||
|
|
@@ -65,13 +55,14 @@ export default function from(object, options = {}) {
|
|
|
65
55
|
) {
|
|
66
56
|
// A primitive value; box it into an object and construct a tree.
|
|
67
57
|
const boxed = box(object);
|
|
68
|
-
|
|
58
|
+
map = new ObjectMap(boxed);
|
|
69
59
|
} else {
|
|
70
|
-
throw new TypeError("Couldn't convert argument to
|
|
60
|
+
throw new TypeError("Couldn't convert argument to a map");
|
|
71
61
|
}
|
|
72
62
|
|
|
73
|
-
if (
|
|
74
|
-
|
|
63
|
+
if (options.parent) {
|
|
64
|
+
setParent(map, options.parent);
|
|
75
65
|
}
|
|
76
|
-
|
|
66
|
+
|
|
67
|
+
return map;
|
|
77
68
|
}
|
|
@@ -1,31 +1,36 @@
|
|
|
1
|
-
import
|
|
1
|
+
import AsyncMap from "../drivers/AsyncMap.js";
|
|
2
|
+
import ObjectMap from "../drivers/ObjectMap.js";
|
|
2
3
|
import * as trailingSlash from "../trailingSlash.js";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
4
|
+
import getMapArgument from "../utilities/getMapArgument.js";
|
|
5
|
+
import isMap from "./isMap.js";
|
|
5
6
|
import merge from "./merge.js";
|
|
6
7
|
|
|
7
8
|
const globstar = "**";
|
|
8
9
|
const globstarSlash = `${globstar}/`;
|
|
9
10
|
|
|
10
|
-
export default async function globKeys(
|
|
11
|
-
const
|
|
12
|
-
return {
|
|
11
|
+
export default async function globKeys(maplike) {
|
|
12
|
+
const source = await getMapArgument(maplike, "globKeys", { deep: true });
|
|
13
|
+
return Object.assign(new AsyncMap(), {
|
|
13
14
|
async get(key) {
|
|
14
15
|
if (typeof key !== "string") {
|
|
15
16
|
return undefined;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
let value = await matchGlobs(
|
|
19
|
-
if (
|
|
19
|
+
let value = await matchGlobs(source, key);
|
|
20
|
+
if (isMap(value)) {
|
|
20
21
|
value = globKeys(value);
|
|
21
22
|
}
|
|
22
23
|
return value;
|
|
23
24
|
},
|
|
24
25
|
|
|
25
|
-
async keys() {
|
|
26
|
-
|
|
26
|
+
async *keys() {
|
|
27
|
+
for await (const key of source.keys()) {
|
|
28
|
+
yield key;
|
|
29
|
+
}
|
|
27
30
|
},
|
|
28
|
-
|
|
31
|
+
|
|
32
|
+
trailingSlashKeys: /** @type {any} */ (source).trailingSlashKeys,
|
|
33
|
+
});
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
// Convert the glob to a regular expression
|
|
@@ -45,19 +50,19 @@ async function matchGlobs(globs, key) {
|
|
|
45
50
|
|
|
46
51
|
// Collect all matches
|
|
47
52
|
let matches = [];
|
|
48
|
-
for (let glob of
|
|
49
|
-
if (glob === globstarSlash) {
|
|
53
|
+
for await (let glob of globs.keys()) {
|
|
54
|
+
if (glob === globstar || glob === globstarSlash) {
|
|
50
55
|
// Remember for later
|
|
51
56
|
globstarGlobs = await globs.get(glob);
|
|
52
57
|
if (trailingSlash.has(key)) {
|
|
53
58
|
// A key for a subtree matches the globstar
|
|
54
|
-
matches.push(new
|
|
59
|
+
matches.push(new ObjectMap({ [globstar]: globstarGlobs }));
|
|
55
60
|
}
|
|
56
61
|
} else if (matchGlob(glob, key)) {
|
|
57
62
|
// Text matches glob, get value
|
|
58
63
|
const globValue = await globs.get(glob);
|
|
59
64
|
if (globValue !== undefined) {
|
|
60
|
-
if (!
|
|
65
|
+
if (!isMap(globValue)) {
|
|
61
66
|
// Found a non-tree match, return immediately
|
|
62
67
|
return globValue;
|
|
63
68
|
}
|
|
@@ -75,12 +80,12 @@ async function matchGlobs(globs, key) {
|
|
|
75
80
|
} else {
|
|
76
81
|
// Try globstar
|
|
77
82
|
const globstarValue = await matchGlobs(globstarGlobs, key);
|
|
78
|
-
if (!
|
|
83
|
+
if (!isMap(globstarValue)) {
|
|
79
84
|
// Found a non-tree match, return immediately
|
|
80
85
|
return globstarValue;
|
|
81
86
|
} else if (trailingSlash.has(key)) {
|
|
82
87
|
// No match but key is for subtree, return globstar tree
|
|
83
|
-
return new
|
|
88
|
+
return new ObjectMap({ [globstar]: globstarGlobs });
|
|
84
89
|
}
|
|
85
90
|
}
|
|
86
91
|
}
|
package/src/operations/group.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import groupBy from "./groupBy.js";
|
|
2
2
|
|
|
3
|
-
export default async function group(
|
|
3
|
+
export default async function group(maplike, groupKeyFn) {
|
|
4
4
|
console.warn("Tree.group() is deprecated. Use Tree.groupBy() instead.");
|
|
5
|
-
return groupBy(
|
|
5
|
+
return groupBy(maplike, groupKeyFn);
|
|
6
6
|
}
|
|
@@ -1,51 +1,53 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
1
|
+
import SyncMap from "../drivers/SyncMap.js";
|
|
2
|
+
import getMapArgument from "../utilities/getMapArgument.js";
|
|
3
|
+
import entries from "./entries.js";
|
|
4
|
+
import isMaplike from "./isMaplike.js";
|
|
5
5
|
import values from "./values.js";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Given a function that returns a grouping key for a value, returns a transform
|
|
9
9
|
* that applies that grouping function to a tree.
|
|
10
10
|
*
|
|
11
|
-
* @param {import("../../index.ts").
|
|
11
|
+
* @param {import("../../index.ts").Maplike} maplike
|
|
12
12
|
* @param {import("../../index.ts").ValueKeyFn} groupKeyFn
|
|
13
13
|
*/
|
|
14
|
-
export default async function groupBy(
|
|
15
|
-
const
|
|
14
|
+
export default async function groupBy(maplike, groupKeyFn) {
|
|
15
|
+
const source = await getMapArgument(maplike, "groupBy");
|
|
16
16
|
|
|
17
|
-
const
|
|
17
|
+
const result = new SyncMap();
|
|
18
|
+
const sourceEntries = await entries(source);
|
|
18
19
|
|
|
19
20
|
// Are all the keys integers?
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
for (const key of await tree.keys()) {
|
|
24
|
-
const value = await tree.get(key);
|
|
21
|
+
const integerKeys = sourceEntries.every(
|
|
22
|
+
([key]) => !Number.isNaN(parseInt(key))
|
|
23
|
+
);
|
|
25
24
|
|
|
25
|
+
for (const [key, value] of sourceEntries) {
|
|
26
26
|
// Get the groups for this value.
|
|
27
|
-
let groups = await groupKeyFn(value, key,
|
|
27
|
+
let groups = await groupKeyFn(value, key, source);
|
|
28
28
|
if (!groups) {
|
|
29
29
|
continue;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
if (!
|
|
32
|
+
if (!isMaplike(groups)) {
|
|
33
33
|
// A single value was returned
|
|
34
34
|
groups = [groups];
|
|
35
35
|
}
|
|
36
|
-
groups = from(groups);
|
|
37
36
|
|
|
38
37
|
// Add the value to each group.
|
|
39
38
|
for (const group of await values(groups)) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
let grouped = await result.get(group);
|
|
40
|
+
if (!grouped) {
|
|
41
|
+
grouped = integerKeys ? [] : new SyncMap();
|
|
42
|
+
result.set(group, grouped);
|
|
43
|
+
}
|
|
44
|
+
if (integerKeys) {
|
|
45
|
+
grouped.push(value);
|
|
43
46
|
} else {
|
|
44
|
-
|
|
45
|
-
result[group][key] = value;
|
|
47
|
+
grouped.set(key, value);
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
51
|
|
|
50
|
-
return
|
|
52
|
+
return result;
|
|
51
53
|
}
|
package/src/operations/has.js
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
import
|
|
1
|
+
import getMapArgument from "../utilities/getMapArgument.js";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Returns
|
|
5
|
-
* value for the given `key`.
|
|
4
|
+
* Returns true if the map has the given key, false otherwise.
|
|
6
5
|
*
|
|
7
|
-
* @typedef {import("../../index.ts").
|
|
6
|
+
* @typedef {import("../../index.ts").Maplike} Maplike
|
|
8
7
|
*
|
|
9
|
-
* @param {
|
|
8
|
+
* @param {Maplike} maplike
|
|
10
9
|
* @param {any} key
|
|
11
10
|
*/
|
|
12
|
-
export default async function has(
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
return value !== undefined;
|
|
11
|
+
export default async function has(maplike, key) {
|
|
12
|
+
const map = await getMapArgument(maplike, "has");
|
|
13
|
+
return map.has(key);
|
|
16
14
|
}
|
package/src/operations/indent.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import toString from "../utilities/toString.js";
|
|
2
2
|
import deepText from "./deepText.js";
|
|
3
|
-
import
|
|
3
|
+
import isMaplike from "./isMaplike.js";
|
|
4
4
|
|
|
5
5
|
const lastLineWhitespaceRegex = /\n(?<indent>[ \t]*)$/;
|
|
6
6
|
|
|
@@ -21,7 +21,7 @@ export default async function indent(strings, ...values) {
|
|
|
21
21
|
}
|
|
22
22
|
const { blockIndentations, strings: modifiedStrings } = modified;
|
|
23
23
|
const valueTexts = await Promise.all(
|
|
24
|
-
values.map((value) => (
|
|
24
|
+
values.map((value) => (isMaplike(value) ? deepText(value) : value))
|
|
25
25
|
);
|
|
26
26
|
return joinBlocks(modifiedStrings, valueTexts, blockIndentations);
|
|
27
27
|
}
|
package/src/operations/inners.js
CHANGED
|
@@ -1,29 +1,33 @@
|
|
|
1
|
+
import AsyncMap from "../drivers/AsyncMap.js";
|
|
1
2
|
import * as trailingSlash from "../trailingSlash.js";
|
|
2
|
-
import
|
|
3
|
-
import
|
|
3
|
+
import getMapArgument from "../utilities/getMapArgument.js";
|
|
4
|
+
import isMap from "./isMap.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Return the interior nodes of the tree. This relies on subtree keys having
|
|
7
8
|
* trailing slashes.
|
|
8
9
|
*
|
|
9
|
-
* @typedef
|
|
10
|
-
* @typedef {import("../../index.ts").Treelike} Treelike
|
|
10
|
+
* @typedef {import("../../index.ts").Maplike} Maplike
|
|
11
11
|
*
|
|
12
|
-
* @param {
|
|
12
|
+
* @param {Maplike} maplike
|
|
13
13
|
*/
|
|
14
|
-
export default async function inners(
|
|
15
|
-
const
|
|
14
|
+
export default async function inners(maplike) {
|
|
15
|
+
const source = await getMapArgument(maplike, "inners");
|
|
16
16
|
|
|
17
|
-
return {
|
|
17
|
+
return Object.assign(new AsyncMap(), {
|
|
18
18
|
async get(key) {
|
|
19
|
-
const value = await
|
|
20
|
-
return
|
|
19
|
+
const value = await source.get(key);
|
|
20
|
+
return isMap(value) ? inners(value) : undefined;
|
|
21
21
|
},
|
|
22
22
|
|
|
23
|
-
async keys() {
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
async *keys() {
|
|
24
|
+
for await (const key of source.keys()) {
|
|
25
|
+
if (trailingSlash.has(key)) {
|
|
26
|
+
yield key;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
27
29
|
},
|
|
28
|
-
|
|
30
|
+
|
|
31
|
+
trailingSlashKeys: /** @type {any} */ (source).trailingSlashKeys,
|
|
32
|
+
});
|
|
29
33
|
}
|
|
@@ -1,21 +1,33 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import AsyncMap from "../drivers/AsyncMap.js";
|
|
2
|
+
import getMapArgument from "../utilities/getMapArgument.js";
|
|
3
|
+
import isMap from "./isMap.js";
|
|
4
|
+
|
|
5
|
+
export default async function invokeFunctions(maplike) {
|
|
6
|
+
const source = await getMapArgument(maplike, "invokeFunctions", {
|
|
7
|
+
deep: true,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
return Object.assign(new AsyncMap(), {
|
|
11
|
+
description: "invokeFunctions",
|
|
3
12
|
|
|
4
|
-
export default async function invokeFunctions(treelike) {
|
|
5
|
-
const tree = from(treelike);
|
|
6
|
-
return {
|
|
7
13
|
async get(key) {
|
|
8
|
-
let value = await
|
|
14
|
+
let value = await source.get(key);
|
|
9
15
|
if (typeof value === "function") {
|
|
10
16
|
value = value();
|
|
11
|
-
} else if (
|
|
17
|
+
} else if (isMap(value)) {
|
|
12
18
|
value = invokeFunctions(value);
|
|
13
19
|
}
|
|
14
20
|
return value;
|
|
15
21
|
},
|
|
16
22
|
|
|
17
|
-
async keys() {
|
|
18
|
-
|
|
23
|
+
async *keys() {
|
|
24
|
+
for await (const key of source.keys()) {
|
|
25
|
+
yield key;
|
|
26
|
+
}
|
|
19
27
|
},
|
|
20
|
-
|
|
28
|
+
|
|
29
|
+
source: source,
|
|
30
|
+
|
|
31
|
+
trailingSlashKeys: /** @type {any} */ (source).trailingSlashKeys,
|
|
32
|
+
});
|
|
21
33
|
}
|
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import isReadOnlyMap from "./isReadOnlyMap.js";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* @typedef {import("@weborigami/types").AsyncMutableTree} AsyncMutableTree
|
|
7
|
-
*
|
|
8
|
-
* @param {any} obj
|
|
9
|
-
* @returns {obj is AsyncMutableTree}
|
|
10
|
-
*/
|
|
11
|
-
export default function isAsyncMutableTree(obj) {
|
|
12
|
-
return (
|
|
13
|
-
isAsyncTree(obj) && typeof (/** @type {any} */ (obj).set) === "function"
|
|
3
|
+
export default function isAsyncMutableTree(treelike) {
|
|
4
|
+
console.warn(
|
|
5
|
+
"Tree.isAsyncMutableTree() is deprecated, use Tree.isReadOnlyMap() instead, which returns the inverse."
|
|
14
6
|
);
|
|
7
|
+
return !isReadOnlyMap(treelike);
|
|
15
8
|
}
|