@weborigami/async-tree 0.6.9 → 0.6.10

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.
Files changed (66) hide show
  1. package/package.json +1 -1
  2. package/shared.js +2 -1
  3. package/src/TraverseError.js +6 -3
  4. package/src/drivers/CalendarMap.js +12 -4
  5. package/src/operations/addNextPrevious.js +2 -2
  6. package/src/operations/assign.js +7 -3
  7. package/src/operations/cache.js +4 -4
  8. package/src/operations/child.js +2 -2
  9. package/src/operations/clear.js +3 -3
  10. package/src/operations/deepEntries.js +3 -3
  11. package/src/operations/deepMap.js +2 -2
  12. package/src/operations/deepMerge.js +15 -2
  13. package/src/operations/deepReverse.js +4 -2
  14. package/src/operations/deepTake.js +3 -2
  15. package/src/operations/deepText.js +5 -4
  16. package/src/operations/deepValuesIterator.js +3 -3
  17. package/src/operations/delete.js +4 -5
  18. package/src/operations/entries.js +2 -2
  19. package/src/operations/filter.js +2 -2
  20. package/src/operations/first.js +2 -2
  21. package/src/operations/forEach.js +6 -2
  22. package/src/operations/from.js +5 -2
  23. package/src/operations/globKeys.js +2 -2
  24. package/src/operations/groupBy.js +5 -4
  25. package/src/operations/has.js +2 -2
  26. package/src/operations/indent.js +9 -3
  27. package/src/operations/inners.js +2 -2
  28. package/src/operations/invokeFunctions.js +2 -2
  29. package/src/operations/json.js +2 -2
  30. package/src/operations/keys.js +2 -2
  31. package/src/operations/length.js +2 -2
  32. package/src/operations/map.js +22 -18
  33. package/src/operations/mapExtension.js +3 -3
  34. package/src/operations/mapReduce.js +4 -4
  35. package/src/operations/mask.js +6 -6
  36. package/src/operations/match.js +7 -18
  37. package/src/operations/merge.js +13 -2
  38. package/src/operations/paginate.js +3 -2
  39. package/src/operations/parent.js +2 -2
  40. package/src/operations/paths.js +2 -2
  41. package/src/operations/plain.js +2 -2
  42. package/src/operations/reduce.js +2 -2
  43. package/src/operations/regExpKeys.js +5 -3
  44. package/src/operations/reverse.js +2 -2
  45. package/src/operations/root.js +2 -2
  46. package/src/operations/scope.js +5 -4
  47. package/src/operations/set.js +2 -2
  48. package/src/operations/shuffle.js +2 -2
  49. package/src/operations/size.js +2 -2
  50. package/src/operations/sort.js +4 -4
  51. package/src/operations/sync.js +2 -2
  52. package/src/operations/take.js +3 -2
  53. package/src/operations/toFunction.js +2 -2
  54. package/src/operations/traverse.js +3 -1
  55. package/src/operations/traverseOrThrow.js +40 -8
  56. package/src/operations/traversePath.js +5 -3
  57. package/src/operations/values.js +2 -2
  58. package/src/operations/visit.js +2 -2
  59. package/src/operations/withKeys.js +5 -3
  60. package/src/utilities/args.js +128 -0
  61. package/src/utilities/interop.js +9 -0
  62. package/src/utilities/setParent.js +1 -1
  63. package/test/operations/root.test.js +2 -2
  64. package/test/operations/traverse.test.js +1 -32
  65. package/test/operations/traverseOrThrow.test.js +73 -0
  66. package/src/utilities/getMapArgument.js +0 -38
@@ -1,6 +1,6 @@
1
1
  import AsyncMap from "../drivers/AsyncMap.js";
2
2
  import * as trailingSlash from "../trailingSlash.js";
3
- import getMapArgument from "../utilities/getMapArgument.js";
3
+ import * as args from "../utilities/args.js";
4
4
  import isPlainObject from "../utilities/isPlainObject.js";
