@weborigami/async-tree 0.5.7 → 0.6.0
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 +31 -35
- package/main.js +1 -2
- package/package.json +4 -7
- package/shared.js +77 -12
- package/src/Tree.js +8 -2
- package/src/drivers/AsyncMap.js +210 -0
- package/src/drivers/{BrowserFileTree.js → BrowserFileMap.js} +36 -27
- package/src/drivers/{calendarTree.js → CalendarMap.js} +81 -62
- package/src/drivers/ConstantMap.js +30 -0
- package/src/drivers/DeepObjectMap.js +27 -0
- package/src/drivers/{ExplorableSiteTree.js → ExplorableSiteMap.js} +7 -7
- package/src/drivers/FileMap.js +245 -0
- package/src/drivers/{FunctionTree.js → FunctionMap.js} +19 -22
- package/src/drivers/ObjectMap.js +139 -0
- package/src/drivers/SetMap.js +13 -0
- package/src/drivers/{SiteTree.js → SiteMap.js} +16 -17
- package/src/drivers/SyncMap.js +245 -0
- package/src/jsonKeys.d.ts +2 -2
- package/src/jsonKeys.js +6 -5
- package/src/operations/addNextPrevious.js +35 -36
- package/src/operations/assign.js +30 -21
- package/src/operations/cache.js +29 -35
- package/src/operations/cachedKeyFunctions.js +1 -1
- package/src/operations/calendar.js +5 -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 +31 -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 +27 -30
- package/src/operations/mapExtension.js +20 -16
- package/src/operations/mapReduce.js +22 -17
- package/src/operations/mask.js +31 -22
- 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 +8 -8
- package/src/operations/plain.js +6 -6
- 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/shuffle.js +23 -16
- package/src/operations/size.js +13 -0
- package/src/operations/sort.js +55 -40
- package/src/operations/sync.js +21 -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 +13 -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 +10 -2
- 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 +22 -18
- package/test/SampleAsyncMap.js +34 -0
- package/test/browser/assert.js +20 -0
- package/test/browser/index.html +54 -21
- package/test/drivers/AsyncMap.test.js +119 -0
- package/test/drivers/{BrowserFileTree.test.js → BrowserFileMap.test.js} +42 -23
- package/test/drivers/{calendarTree.test.js → CalendarMap.test.js} +17 -19
- package/test/drivers/ConstantMap.test.js +15 -0
- package/test/drivers/DeepObjectMap.test.js +36 -0
- package/test/drivers/{ExplorableSiteTree.test.js → ExplorableSiteMap.test.js} +29 -14
- package/test/drivers/FileMap.test.js +185 -0
- package/test/drivers/FunctionMap.test.js +56 -0
- package/test/drivers/ObjectMap.test.js +166 -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 +321 -0
- package/test/jsonKeys.test.js +2 -2
- package/test/operations/addNextPrevious.test.js +3 -2
- package/test/operations/assign.test.js +30 -35
- package/test/operations/cache.test.js +8 -6
- package/test/operations/cachedKeyFunctions.test.js +6 -5
- package/test/operations/clear.test.js +6 -27
- package/test/operations/deepEntries.test.js +32 -0
- package/test/operations/deepMerge.test.js +6 -5
- 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 +23 -31
- package/test/operations/globKeys.test.js +9 -9
- package/test/operations/groupBy.test.js +6 -5
- package/test/operations/inners.test.js +4 -4
- 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 +20 -18
- package/test/operations/mapExtension.test.js +6 -6
- package/test/operations/mapReduce.test.js +2 -2
- package/test/operations/mask.test.js +4 -3
- package/test/operations/match.test.js +2 -2
- package/test/operations/merge.test.js +15 -11
- package/test/operations/paginate.test.js +5 -5
- package/test/operations/parent.test.js +3 -3
- package/test/operations/paths.test.js +6 -6
- package/test/operations/plain.test.js +8 -8
- package/test/operations/regExpKeys.test.js +12 -11
- package/test/operations/reverse.test.js +4 -3
- package/test/operations/scope.test.js +6 -5
- 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 +4 -5
- package/test/operations/withKeys.test.js +2 -2
- 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,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,31 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import SetTree from "../drivers/SetTree.js";
|
|
1
|
+
import AsyncMap from "../drivers/AsyncMap.js";
|
|
2
|
+
import DeepObjectMap from "../drivers/DeepObjectMap.js";
|
|
3
|
+
import FunctionMap from "../drivers/FunctionMap.js";
|
|
4
|
+
import ObjectMap from "../drivers/ObjectMap.js";
|
|
5
|
+
import SetMap from "../drivers/SetMap.js";
|
|
7
6
|
import * as symbols from "../symbols.js";
|
|
8
7
|
import box from "../utilities/box.js";
|
|
9
8
|
import isPlainObject from "../utilities/isPlainObject.js";
|
|
10
|
-
import
|
|
11
|
-
import
|
|
9
|
+
import setParent from "../utilities/setParent.js";
|
|
10
|
+
import isMap from "./isMap.js";
|
|
12
11
|
|
|
13
12
|
/**
|
|
14
|
-
* Attempts to cast the indicated object to
|
|
13
|
+
* Attempts to cast the indicated object to a map.
|
|
15
14
|
*
|
|
16
|
-
* If the object is a plain object, it will be converted to an
|
|
15
|
+
* If the object is a plain object, it will be converted to an ObjectMap. The
|
|
17
16
|
* optional `deep` option can be set to `true` to convert a plain object to a
|
|
18
|
-
*
|
|
17
|
+
* DeepObjectMap. The optional `parent` parameter will be used as the default
|
|
19
18
|
* parent of the new tree.
|
|
20
19
|
*
|
|
21
|
-
* @typedef {import("../../index.ts").
|
|
22
|
-
* @typedef {import("@weborigami/types").AsyncTree} AsyncTree
|
|
20
|
+
* @typedef {import("../../index.ts").Maplike} Maplike
|
|
23
21
|
*
|
|
24
|
-
* @param {
|
|
25
|
-
* @param {{ deep?: boolean, parent?:
|
|
26
|
-
* @returns {
|
|
22
|
+
* @param {Maplike | Object} object
|
|
23
|
+
* @param {{ deep?: boolean, parent?: Map|AsyncMap|null }} [options]
|
|
24
|
+
* @returns {Map|AsyncMap}
|
|
27
25
|
*/
|
|
28
26
|
export default function from(object, options = {}) {
|
|
29
27
|
const deep = options.deep ?? object[symbols.deep];
|
|
30
|
-
let
|
|
28
|
+
let map;
|
|
31
29
|
if (object == null) {
|
|
32
30
|
throw new TypeError("The tree argument wasn't defined.");
|
|
33
31
|
} else if (object instanceof Promise) {
|
|
@@ -35,29 +33,22 @@ export default function from(object, options = {}) {
|
|
|
35
33
|
throw new TypeError(
|
|
36
34
|
"The tree argument was a Promise. Did you mean to use await?"
|
|
37
35
|
);
|
|
38
|
-
} else if (
|
|
39
|
-
//
|
|
40
|
-
// @ts-ignore
|
|
36
|
+
} else if (isMap(object)) {
|
|
37
|
+
// Already a map
|
|
41
38
|
return object;
|
|
42
39
|
} else if (typeof object === "function") {
|
|
43
|
-
|
|
44
|
-
} else if (object instanceof Map) {
|
|
45
|
-
tree = new MapTree(object);
|
|
40
|
+
map = new FunctionMap(object);
|
|
46
41
|
} else if (object instanceof Set) {
|
|
47
|
-
|
|
42
|
+
map = new SetMap(object);
|
|
48
43
|
} 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());
|
|
44
|
+
map = deep ? new DeepObjectMap(object) : new ObjectMap(object);
|
|
45
|
+
// @ts-ignore
|
|
46
|
+
} else if (object instanceof Iterator) {
|
|
47
|
+
const array = Array.from(object);
|
|
48
|
+
map = new ObjectMap(array);
|
|
58
49
|
} else if (object && typeof object === "object") {
|
|
59
50
|
// An instance of some class.
|
|
60
|
-
|
|
51
|
+
map = new ObjectMap(object);
|
|
61
52
|
} else if (
|
|
62
53
|
typeof object === "string" ||
|
|
63
54
|
typeof object === "number" ||
|
|
@@ -65,13 +56,14 @@ export default function from(object, options = {}) {
|
|
|
65
56
|
) {
|
|
66
57
|
// A primitive value; box it into an object and construct a tree.
|
|
67
58
|
const boxed = box(object);
|
|
68
|
-
|
|
59
|
+
map = new ObjectMap(boxed);
|
|
69
60
|
} else {
|
|
70
|
-
throw new TypeError("Couldn't convert argument to
|
|
61
|
+
throw new TypeError("Couldn't convert argument to a map");
|
|
71
62
|
}
|
|
72
63
|
|
|
73
|
-
if (
|
|
74
|
-
|
|
64
|
+
if (options.parent) {
|
|
65
|
+
setParent(map, options.parent);
|
|
75
66
|
}
|
|
76
|
-
|
|
67
|
+
|
|
68
|
+
return map;
|
|
77
69
|
}
|
|
@@ -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
|
}
|
|
@@ -1,21 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* @param {any} obj
|
|
7
|
-
* @returns {obj is AsyncTree}
|
|
8
|
-
*/
|
|
9
|
-
export default function isAsyncTree(obj) {
|
|
10
|
-
return (
|
|
11
|
-
obj !== null &&
|
|
12
|
-
typeof obj === "object" &&
|
|
13
|
-
typeof obj.get === "function" &&
|
|
14
|
-
typeof obj.keys === "function" &&
|
|
15
|
-
// Regular JavaScript Map instances look like trees but can't have their
|
|
16
|
-
// prototype chains extended (the way map() does), so exclude them.
|
|
17
|
-
// Subclasses of Map that implement their own get() and keys() methods are
|
|
18
|
-
// allowed, because they shouldn't have the same limitations.
|
|
19
|
-
!(obj instanceof Map && Object.getPrototypeOf(obj) === Map.prototype)
|
|
20
|
-
);
|
|
1
|
+
import isMap from "./isMap.js";
|
|
2
|
+
|
|
3
|
+
export default function isAsyncTree(treelike) {
|
|
4
|
+
console.warn("Tree.isAsyncTree() is deprecated, use Tree.isMap() instead.");
|
|
5
|
+
return isMap(treelike);
|
|
21
6
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import AsyncMap from "../drivers/AsyncMap.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Return true if the indicated object is a Map instance or supports
|
|
5
|
+
* a `Map` compatible interface.
|
|
6
|
+
*
|
|
7
|
+
* @typedef {import("../../index.ts").SyncOrAsyncMap} SyncOrAsyncMap
|
|
8
|
+
*
|
|
9
|
+
* @param {any} object
|
|
10
|
+
* @returns {object is Map|AsyncMap}
|
|
11
|
+
*/
|
|
12
|
+
export default function isMap(object) {
|
|
13
|
+
if (object instanceof Map || object instanceof AsyncMap) {
|
|
14
|
+
// Known positive cases
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Check for Map-like interface
|
|
19
|
+
if (
|
|
20
|
+
object &&
|
|
21
|
+
object.clear instanceof Function &&
|
|
22
|
+
object.delete instanceof Function &&
|
|
23
|
+
object.entries instanceof Function &&
|
|
24
|
+
object.forEach instanceof Function &&
|
|
25
|
+
object.get instanceof Function &&
|
|
26
|
+
object.has instanceof Function &&
|
|
27
|
+
object.keys instanceof Function &&
|
|
28
|
+
object.set instanceof Function &&
|
|
29
|
+
object.values instanceof Function &&
|
|
30
|
+
object.constructor.groupBy instanceof Function &&
|
|
31
|
+
"size" in object &&
|
|
32
|
+
(object[Symbol.iterator] instanceof Function ||
|
|
33
|
+
object[Symbol.asyncIterator] instanceof Function)
|
|
34
|
+
) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import isPlainObject from "../utilities/isPlainObject.js";
|
|
2
|
+
import isMap from "./isMap.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns true if the indicated object can be directly treated like a Map. This
|
|
6
|
+
* includes:
|
|
7
|
+
*
|
|
8
|
+
* - A function
|
|
9
|
+
* - An `Array` instance
|
|
10
|
+
* - An `AsyncMap` instance
|
|
11
|
+
* - An `Iterator` instance
|
|
12
|
+
* - A `Map` instance
|
|
13
|
+
* - A `Set` instance
|
|
14
|
+
* - A plain object
|
|
15
|
+
*
|
|
16
|
+
* Note: the `from()` method accepts any JavaScript object, but `isMaplike`
|
|
17
|
+
* returns `false` for an object that isn't one of the above types.
|
|
18
|
+
*
|
|
19
|
+
* @typedef {import("../../index.ts").Maplike} Maplike
|
|
20
|
+
*
|
|
21
|
+
* @param {any} object
|
|
22
|
+
* @returns {obj is Maplike}
|
|
23
|
+
*/
|
|
24
|
+
export default function isMaplike(object) {
|
|
25
|
+
return (
|
|
26
|
+
object instanceof Array ||
|
|
27
|
+
object instanceof Function ||
|
|
28
|
+
// @ts-ignore
|
|
29
|
+
object instanceof Iterator ||
|
|
30
|
+
object instanceof Set ||
|
|
31
|
+
isMap(object) ||
|
|
32
|
+
isPlainObject(object)
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import isMap from "./isMap.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Return true if the indicated object is a read-only map.
|
|
5
|
+
*
|
|
6
|
+
* @param {any} object
|
|
7
|
+
*/
|
|
8
|
+
export default function isReadOnlyMap(object) {
|
|
9
|
+
if (!isMap(object)) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
// Respect readOnly if defined, otherwise assume read/write
|
|
13
|
+
return "readOnly" in object ? object.readOnly : false;
|
|
14
|
+
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import isPacked from "../utilities/isPacked.js";
|
|
2
|
-
import
|
|
2
|
+
import isMaplike from "./isMaplike.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Return true if the object can be traversed via the `traverse()` method. The
|
|
6
|
-
* object must be either
|
|
6
|
+
* object must be either maplike or a packed object with an `unpack()` method.
|
|
7
7
|
*
|
|
8
8
|
* @param {any} object
|
|
9
9
|
*/
|
|
10
10
|
export default function isTraversable(object) {
|
|
11
11
|
return (
|
|
12
|
-
|
|
12
|
+
isMaplike(object) ||
|
|
13
13
|
(isPacked(object) && /** @type {any} */ (object).unpack instanceof Function)
|
|
14
14
|
);
|
|
15
15
|
}
|
|
@@ -1,33 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import isAsyncTree from "./isAsyncTree.js";
|
|
1
|
+
import isMaplike from "./isMaplike.js";
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*
|
|
8
|
-
* - An object that implements the AsyncTree interface (including
|
|
9
|
-
* AsyncTree instances)
|
|
10
|
-
* - A function
|
|
11
|
-
* - An `Array` instance
|
|
12
|
-
* - A `Map` instance
|
|
13
|
-
* - A `Set` instance
|
|
14
|
-
* - A plain object
|
|
15
|
-
*
|
|
16
|
-
* Note: the `from()` method accepts any JavaScript object, but `isTreelike`
|
|
17
|
-
* returns `false` for an object that isn't one of the above types.
|
|
18
|
-
*
|
|
19
|
-
* @typedef {import("../../index.ts").Treelike} Treelike
|
|
20
|
-
*
|
|
21
|
-
* @param {any} obj
|
|
22
|
-
* @returns {obj is Treelike}
|
|
23
|
-
*/
|
|
24
|
-
export default function isTreelike(obj) {
|
|
25
|
-
return (
|
|
26
|
-
isAsyncTree(obj) ||
|
|
27
|
-
obj instanceof Array ||
|
|
28
|
-
obj instanceof Function ||
|
|
29
|
-
obj instanceof Map ||
|
|
30
|
-
obj instanceof Set ||
|
|
31
|
-
isPlainObject(obj)
|
|
3
|
+
export default function isTreelike(treelike) {
|
|
4
|
+
console.warn(
|
|
5
|
+
"Tree.isTreelike() is deprecated, use Tree.isMaplike() instead."
|
|
32
6
|
);
|
|
7
|
+
return isMaplike(treelike);
|
|
33
8
|
}
|