@weborigami/async-tree 0.0.40 → 0.0.41
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 +2 -2
- package/src/FunctionTree.js +2 -1
- package/src/Tree.js +37 -14
- package/test/Tree.test.js +14 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/async-tree",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.41",
|
|
4
4
|
"description": "Asynchronous tree drivers based on standard JavaScript classes",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./main.js",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"typescript": "5.3.3"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@weborigami/types": "0.0.
|
|
14
|
+
"@weborigami/types": "0.0.41"
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
17
|
"test": "node --test --test-reporter=spec",
|
package/src/FunctionTree.js
CHANGED
|
@@ -23,7 +23,8 @@ export default class FunctionTree {
|
|
|
23
23
|
async get(key) {
|
|
24
24
|
const value =
|
|
25
25
|
this.fn.length <= 1
|
|
26
|
-
? // Function takes no arguments or
|
|
26
|
+
? // Function takes no arguments, one argument, or a variable number of
|
|
27
|
+
// arguments: invoke it.
|
|
27
28
|
await this.fn.call(null, key)
|
|
28
29
|
: // Bind the key to the first parameter. Subsequent get calls will
|
|
29
30
|
// eventually bind all parameters until only one remains. At that point,
|
package/src/Tree.js
CHANGED
|
@@ -18,6 +18,8 @@ import { castArrayLike, isPlainObject } from "./utilities.js";
|
|
|
18
18
|
* @typedef {import("@weborigami/types").AsyncTree} AsyncTree
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
+
const treeModule = this;
|
|
22
|
+
|
|
21
23
|
/**
|
|
22
24
|
* Apply the key/values pairs from the source tree to the target tree.
|
|
23
25
|
*
|
|
@@ -331,6 +333,7 @@ export async function traverse(treelike, ...keys) {
|
|
|
331
333
|
* Return the value at the corresponding path of keys. Throw if any interior
|
|
332
334
|
* step of the path doesn't lead to a result.
|
|
333
335
|
*
|
|
336
|
+
* @this {AsyncTree|null|undefined}
|
|
334
337
|
* @param {Treelike} treelike
|
|
335
338
|
* @param {...any} keys
|
|
336
339
|
*/
|
|
@@ -339,11 +342,15 @@ export async function traverseOrThrow(treelike, ...keys) {
|
|
|
339
342
|
/** @type {any} */
|
|
340
343
|
let value = treelike;
|
|
341
344
|
|
|
342
|
-
//
|
|
343
|
-
//
|
|
345
|
+
// If traversal operation was called with a `this` context, use that as the
|
|
346
|
+
// target for function calls.
|
|
347
|
+
const target = this === treeModule ? undefined : this;
|
|
348
|
+
|
|
349
|
+
// Process all the keys.
|
|
344
350
|
const remainingKeys = keys.slice();
|
|
345
351
|
while (remainingKeys.length > 0) {
|
|
346
352
|
if (value === undefined) {
|
|
353
|
+
// Attempted to traverse an undefined value
|
|
347
354
|
const keyStrings = keys.map((key) => String(key));
|
|
348
355
|
throw new TraverseError(
|
|
349
356
|
`Couldn't traverse the path: ${keyStrings.join("/")}`,
|
|
@@ -352,24 +359,40 @@ export async function traverseOrThrow(treelike, ...keys) {
|
|
|
352
359
|
);
|
|
353
360
|
}
|
|
354
361
|
|
|
355
|
-
//
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
// An empty string as the last key is a special case.
|
|
359
|
-
if (key === "" && remainingKeys.length === 0) {
|
|
362
|
+
// Special case: one key left that's an empty string
|
|
363
|
+
if (remainingKeys.length === 1 && remainingKeys[0] === "") {
|
|
360
364
|
// Unpack the value if it defines an `unpack` function, otherwise return
|
|
361
365
|
// the value itself.
|
|
362
|
-
|
|
363
|
-
continue;
|
|
366
|
+
return typeof value.unpack === "function" ? await value.unpack() : value;
|
|
364
367
|
}
|
|
365
368
|
|
|
366
|
-
//
|
|
367
|
-
//
|
|
368
|
-
|
|
369
|
+
// If the value is not a function or async tree already, but can be
|
|
370
|
+
// unpacked, unpack it.
|
|
371
|
+
if (
|
|
372
|
+
!(value instanceof Function) &&
|
|
373
|
+
!isAsyncTree(value) &&
|
|
374
|
+
value.unpack instanceof Function
|
|
375
|
+
) {
|
|
376
|
+
value = await value.unpack();
|
|
377
|
+
}
|
|
369
378
|
|
|
370
|
-
|
|
371
|
-
|
|
379
|
+
if (value instanceof Function) {
|
|
380
|
+
// Value is a function: call it with the remaining keys.
|
|
381
|
+
const fn = value;
|
|
382
|
+
// We'll take as many keys as the function's length, but at least one.
|
|
383
|
+
let fnKeyCount = Math.max(fn.length, 1);
|
|
384
|
+
const args = remainingKeys.splice(0, fnKeyCount);
|
|
385
|
+
value = await fn.call(target, ...args);
|
|
386
|
+
} else {
|
|
387
|
+
// Value is some other treelike object: cast it to a tree.
|
|
388
|
+
const tree = from(value);
|
|
389
|
+
// Get the next key.
|
|
390
|
+
const key = remainingKeys.shift();
|
|
391
|
+
// Get the value for the key.
|
|
392
|
+
value = await tree.get(key);
|
|
393
|
+
}
|
|
372
394
|
}
|
|
395
|
+
|
|
373
396
|
return value;
|
|
374
397
|
}
|
|
375
398
|
|
package/test/Tree.test.js
CHANGED
|
@@ -285,6 +285,13 @@ describe("Tree", () => {
|
|
|
285
285
|
);
|
|
286
286
|
});
|
|
287
287
|
|
|
288
|
+
test("traverse() a function with fixed number of arguments", async () => {
|
|
289
|
+
const tree = (a, b) => ({
|
|
290
|
+
c: "Result",
|
|
291
|
+
});
|
|
292
|
+
assert.equal(await Tree.traverse(tree, "a", "b", "c"), "Result");
|
|
293
|
+
});
|
|
294
|
+
|
|
288
295
|
test("traverse() from one tree into another", async () => {
|
|
289
296
|
const tree = new ObjectTree({
|
|
290
297
|
a: {
|
|
@@ -298,15 +305,13 @@ describe("Tree", () => {
|
|
|
298
305
|
});
|
|
299
306
|
|
|
300
307
|
test("traversing a final empty string can unpack the last value", async () => {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
unpackable,
|
|
309
|
-
});
|
|
308
|
+
const tree = {
|
|
309
|
+
unpackable: {
|
|
310
|
+
unpack() {
|
|
311
|
+
return "Content";
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
};
|
|
310
315
|
const result = await Tree.traverse(tree, "unpackable", "");
|
|
311
316
|
assert.equal(result, "Content");
|
|
312
317
|
});
|