5
5
  import isUnpackable from "../utilities/isUnpackable.js";
6
6
  import toFunction from "../utilities/toFunction.js";
@@ -28,7 +28,9 @@ export default async function map(maplike, options = {}) {
28
28
  const validated = validateOptions(options);
29
29
  const mapFn = createMapFn(validated);
30
30
 
31
- const tree = await getMapArgument(maplike, "map", { deep: validated.deep });
31
+ const tree = await args.map(maplike, "Tree.map", {
32
+ deep: validated.deep,
33
+ });
32
34
  return mapFn(tree);
33
35
  }
34
36
 
@@ -37,7 +39,7 @@ function createGet(tree, options, mapFn) {
37
39
  const { inverseKeyFn, deep, valueFn } = options;
38
40
  return async (resultKey) => {
39
41
  if (resultKey === undefined) {
40
- throw new ReferenceError(`map: Cannot get an undefined key.`);
42
+ throw new ReferenceError(`Tree.map: Cannot get an undefined key.`);
41
43
  }
42
44
 
43
45
  // Step 1: Map the result key to the source key
@@ -102,8 +104,8 @@ function createKeys(tree, options) {
102
104
  // Deep maps leave source keys for subtrees alone
103
105
  deep && trailingSlash.has(sourceKey)
104
106
  ? sourceKey
105
- : await keyFn(sourceValues[index], sourceKey, tree)
106
- )
107
+ : await keyFn(sourceValues[index], sourceKey, tree),
108
+ ),
107
109
  );
108
110
  // Filter out any cases where the keyFn returned undefined.
109
111
  const resultKeys = mapped.filter((key) => key !== undefined);
@@ -135,7 +137,7 @@ function validateOption(options, key) {
135
137
  const value = options[key];
136
138
  if (key in options && value === undefined) {
137
139
  throw new TypeError(
138
- `map: The ${key} option is given but its value is undefined.`
140
+ `Tree.map: The ${key} option is given but its value is undefined.`,
139
141
  );
140
142
  }
141
143
  return value;
@@ -173,38 +175,40 @@ function validateOptions(options) {
173
175
  (keyFn.includes("=>") || keyFn.includes("→"))
174
176
  ) {
175
177
  throw new TypeError(
176
- `map: The key option appears to be an extension mapping. Did you mean to call Tree.mapExtension() ?`
178
+ `Tree.map: The key option appears to be an extension mapping. Did you mean to call Tree.mapExtension() ?`,
177
179
  );
178
180
  }
179
181
  keyFn &&= castToFunction(keyFn, "key");
180
182
  valueFn &&= castToFunction(valueFn, "value");
181
183
  } else if (options === undefined) {
182
184
  /** @type {any} */
183
- const error = new TypeError(`map: The second parameter was undefined.`);
184
- error.position = 1;
185
+ const error = new TypeError(
186
+ `Tree.map: The second parameter was undefined.`,
187
+ );
188
+ error.position = 2;
185
189
  throw error;
186
190
  } else {
187
191
  /** @type {any} */
188
192
  const error = new TypeError(
189
- `map: You must specify a value function or options dictionary as the second parameter.`
193
+ `Tree.map: You must specify a value function or options dictionary as the second parameter.`,
190
194
  );
191
- error.position = 1;
195
+ error.position = 2;
192
196
  throw error;
193
197
  }
194
198
 
195
199
  if (extension && !options._noExtensionWarning) {
196
200
  console.warn(
197
- `map: The 'extension' option for Tree.map() is deprecated and will be removed in a future release. Use Tree.mapExtension() instead.`
201
+ `Tree.map: The 'extension' option for Tree.map() is deprecated and will be removed in a future release. Use Tree.mapExtension() instead.`,
198
202
  );
199
203
  }
200
204
  if (extension && (keyFn || inverseKeyFn)) {
201
205
  throw new TypeError(
202
- `map: You can't specify extensions and also a key or inverseKey function`
206
+ `Tree.map: You can't specify extensions and also a key or inverseKey function`,
203
207
  );
204
208
  }
