@weborigami/async-tree 0.0.66-beta.2 → 0.0.66
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/main.js
CHANGED
|
@@ -6,9 +6,9 @@ export { default as FunctionTree } from "./src/FunctionTree.js";
|
|
|
6
6
|
export { default as MapTree } from "./src/MapTree.js";
|
|
7
7
|
// Skip BrowserFileTree.js, which is browser-only.
|
|
8
8
|
export { default as DeepMapTree } from "./src/DeepMapTree.js";
|
|
9
|
+
export { default as ExplorableSiteTree } from "./src/ExplorableSiteTree.js";
|
|
9
10
|
export { DeepObjectTree, ObjectTree, Tree } from "./src/internal.js";
|
|
10
11
|
export * as jsonKeys from "./src/jsonKeys.js";
|
|
11
|
-
export { default as OpenSiteTree } from "./src/OpenSiteTree.js";
|
|
12
12
|
export { default as cache } from "./src/operations/cache.js";
|
|
13
13
|
export { default as concat } from "./src/operations/concat.js";
|
|
14
14
|
export { default as deepMerge } from "./src/operations/deepMerge.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/async-tree",
|
|
3
|
-
"version": "0.0.66
|
|
3
|
+
"version": "0.0.66",
|
|
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.6.2"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@weborigami/types": "0.0.66
|
|
14
|
+
"@weborigami/types": "0.0.66"
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
17
|
"test": "node --test --test-reporter=spec",
|
package/src/DeferredTree.js
CHANGED
|
@@ -14,12 +14,14 @@ import { Tree } from "./internal.js";
|
|
|
14
14
|
export default class DeferredTree {
|
|
15
15
|
/**
|
|
16
16
|
* @param {Function|Promise<any>} loader
|
|
17
|
+
* @param {{ deep?: boolean }} [options]
|
|
17
18
|
*/
|
|
18
|
-
constructor(loader) {
|
|
19
|
+
constructor(loader, options) {
|
|
19
20
|
this.loader = loader;
|
|
20
21
|
this.treePromise = null;
|
|
21
22
|
this._tree = null;
|
|
22
23
|
this._parentUntilLoaded = null;
|
|
24
|
+
this._deep = options?.deep ?? false;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
async get(key) {
|
|
@@ -60,7 +62,7 @@ export default class DeferredTree {
|
|
|
60
62
|
|
|
61
63
|
// Use a promise to ensure the treelike is only converted to a tree once.
|
|
62
64
|
this.treePromise ??= this.loadResult().then((treelike) => {
|
|
63
|
-
this._tree = Tree.from(treelike);
|
|
65
|
+
this._tree = Tree.from(treelike, { deep: this._deep });
|
|
64
66
|
if (this._parentUntilLoaded) {
|
|
65
67
|
// Now that the tree has been loaded, we can set its parent if it hasn't
|
|
66
68
|
// already been set.
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import SiteTree from "./SiteTree.js";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* A [SiteTree](SiteTree.html) that implements the [JSON Keys](jsonKeys.html)
|
|
5
|
+
* protocol. This enables a `keys()` method that can return the keys of a site
|
|
6
|
+
* route even though such a mechanism is not built into the HTTP protocol.
|
|
7
|
+
*/
|
|
8
|
+
export default class ExplorableSiteTree extends SiteTree {
|
|
4
9
|
constructor(...args) {
|
|
5
10
|
super(...args);
|
|
6
11
|
this.serverKeysPromise = undefined;
|
|
@@ -24,6 +29,12 @@ export default class OpenSiteTree extends SiteTree {
|
|
|
24
29
|
return this.serverKeysPromise;
|
|
25
30
|
}
|
|
26
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Returns the keys of the site route. For this to work, the route must have a
|
|
34
|
+
* `.keys.json` file that contains a JSON array of string keys.
|
|
35
|
+
*
|
|
36
|
+
* @returns {Promise<Iterable<string>>}
|
|
37
|
+
*/
|
|
27
38
|
async keys() {
|
|
28
39
|
const serverKeys = await this.getServerKeys();
|
|
29
40
|
return serverKeys ?? [];
|
package/src/SiteTree.js
CHANGED
|
@@ -56,6 +56,14 @@ export default class SiteTree {
|
|
|
56
56
|
return this.processResponse(response);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Returns an empty set of keys.
|
|
61
|
+
*
|
|
62
|
+
* For a variation of `SiteTree` that can return the keys for a site route,
|
|
63
|
+
* see [ExplorableSiteTree](ExplorableSiteTree.html).
|
|
64
|
+
*
|
|
65
|
+
* @returns {Promise<Iterable<string>>}
|
|
66
|
+
*/
|
|
59
67
|
async keys() {
|
|
60
68
|
return [];
|
|
61
69
|
}
|
package/src/Tree.js
CHANGED
|
@@ -110,10 +110,11 @@ export async function forEach(tree, callbackFn) {
|
|
|
110
110
|
* parent of the new tree.
|
|
111
111
|
*
|
|
112
112
|
* @param {Treelike | Object} object
|
|
113
|
-
* @param {{ deep?:
|
|
113
|
+
* @param {{ deep?: boolean, parent?: AsyncTree|null }} [options]
|
|
114
114
|
* @returns {AsyncTree}
|
|
115
115
|
*/
|
|
116
116
|
export function from(object, options = {}) {
|
|
117
|
+
const deep = options.deep ?? false;
|
|
117
118
|
let tree;
|
|
118
119
|
if (isAsyncTree(object)) {
|
|
119
120
|
// Argument already supports the tree interface.
|
|
@@ -126,13 +127,13 @@ export function from(object, options = {}) {
|
|
|
126
127
|
} else if (object instanceof Set) {
|
|
127
128
|
tree = new SetTree(object);
|
|
128
129
|
} else if (isPlainObject(object) || object instanceof Array) {
|
|
129
|
-
tree =
|
|
130
|
+
tree = deep ? new DeepObjectTree(object) : new ObjectTree(object);
|
|
130
131
|
} else if (isUnpackable(object)) {
|
|
131
132
|
async function AsyncFunction() {} // Sample async function
|
|
132
133
|
tree =
|
|
133
134
|
object.unpack instanceof AsyncFunction.constructor
|
|
134
135
|
? // Async unpack: return a deferred tree.
|
|
135
|
-
new DeferredTree(object.unpack)
|
|
136
|
+
new DeferredTree(object.unpack, { deep })
|
|
136
137
|
: // Synchronous unpack: cast the result of unpack() to a tree.
|
|
137
138
|
from(object.unpack());
|
|
138
139
|
} else if (object && typeof object === "object") {
|
|
@@ -320,6 +321,8 @@ export async function paths(treelike, base = "") {
|
|
|
320
321
|
* The result's keys will be the tree's keys cast to strings. Any tree value
|
|
321
322
|
* that is itself a tree will be similarly converted to a plain object.
|
|
322
323
|
*
|
|
324
|
+
* Any trailing slashes in keys will be removed.
|
|
325
|
+
*
|
|
323
326
|
* @param {Treelike} treelike
|
|
324
327
|
* @returns {Promise<PlainObject|Array>}
|
|
325
328
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from "node:assert";
|
|
2
2
|
import { beforeEach, describe, mock, test } from "node:test";
|
|
3
|
-
import
|
|
3
|
+
import ExplorableSiteTree from "../src/ExplorableSiteTree.js";
|
|
4
4
|
import { Tree } from "../src/internal.js";
|
|
5
5
|
|
|
6
6
|
const textDecoder = new TextDecoder();
|
|
@@ -34,31 +34,31 @@ const mockResponses = {
|
|
|
34
34
|
},
|
|
35
35
|
};
|
|
36
36
|
|
|
37
|
-
describe("
|
|
37
|
+
describe("ExplorableSiteTree", () => {
|
|
38
38
|
beforeEach(() => {
|
|
39
39
|
mock.method(global, "fetch", mockFetch);
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
test("can get the keys of a tree", async () => {
|
|
43
|
-
const fixture = new
|
|
43
|
+
const fixture = new ExplorableSiteTree(mockHost);
|
|
44
44
|
const keys = await fixture.keys();
|
|
45
45
|
assert.deepEqual(Array.from(keys), ["about/", "index.html"]);
|
|
46
46
|
});
|
|
47
47
|
|
|
48
48
|
test("can get a plain value for a key", async () => {
|
|
49
|
-
const fixture = new
|
|
49
|
+
const fixture = new ExplorableSiteTree(mockHost);
|
|
50
50
|
const arrayBuffer = await fixture.get("index.html");
|
|
51
51
|
const text = textDecoder.decode(arrayBuffer);
|
|
52
52
|
assert.equal(text, "Home page");
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
test("getting an unsupported key returns undefined", async () => {
|
|
56
|
-
const fixture = new
|
|
56
|
+
const fixture = new ExplorableSiteTree(mockHost);
|
|
57
57
|
assert.equal(await fixture.get("xyz"), undefined);
|
|
58
58
|
});
|
|
59
59
|
|
|
60
60
|
test("getting a null/undefined key throws an exception", async () => {
|
|
61
|
-
const fixture = new
|
|
61
|
+
const fixture = new ExplorableSiteTree(mockHost);
|
|
62
62
|
await assert.rejects(async () => {
|
|
63
63
|
await fixture.get(null);
|
|
64
64
|
});
|
|
@@ -68,14 +68,14 @@ describe("OpenSiteTree", () => {
|
|
|
68
68
|
});
|
|
69
69
|
|
|
70
70
|
test("can return a new tree for a key that redirects", async () => {
|
|
71
|
-
const fixture = new
|
|
71
|
+
const fixture = new ExplorableSiteTree(mockHost);
|
|
72
72
|
const about = await fixture.get("about");
|
|
73
|
-
assert(about instanceof
|
|
73
|
+
assert(about instanceof ExplorableSiteTree);
|
|
74
74
|
assert.equal(about.href, "https://mock/about/");
|
|
75
75
|
});
|
|
76
76
|
|
|
77
77
|
test("can convert a site to a plain object", async () => {
|
|
78
|
-
const fixture = new
|
|
78
|
+
const fixture = new ExplorableSiteTree(mockHost);
|
|
79
79
|
// Convert buffers to strings.
|
|
80
80
|
const strings = Tree.map(fixture, (value) => textDecoder.decode(value));
|
|
81
81
|
assert.deepEqual(await Tree.plain(strings), {
|