@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-beta.2",
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-beta.2"
14
+ "@weborigami/types": "0.0.66"
15
15
  },
16
16
  "scripts": {
17
17
  "test": "node --test --test-reporter=spec",
@@ -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
- export default class OpenSiteTree extends SiteTree {
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?: true, parent?: AsyncTree|null }} [options]
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 = options.deep ? new DeepObjectTree(object) : new ObjectTree(object);
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 OpenSiteTree from "../src/OpenSiteTree.js";
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("OpenSiteTree", () => {
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 OpenSiteTree(mockHost);
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 OpenSiteTree(mockHost);
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 OpenSiteTree(mockHost);
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 OpenSiteTree(mockHost);
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 OpenSiteTree(mockHost);
71
+ const fixture = new ExplorableSiteTree(mockHost);
72
72
  const about = await fixture.get("about");
73
- assert(about instanceof OpenSiteTree);
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 OpenSiteTree(mockHost);
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), {