205
209
  if (extension && keyNeedsSourceValue === true) {
206
210
  throw new TypeError(
207
- `map: using extensions sets keyNeedsSourceValue to be false`
211
+ `Tree.map: using extensions sets keyNeedsSourceValue to be false`,
208
212
  );
209
213
  }
210
214
 
@@ -213,7 +217,7 @@ function validateOptions(options) {
213
217
  const parsed = parseExtensions(extension);
214
218
  const keyFns = extensionKeyFunctions(
215
219
  parsed.sourceExtension,
216
- parsed.resultExtension
220
+ parsed.resultExtension,
217
221
  );
218
222
  keyFn = keyFns.key;
219
223
  inverseKeyFn = keyFns.inverseKey;
@@ -225,7 +229,7 @@ function validateOptions(options) {
225
229
 
226
230
  if (!keyFn && inverseKeyFn) {
227
231
  throw new TypeError(
228
- `map: You can't specify an inverseKey function without a key function`
232
+ `Tree.map: You can't specify an inverseKey function without a key function`,
229
233
  );
230
234
  }
231
235
 
@@ -239,7 +243,7 @@ function validateOptions(options) {
239
243
 
240
244
  if (!valueFn && !keyFn) {
241
245
  throw new TypeError(
242
- `map: You must specify a value function or a key function`
246
+ `Tree.map: You must specify a value function or a key function`,
243
247
  );
244
248
  }
245
249
 
@@ -262,7 +266,7 @@ function castToFunction(object, name) {
262
266
  const fn = toFunction(object);
263
267
  if (!fn) {
264
268
  throw new TypeError(
265
- `map: The ${name} option must be a function but couldn't be treated as one.`
269
+ `Tree.map: The ${name} option must be a function but couldn't be treated as one.`,
266
270
  );
267
271
  }
268
272
  return fn;
@@ -54,13 +54,13 @@ export default async function mapExtension(maplike, arg2, arg3) {
54
54
  Object.assign(options, arg2);
55
55
  } else {
56
56
  throw new TypeError(
57
- "mapExtension: Expected a string or options object for the second argument."
57
+ "Tree.mapExtension: Expected a string or options object for the second argument.",
58
58
  );
59
59
  }
60
60
  } else {
61
61
  if (typeof arg2 !== "string") {
62
62
  throw new TypeError(
63
- "mapExtension: Expected a string for the second argument."
63
+ "Tree.mapExtension: Expected a string for the second argument.",
64
64
  );
65
65
  }
66
66
  options.extension = arg2;
@@ -73,7 +73,7 @@ export default async function mapExtension(maplike, arg2, arg3) {
73
73
  Object.assign(options, arg3);
74
74
  } else {
75
75
  throw new TypeError(
76
- "mapExtension: Expected a function or options object for the third argument."
76
+ "Tree.mapExtension: Expected a function or options object for the third argument.",
77
77
  );
78
78
  }
79
79
  }
@@ -1,4 +1,4 @@
1
- import getMapArgument from "../utilities/getMapArgument.js";
1
+ import * as args from "../utilities/args.js";
2
2
  import isMap from "./isMap.js";
3
3
 
4
4
  /**
@@ -23,7 +23,7 @@ import isMap from "./isMap.js";
23
23
  * @param {ReduceFn} reduceFn
24
24
  */
25
25
  export default async function mapReduce(source, valueFn, reduceFn) {
26
- const sourceMap = await getMapArgument(source, "mapReduce");
26
+ const sourceMap = await args.map(source, "Tree.mapReduce");
27
27
 
28
28
  // We're going to fire off all the get requests in parallel, as quickly as
29
29
  // the keys come in. We call the tree's `get` method for each key, but
@@ -37,8 +37,8 @@ export default async function mapReduce(source, valueFn, reduceFn) {
37
37
  return isMap(value)
38
38
  ? mapReduce(value, valueFn, reduceFn) // subtree; recurse
39
39
  : valueFn
40
- ? valueFn(value, key, sourceMap)
41
- : value;
40
+ ? valueFn(value, key, sourceMap)
41
+ : value;
42
42
  })();
43
43
  promises.push(promise);
44
44
  }
@@ -1,6 +1,6 @@
1
1
  import AsyncMap from "../drivers/AsyncMap.js";
2
2
  import * as trailingSlash from "../trailingSlash.js";
3
- import getMapArgument from "../utilities/getMapArgument.js";
3
+ import * as args from "../utilities/args.js";
4
4
  import isMaplike from "./isMaplike.js";
5
5
  import keys from "./keys.js";
6
6
 
@@ -16,13 +16,13 @@ import keys from "./keys.js";
16
16
  * @returns {Promise<AsyncMap>}
17
17
  */
18
18
  export default async function mask(aMaplike, bMaplike) {
19
- const aMap = await getMapArgument(aMaplike, "filter", {
19
+ const aMap = await args.map(aMaplike, "Tree.mask", {
20
20
  deep: true,
21
- position: 0,
21
+ position: 1,
22
22
  });
23
- const bMap = await getMapArgument(bMaplike, "filter", {
23
+ const bMap = await args.map(bMaplike, "Tree.mask", {
24
24
  deep: true,
25
- position: 1,
25
+ position: 2,
26
26
  });
27
27
 
28
28
  return Object.assign(new AsyncMap(), {
@@ -66,7 +66,7 @@ export default async function mask(aMaplike, bMaplike) {
66
66
  }
67
67
  return trailingSlash.toggle(
68
68
  key,
69
- trailingSlash.has(key) || isMaplike(bValue)
69
+ trailingSlash.has(key) || isMaplike(bValue),
70
70
  );
71
71
  });
72
72
 
@@ -1,5 +1,5 @@
1
1
  import AsyncMap from "../drivers/AsyncMap.js";
2
- import isMap from "./isMap.js";
2
+ import * as args from "../utilities/args.js";
3
3
 
4
4
  /**
5
5
  * Return a tree with the indicated keys (if provided).
@@ -27,15 +27,17 @@ export default function match(pattern, resultFn, keys = []) {
27
27
  // Convert the simple pattern format into a regular expression.
28
28
  const regexText = pattern.replace(
29
29
  /\[(?<variable>.+)\]/g,
30
- (match, p1, offset, string, groups) => `(?<${groups.variable}>.+)`
30
+ (match, p1, offset, string, groups) => `(?<${groups.variable}>.+)`,
31
31
  );
32
32
  regex = new RegExp(`^${regexText}$`);
33
33
  } else if (pattern instanceof RegExp) {
34
34
  regex = pattern;
35
35
  } else {
36
- throw new Error(`match(): Unsupported pattern`);
36
+ throw new Error(`Tree.match: Unsupported pattern`);
37
37
  }
38
38
 
39
+ const fn = args.invocable(resultFn, "Tree.match", { position: 2 });
40
+
39
41
  const result = Object.assign(new AsyncMap(), {
40
42
  description: "match",
41
43
 
@@ -45,24 +47,11 @@ export default function match(pattern, resultFn, keys = []) {
45
47
  return undefined;
46
48
  }
47
49
 
48
- if (
49
- typeof resultFn !== "function" &&
50
- !(isMap(resultFn) && "parent" in resultFn)
51
- ) {
52
- // Simple return value; return as is
53
- return resultFn;
54
- }
55
-
56
50
  // Copy the `groups` property to a real object
57
51
  const matches = { ...keyMatch.groups };
58
52
 
59
- // Invoke the result function with the extended scope.
60
- let value;
61
- if (typeof resultFn === "function") {
62
- value = await resultFn(matches);
63
- } else {
64
- value = Object.create(resultFn);
65
- }
53
+ // Invoke the result function
54
+ const value = await fn(matches);
66
55
 
67
56
  return value;
68
57
  },
@@ -4,6 +4,7 @@ import isPlainObject from "../utilities/isPlainObject.js";
4
4
  import isUnpackable from "../utilities/isUnpackable.js";
5
5
  import from from "./from.js";
6
6
  import isMap from "./isMap.js";
7
+ import isMaplike from "./isMaplike.js";
7
8
  import keys from "./keys.js";
8
9
 
9
10
  /**
@@ -25,10 +26,20 @@ export default async function merge(...treelikes) {
25
26
  const filtered = treelikes.filter((source) => source);
26
27
  const unpacked = await Promise.all(
27
28
  filtered.map(async (source) =>
28
- isUnpackable(source) ? await source.unpack() : source
29
- )
29
+ isUnpackable(source) ? await source.unpack() : source,
30
+ ),
30
31
  );
31
32
 
33
+ // If any argument isn't maplike, throw an error.
34
+ for (const index in unpacked) {
35
+ if (!isMaplike(unpacked[index])) {
36
+ /** @type {any} */
37
+ const error = new TypeError(`Tree.merge: an argument wasn't maplike.`);
38
+ error.position = Number(index) + 1;
39
+ throw error;
40
+ }
41
+ }
42
+
32
43
  // If all arguments are plain objects, return a plain object.
33
44
  if (unpacked.every((source) => !isMap(source) && isPlainObject(source))) {
34
45
  return unpacked.reduce((acc, obj) => ({ ...acc, ...obj }), {});
@@ -1,7 +1,7 @@
1
1
  import AsyncMap from "../drivers/AsyncMap.js";
2
2
  import SyncMap from "../drivers/SyncMap.js";
3
3
  import * as trailingSlash from "../trailingSlash.js";
4
- import getMapArgument from "../utilities/getMapArgument.js";
4
+ import * as args from "../utilities/args.js";
5
5
  import keys from "./keys.js";
6
6
 
7
7
  /**
@@ -14,7 +14,8 @@ import keys from "./keys.js";
14
14
  * @param {number} [size=10]
15
15
  */
16
16
  export default async function paginate(maplike, size = 10) {
17
- const source = await getMapArgument(maplike, "paginate");
17
+ const source = await args.map(maplike, "Tree.paginate");
18
+ size = args.number(size, "Tree.paginate", { position: 2 });
18
19
 
19
20
  const treeKeys = await keys(source);
20
21
  const pageCount = Math.ceil(treeKeys.length / size);
@@ -1,4 +1,4 @@
1
- import getMapArgument from "../utilities/getMapArgument.js";
1
+ import * as args from "../utilities/args.js";
2
2
 
3
3
  /**
4
4
  * Returns the parent of the map, if any.
@@ -8,6 +8,6 @@ import getMapArgument from "../utilities/getMapArgument.js";
8
8
  * @param {Maplike} maplike
9
9
  */
10
10
  export default async function parent(maplike) {
11
- const map = await getMapArgument(maplike, "parent");
11
+ const map = await args.map(maplike, "Tree.parent");
12
12
  return "parent" in map ? map.parent : undefined;
13
13
  }
@@ -1,5 +1,5 @@
1
1
  import * as trailingSlash from "../trailingSlash.js";
2
- import getMapArgument from "../utilities/getMapArgument.js";
2
+ import * as args from "../utilities/args.js";
3
3
  import from from "./from.js";
4
4
  import isMap from "./isMap.js";
5
5
  import isMaplike from "./isMaplike.js";
@@ -15,7 +15,7 @@ import isMaplike from "./isMaplike.js";
15
15
  * @param {{ base?: string }} options
16
16
  */
17
17
  export default async function paths(maplike, options = {}) {
18
- const tree = await getMapArgument(maplike, "paths");
18
+ const tree = await args.map(maplike, "Tree.paths");
19
19
  const base = options.base ?? "";
20
20
  const result = [];
21
21
  for await (const key of tree.keys()) {
@@ -1,4 +1,4 @@
1
- import getMapArgument from "../utilities/getMapArgument.js";
1
+ import * as args from "../utilities/args.js";
2
2
  import toPlainValue from "../utilities/toPlainValue.js";
3
3
 
4
4
  /**
@@ -29,6 +29,6 @@ export default async function plain(maplike) {
29
29
  if (maplike instanceof Function) {
30
30
  throw new TypeError("plain: can't convert a function to a plain object");
31
31
  }
32
- const tree = await getMapArgument(maplike, "plain");
32
+ const tree = await args.map(maplike, "Tree.plain");
33
33
  return toPlainValue(tree);
34
34
  }
@@ -1,4 +1,4 @@
1
- import getMapArgument from "../utilities/getMapArgument.js";
1
+ import * as args from "../utilities/args.js";
2
2
  import mapReduce from "./mapReduce.js";
3
3
 
4
4
  /**
@@ -11,6 +11,6 @@ import mapReduce from "./mapReduce.js";
11
11
  * @param {ReduceFn} reduceFn
12
12
  */
13
13
  export default async function reduce(maplike, reduceFn) {
14
- const map = await getMapArgument(maplike, "reduce");
14
+ const map = await args.map(maplike, "Tree.reduce");
15
15
  return mapReduce(map, null, reduceFn);
16
16
  }
@@ -1,7 +1,7 @@
1
1
  import AsyncMap from "../drivers/AsyncMap.js";
2
2
  import SyncMap from "../drivers/SyncMap.js";
3
3
  import * as trailingSlash from "../trailingSlash.js";
4
- import getMapArgument from "../utilities/getMapArgument.js";
4
+ import * as args from "../utilities/args.js";
5
5
  import isMap from "./isMap.js";
6
6
 
7
7
  /**
@@ -18,7 +18,9 @@ import isMap from "./isMap.js";
18
18
  * @returns {Promise<AsyncMap>}
19
19
  */
20
20
  export default async function regExpKeys(maplike) {
21
- const source = await getMapArgument(maplike, "regExpKeys", { deep: true });
21
+ const source = await args.map(maplike, "Tree.regExpKeys", {
22
+ deep: true,
23
+ });
22
24
 
23
25
  const map = new SyncMap();
24
26
 
@@ -32,7 +34,7 @@ export default async function regExpKeys(maplike) {
32
34
  if (key == null) {
33
35
  // Reject nullish key.
34
36
  throw new ReferenceError(
35
- `regExpKeys: Cannot get a null or undefined key.`
37
+ `regExpKeys: Cannot get a null or undefined key.`,
36
38
  );
37
39
  }
38
40
 
@@ -1,5 +1,5 @@
1
1
  import AsyncMap from "../drivers/AsyncMap.js";
2
- import getMapArgument from "../utilities/getMapArgument.js";
2
+ import * as args from "../utilities/args.js";
3
3
  import keys from "./keys.js";
4
4
 
5
5
  /**
@@ -11,7 +11,7 @@ import keys from "./keys.js";
11
11
  * @returns {Promise<AsyncMap>}
12
12
  */
13
13
  export default async function reverse(maplike) {
14
- const source = await getMapArgument(maplike, "reverse");
14
+ const source = await args.map(maplike, "Tree.reverse");
15
15
  return Object.assign(new AsyncMap(), {
16
16
  description: "reverse",
17
17
 
@@ -1,5 +1,5 @@
1
1
  import * as symbols from "../symbols.js";
2
- import getMapArgument from "../utilities/getMapArgument.js";
2
+ import * as args from "../utilities/args.js";
3
3
 
4
4
  /**
5
5
  * Walk up the `parent` chain to find the root of the tree.
@@ -10,7 +10,7 @@ import getMapArgument from "../utilities/getMapArgument.js";
10
10
  */
11
11
  export default async function root(maplike) {
12
12
  /** @type {any} */
13
- let current = await getMapArgument(maplike, "root");
13
+ let current = await args.map(maplike, "Tree.root");
14
14
  while (current.parent || current[symbols.parent]) {
15
15
  current = current.parent || current[symbols.parent];
16
16
  }
@@ -1,5 +1,6 @@
1
1
  import AsyncMap from "../drivers/AsyncMap.js";
2
- import getMapArgument from "../utilities/getMapArgument.js";
2
+ import * as args from "../utilities/args.js";
3
+ import getParent from "../utilities/getParent.js";
3
4
 
4
5
  /**
5
6
  * A map's "scope" is the collection of everything in that map and all of its
@@ -11,7 +12,7 @@ import getMapArgument from "../utilities/getMapArgument.js";
11
12
  * @returns {Promise<AsyncMap>}
12
13
  */
13
14
  export default async function scope(maplike) {
14
- const source = await getMapArgument(maplike, "scope");
15
+ const source = await args.map(maplike, "Tree.scope");
15
16
 
16
17
  return Object.assign(new AsyncMap(), {
17
18
  description: "scope",
@@ -26,7 +27,7 @@ export default async function scope(maplike) {
26
27
  if (value !== undefined) {
27
28
  break;
28
29
  }
29
- current = "parent" in current ? current.parent : null;
30
+ current = getParent(current);
30
31
  }
31
32
  return value;
32
33
  },
@@ -40,7 +41,7 @@ export default async function scope(maplike) {
40
41
  for await (const key of current.keys()) {
41
42
  scopeKeys.add(key);
42
43
  }
43
- current = "parent" in current ? current.parent : null;
44
+ current = getParent(current);
44
45
  }
45
46
 
46
47
  yield* scopeKeys;
@@ -1,4 +1,4 @@
1
- import getMapArgument from "../utilities/getMapArgument.js";
1
+ import * as args from "../utilities/args.js";
2
2
 
3
3
  /**
4
4
  * Set a key/value pair in a map.
@@ -10,7 +10,7 @@ import getMapArgument from "../utilities/getMapArgument.js";
10
10
  * @param {any} value
11
11
  */
12
12
  export default async function set(maplike, key, value) {
13
- const map = await getMapArgument(maplike, "set");
13
+ const map = await args.map(maplike, "Tree.set");
14
14
  await map.set(key, value);
15
15
 
16
16
  // Unlike Map.prototype.set, we return undefined. This is more useful when
@@ -1,5 +1,5 @@
1
1
  import AsyncMap from "../drivers/AsyncMap.js";
2
- import getMapArgument from "../utilities/getMapArgument.js";
2
+ import * as args from "../utilities/args.js";
3
3
  import keys from "./keys.js";
4
4
 
5
5
  /**
@@ -12,7 +12,7 @@ import keys from "./keys.js";
12
12
  * @returns {Promise<AsyncMap>}
13
13
  */
14
14
  export default async function shuffle(maplike, reshuffle = false) {
15
- const source = await getMapArgument(maplike, "shuffle");
15
+ const source = await args.map(maplike, "Tree.shuffle");
16
16
 
17
17
  let mapKeys;
18
18
 
@@ -1,4 +1,4 @@
1
- import getMapArgument from "../utilities/getMapArgument.js";
1
+ import * as args from "../utilities/args.js";
2
2
 
3
3
  /**
4
4
  * Return the number of keys in the map.
@@ -8,6 +8,6 @@ import getMapArgument from "../utilities/getMapArgument.js";
8
8
  * @param {Maplike} maplike
9
9
  */
10
10
  export default async function size(maplike) {
11
- const map = await getMapArgument(maplike, "size");
11
+ const map = await args.map(maplike, "Tree.size");
12
12
  return map.size;
13
13
  }
@@ -1,5 +1,5 @@
1
1
  import AsyncMap from "../drivers/AsyncMap.js";
2
- import getMapArgument from "../utilities/getMapArgument.js";
2
+ import * as args from "../utilities/args.js";
3
3
  import keys from "./keys.js";
4
4
 
5
5
  /**
@@ -17,7 +17,7 @@ import keys from "./keys.js";
17
17
  * @param {SortOptions|ValueKeyFn} [options]
18
18
  */
19
19
  export default async function sort(maplike, options) {
20
- const source = await getMapArgument(maplike, "sort");
20
+ const source = await args.map(maplike, "Tree.sort");
21
21
 
22
22
  let sortKey;
23
23
  let compare;
@@ -49,11 +49,11 @@ export default async function sort(maplike, options) {
49
49
  const sort = await sortKey(value, key, source);
50
50
  if (sort === undefined) {
51
51
  throw new Error(
52
- `sortKey function returned undefined for key ${key}`
52
+ `sortKey function returned undefined for key ${key}`,
53
53
  );
54
54
  }
55
55
  return { key, sort };
56
- })
56
+ }),
57
57
  );
58
58
 
59
59
  // Wrap the comparison function so it applies to sort keys.
@@ -1,4 +1,4 @@
1
- import getMapArgument from "../utilities/getMapArgument.js";
1
+ import * as args from "../utilities/args.js";
2
2
  import reduce from "./reduce.js";
3
3
 
4
4
  /**
@@ -9,6 +9,6 @@ import reduce from "./reduce.js";
9
9
  * @param {Maplike} source
10
10
  */
11
11
  export default async function sync(source) {
12
- const tree = await getMapArgument(source, "sync");
12
+ const tree = await args.map(source, "Tree.sync");
13
13
  return reduce(tree, (mapped) => mapped);
14
14
  }
@@ -1,5 +1,5 @@
1
1
  import AsyncMap from "../drivers/AsyncMap.js";
2
- import getMapArgument from "../utilities/getMapArgument.js";
2
+ import * as args from "../utilities/args.js";
3
3
 
4
4
  /**
5
5
  * Returns a new map with the number of keys limited to the indicated count.
@@ -8,7 +8,8 @@ import getMapArgument from "../utilities/getMapArgument.js";
8
8
  * @param {number} count
9
9
  */
10
10
  export default async function take(maplike, count) {
11
- const source = await getMapArgument(maplike, "take");
11
+ const source = await args.map(maplike, "Tree.take");
12
+ count = args.number(count, "Tree.take", { position: 2 });
12
13
  return Object.assign(new AsyncMap(), {
13
14
  description: `take ${count}`,
14
15
 
@@ -1,4 +1,4 @@
1
- import getMapArgument from "../utilities/getMapArgument.js";
1
+ import * as args from "../utilities/args.js";
2
2
 
3
3
  /**
4
4
  * Returns a function that invokes the map's `get` method.
@@ -9,6 +9,6 @@ import getMapArgument from "../utilities/getMapArgument.js";
9
9
  * @returns {Promise<Function>}
10
10
  */
11
11
  export default async function toFunction(maplike) {
12
- const map = await getMapArgument(maplike, "toFunction");
12
+ const map = await args.map(maplike, "Tree.toFunction");
13
13
  return map.get.bind(map);
14
14
  }
@@ -1,4 +1,5 @@
1
1
  import TraverseError from "../TraverseError.js";
2
+ import * as args from "../utilities/args.js";
2
3
  import traverseOrThrow from "./traverseOrThrow.js";
3
4
 
4
5
  /**
@@ -10,10 +11,11 @@ import traverseOrThrow from "./traverseOrThrow.js";
10
11
  * @param {...any} keys
11
12
  */
12
13
  export default async function traverse(maplike, ...keys) {
14
+ const map = await args.map(maplike, "Tree.traverse");
13
15
  try {
14
16
  // Await the result here so that, if the path doesn't exist, the catch
15
17
  // block below will catch the exception.
16
- return await traverseOrThrow(maplike, ...keys);
18
+ return await traverseOrThrow(map, ...keys);
17
19
  } catch (/** @type {any} */ error) {
18
20
  if (error instanceof TraverseError) {
19
21
  return undefined;