@weborigami/async-tree 0.0.65 → 0.0.66-beta.2

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 (45) hide show
  1. package/main.js +2 -0
  2. package/package.json +4 -4
  3. package/src/BrowserFileTree.js +28 -6
  4. package/src/DeepMapTree.js +2 -2
  5. package/src/DeepObjectTree.js +6 -9
  6. package/src/FileTree.js +14 -10
  7. package/src/MapTree.js +27 -4
  8. package/src/ObjectTree.js +53 -6
  9. package/src/OpenSiteTree.js +41 -0
  10. package/src/SetTree.js +0 -6
  11. package/src/SiteTree.js +24 -85
  12. package/src/Tree.d.ts +1 -2
  13. package/src/Tree.js +40 -52
  14. package/src/jsonKeys.js +4 -37
  15. package/src/operations/cache.js +0 -4
  16. package/src/operations/deepMerge.js +7 -10
  17. package/src/operations/merge.js +7 -10
  18. package/src/trailingSlash.js +54 -0
  19. package/src/transforms/cachedKeyFunctions.js +72 -34
  20. package/src/transforms/keyFunctionsForExtensions.js +24 -10
  21. package/src/transforms/mapFn.js +11 -17
  22. package/src/transforms/regExpKeys.js +17 -12
  23. package/src/utilities.js +34 -6
  24. package/test/BrowserFileTree.test.js +28 -5
  25. package/test/DeepMapTree.test.js +17 -0
  26. package/test/DeepObjectTree.test.js +17 -7
  27. package/test/FileTree.test.js +14 -7
  28. package/test/MapTree.test.js +21 -0
  29. package/test/ObjectTree.test.js +16 -12
  30. package/test/OpenSiteTree.test.js +113 -0
  31. package/test/SiteTree.test.js +14 -49
  32. package/test/Tree.test.js +19 -39
  33. package/test/browser/assert.js +9 -0
  34. package/test/browser/index.html +4 -4
  35. package/test/calendarTree.test.js +1 -1
  36. package/test/fixtures/markdown/subfolder/README.md +1 -0
  37. package/test/jsonKeys.test.js +0 -9
  38. package/test/operations/cache.test.js +1 -1
  39. package/test/operations/merge.test.js +20 -1
  40. package/test/trailingSlash.test.js +36 -0
  41. package/test/transforms/cachedKeyFunctions.test.js +90 -0
  42. package/test/transforms/keyFunctionsForExtensions.test.js +7 -3
  43. package/test/transforms/mapFn.test.js +29 -20
  44. package/test/utilities.test.js +6 -2
  45. package/test/transforms/cachedKeyMaps.test.js +0 -41
@@ -1,4 +1,5 @@
1
1
  import { Tree } from "../internal.js";
2
+ import * as trailingSlash from "../trailingSlash.js";
2
3
 
3
4
  /**
4
5
  * A tree whose keys are strings interpreted as regular expressions.
@@ -57,25 +58,29 @@ export default async function regExpKeys(treelike) {
57
58
  continue;
58
59
  }
59
60
 
60
- // Construct regular expression.
61
- let text = key;
62
- if (!text.startsWith("^")) {
63
- text = "^" + text;
64
- }
65
- if (!text.endsWith("$")) {
66
- text = text + "$";
67
- }
68
- const regExp = new RegExp(text);
69
-
70
61
  // Get value.
71
62
  let value = await tree.get(key);
72
- if (Tree.isAsyncTree(value)) {
63
+
64
+ let regExp;
65
+ if (trailingSlash.has(key) || Tree.isAsyncTree(value)) {
66
+ const baseKey = trailingSlash.remove(key);
67
+ regExp = new RegExp("^" + baseKey + "/?$");
68
+ // Subtree
73
69
  value = regExpKeys(value);
74
70
  if (!value.parent) {
75
71
  value.parent = result;
76
72
  }
73
+ } else {
74
+ // Construct regular expression.
75
+ let text = key;
76
+ if (!text.startsWith("^")) {
77
+ text = "^" + text;
78
+ }
79
+ if (!text.endsWith("$")) {
80
+ text = text + "$";
81
+ }
82
+ regExp = new RegExp(text);
77
83
  }
78
-
79
84
  map.set(regExp, value);
80
85
  }
81
86
 
package/src/utilities.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Tree } from "./internal.js";
2
2
  import * as symbols from "./symbols.js";
3
+ import * as trailingSlash from "./trailingSlash.js";
3
4
 
4
5
  const textDecoder = new TextDecoder();
5
6
  const TypedArray = Object.getPrototypeOf(Uint8Array);
@@ -155,20 +156,35 @@ export function isUnpackable(obj) {
155
156
  }
156
157
 
157
158
  /**
158
- * Given a path like "/foo/bar/baz", return an array of keys like ["foo", "bar",
159
- * "baz"].
159
+ * Given a path like "/foo/bar/baz", return an array of keys like ["foo/",
160
+ * "bar/", "baz"].
160
161
  *
161
- * Leading slashes are ignored. Consecutive slashes or a trailing slash will be
162
- * represented by the empty string.
162
+ * Leading slashes are ignored. Consecutive slashes will be ignored. Trailing
163
+ * slashes are preserved.
163
164
  *
164
165
  * @param {string} pathname
165
166
  */
166
167
  export function keysFromPath(pathname) {
167
- const keys = pathname.split("/");
168
+ // Split the path at each slash
169
+ let keys = pathname.split("/");
168
170
  if (keys[0] === "") {
169
171
  // The path begins with a slash; drop that part.
170
172
  keys.shift();
171
173
  }
174
+ if (keys.at(-1) === "") {
175
+ // The path ends with a slash; drop that part.
176
+ keys.pop();
177
+ }
178
+ // Drop any empty keys
179
+ keys = keys.filter((key) => key !== "");
180
+ // Add the trailing slash back to all keys but the last
181
+ for (let i = 0; i < keys.length - 1; i++) {
182
+ keys[i] += "/";
183
+ }
184
+ // Add trailing slash to last key if path ended with a slash
185
+ if (keys.length > 0 && trailingSlash.has(pathname)) {
186
+ keys[keys.length - 1] += "/";
187
+ }
172
188
  return keys;
173
189
  }
174
190
 
@@ -283,7 +299,19 @@ export async function toPlainValue(input) {
283
299
  }
284
300
 
285
301
  function toBase64(object) {
286
- return Buffer.from(object).toString("base64");
302
+ if (typeof Buffer !== "undefined") {
303
+ // Node.js environment
304
+ return Buffer.from(object).toString("base64");
305
+ } else {
306
+ // Browser environment
307
+ let binary = "";
308
+ const bytes = new Uint8Array(object);
309
+ const len = bytes.byteLength;
310
+ for (let i = 0; i < len; i++) {
311
+ binary += String.fromCharCode(bytes[i]);
312
+ }
313
+ return btoa(binary);
314
+ }
287
315
  }
288
316
 
289
317
  /**
@@ -13,16 +13,14 @@ if (isBrowser) {
13
13
  "Alice.md",
14
14
  "Bob.md",
15
15
  "Carol.md",
16
+ "subfolder/",
16
17
  ]);
17
18
  });
18
19
 
19
20
  test("can get the value for a key", async () => {
20
21
  const fixture = await createFixture();
21
- assert.deepEqual(await strings(fixture), {
22
- "Alice.md": "Hello, **Alice**.",
23
- "Bob.md": "Hello, **Bob**.",
24
- "Carol.md": "Hello, **Carol**.",
25
- });
22
+ const buffer = await fixture.get("Alice.md");
23
+ assert.equal(text(buffer), "Hello, **Alice**.");
26
24
  });
27
25
 
28
26
  test("getting an unsupported key returns undefined", async () => {
@@ -30,6 +28,11 @@ if (isBrowser) {
30
28
  assert.equal(await fixture.get("xyz"), undefined);
31
29
  });
32
30
 
31
+ test("getting empty key returns undefined", async () => {
32
+ const fixture = await createFixture();
33
+ assert.equal(await fixture.get(""), undefined);
34
+ });
35
+
33
36
  test("getting a null/undefined key throws an exception", async () => {
34
37
  const fixture = await createFixture();
35
38
  await assert.rejects(async () => {
@@ -40,6 +43,20 @@ if (isBrowser) {
40
43
  });
41
44
  });
42
45
 
46
+ test("sets parent on subtrees", async () => {
47
+ const fixture = await createFixture();
48
+ const subfolder = await fixture.get("subfolder");
49
+ assert.equal(subfolder.parent, fixture);
50
+ });
51
+
52
+ test("can retrieve values with optional trailing slash", async () => {
53
+ const fixture = await createFixture();
54
+ assert(await fixture.get("Alice.md"));
55
+ assert(await fixture.get("Alice.md/"));
56
+ assert(await fixture.get("subfolder"));
57
+ assert(await fixture.get("subfolder/"));
58
+ });
59
+
43
60
  test("can set a value", async () => {
44
61
  const fixture = await createFixture();
45
62
 
@@ -59,6 +76,7 @@ if (isBrowser) {
59
76
  "Alice.md": "Goodbye, **Alice**.",
60
77
  "Carol.md": "Hello, **Carol**.",
61
78
  "David.md": "Hello, **David**.",
79
+ subfolder: {},
62
80
  });
63
81
  });
64
82
 
@@ -81,6 +99,7 @@ if (isBrowser) {
81
99
  more: {
82
100
  "Ellen.md": "Hello, **Ellen**.",
83
101
  },
102
+ subfolder: {},
84
103
  });
85
104
  });
86
105
  });
@@ -118,6 +137,10 @@ async function createFixture() {
118
137
  await createFile(subdirectory, "Bob.md", "Hello, **Bob**.");
119
138
  await createFile(subdirectory, "Carol.md", "Hello, **Carol**.");
120
139
 
140
+ await subdirectory.getDirectoryHandle("subfolder", {
141
+ create: true,
142
+ });
143
+
121
144
  return new BrowserFileTree(subdirectory);
122
145
  }
123
146
 
@@ -0,0 +1,17 @@
1
+ import assert from "node:assert";
2
+ import { describe, test } from "node:test";
3
+ import DeepMapTree from "../src/DeepMapTree.js";
4
+ import { Tree } from "../src/internal.js";
5
+
6
+ describe("DeepMapTree", () => {
7
+ test("returns a DeepMapTree for value that's a Map", async () => {
8
+ const tree = new DeepMapTree([
9
+ ["a", 1],
10
+ ["map", new Map([["b", 2]])],
11
+ ]);
12
+ const map = await tree.get("map");
13
+ assert.equal(map instanceof DeepMapTree, true);
14
+ assert.deepEqual(await Tree.plain(map), { b: 2 });
15
+ assert.equal(map.parent, tree);
16
+ });
17
+ });
@@ -4,13 +4,7 @@ import { DeepObjectTree, Tree } from "../src/internal.js";
4
4
 
5
5
  describe("DeepObjectTree", () => {
6
6
  test("returns an ObjectTree for value that's a plain sub-object or sub-array", async () => {
7
- const tree = new DeepObjectTree({
8
- a: 1,
9
- object: {
10
- b: 2,
11
- },
12
- array: [3],
13
- });
7
+ const tree = createFixture();
14
8
 
15
9
  const object = await tree.get("object");
16
10
  assert.equal(object instanceof DeepObjectTree, true);
@@ -22,4 +16,20 @@ describe("DeepObjectTree", () => {
22
16
  assert.deepEqual(await Tree.plain(array), [3]);
23
17
  assert.equal(array.parent, tree);
24
18
  });
19
+
20
+ test("adds trailing slashes to keys for subtrees including plain objects or arrays", async () => {
21
+ const tree = createFixture();
22
+ const keys = Array.from(await tree.keys());
23
+ assert.deepEqual(keys, ["a", "object/", "array/"]);
24
+ });
25
25
  });
26
+
27
+ function createFixture() {
28
+ return new DeepObjectTree({
29
+ a: 1,
30
+ object: {
31
+ b: 2,
32
+ },
33
+ array: [3],
34
+ });
35
+ }
@@ -18,6 +18,7 @@ describe("FileTree", async () => {
18
18
  "Alice.md",
19
19
  "Bob.md",
20
20
  "Carol.md",
21
+ "subfolder/",
21
22
  ]);
22
23
  });
23
24
 
@@ -33,6 +34,11 @@ describe("FileTree", async () => {
33
34
  assert.equal(await fixture.get("xyz"), undefined);
34
35
  });
35
36
 
37
+ test("getting empty key returns undefined", async () => {
38
+ const fixture = createFixture("fixtures/markdown");
39
+ assert.equal(await fixture.get(""), undefined);
40
+ });
41
+
36
42
  test("getting a null/undefined key throws an exception", async () => {
37
43
  const fixture = createFixture("fixtures/markdown");
38
44
  await assert.rejects(async () => {
@@ -43,17 +49,18 @@ describe("FileTree", async () => {
43
49
  });
44
50
  });
45
51
 
46
- test("sets parent on subtrees", async () => {
47
- const fixture = createFixture("fixtures");
48
- const markdown = await fixture.get("markdown");
49
- assert.equal(markdown.parent, fixture);
52
+ test("can retrieve values with optional trailing slash", async () => {
53
+ const fixture = createFixture("fixtures/markdown");
54
+ assert(await fixture.get("Alice.md"));
55
+ assert(await fixture.get("Alice.md/"));
56
+ assert(await fixture.get("subfolder"));
57
+ assert(await fixture.get("subfolder/"));
50
58
  });
51
59
 
52
- test("can indicate which values are subtrees", async () => {
60
+ test("sets parent on subtrees", async () => {
53
61
  const fixture = createFixture("fixtures");
54
- assert(await fixture.isKeyForSubtree("markdown"));
55
62
  const markdown = await fixture.get("markdown");
56
- assert(!(await markdown.isKeyForSubtree("a.txt")));
63
+ assert.equal(markdown.parent, fixture);
57
64
  });
58
65
 
59
66
  test("can write out a file via set()", async () => {
@@ -22,6 +22,27 @@ describe("MapTree", () => {
22
22
  assert.equal(more[symbols.parent], fixture);
23
23
  });
24
24
 
25
+ test("adds trailing slashes to keys for subtrees", async () => {
26
+ const tree = new MapTree([
27
+ ["a", 1],
28
+ ["subtree", new MapTree([["b", 2]])],
29
+ ]);
30
+ const keys = Array.from(await tree.keys());
31
+ assert.deepEqual(keys, ["a", "subtree/"]);
32
+ });
33
+
34
+ test("can retrieve values with optional trailing slash", async () => {
35
+ const subtree = new MapTree([["b", 2]]);
36
+ const tree = new MapTree([
37
+ ["a", 1],
38
+ ["subtree", subtree],
39
+ ]);
40
+ assert.equal(await tree.get("a"), 1);
41
+ assert.equal(await tree.get("a/"), 1);
42
+ assert.equal(await tree.get("subtree"), subtree);
43
+ assert.equal(await tree.get("subtree/"), subtree);
44
+ });
45
+
25
46
  test("getting an unsupported key returns undefined", async () => {
26
47
  const fixture = createFixture();
27
48
  assert.equal(await fixture.get("d"), undefined);
@@ -41,18 +41,21 @@ describe("ObjectTree", () => {
41
41
  c: 3,
42
42
  });
43
43
 
44
- // Update existing key.
44
+ // Update existing key
45
45
  await tree.set("a", 4);
46
46
 
47
- // New key.
48
- await tree.set("d", 5);
49
-
50
- // Delete key.
47
+ // Delete key
51
48
  await tree.set("b", undefined);
52
49
 
50
+ // Overwrite key with trailing slash
51
+ await tree.set("c/", {});
52
+
53
+ // New key
54
+ await tree.set("d", 5);
55
+
53
56
  assert.deepEqual(await Tree.entries(tree), [
54
57
  ["a", 4],
55
- ["c", 3],
58
+ ["c/", {}],
56
59
  ["d", 5],
57
60
  ]);
58
61
  });
@@ -106,7 +109,7 @@ describe("ObjectTree", () => {
106
109
  assert.equal(more.parent, fixture);
107
110
  });
108
111
 
109
- test("isKeyForSubtree() indicates which values are subtrees", async () => {
112
+ test("adds trailing slashes to keys for subtrees", async () => {
110
113
  const tree = new ObjectTree({
111
114
  a1: 1,
112
115
  a2: new ObjectTree({
@@ -118,21 +121,22 @@ describe("ObjectTree", () => {
118
121
  }),
119
122
  });
120
123
  const keys = Array.from(await tree.keys());
121
- const subtrees = await Promise.all(
122
- keys.map(async (key) => await tree.isKeyForSubtree(key))
123
- );
124
- assert.deepEqual(subtrees, [false, true, false, true]);
124
+ assert.deepEqual(keys, ["a1", "a2/", "a3", "a4/"]);
125
125
  });
126
126
 
127
- test("returns an async tree value as is", async () => {
127
+ test("can retrieve values with optional trailing slash", async () => {
128
128
  const subtree = {
129
129
  async get(key) {},
130
130
  async keys() {},
131
131
  };
132
132
  const tree = new ObjectTree({
133
+ a: 1,
133
134
  subtree,
134
135
  });
136
+ assert.equal(await tree.get("a"), 1);
137
+ assert.equal(await tree.get("a/"), 1);
135
138
  assert.equal(await tree.get("subtree"), subtree);
139
+ assert.equal(await tree.get("subtree/"), subtree);
136
140
  });
137
141
 
138
142
  test("method on an object is bound to the object", async () => {
@@ -0,0 +1,113 @@
1
+ import assert from "node:assert";
2
+ import { beforeEach, describe, mock, test } from "node:test";
3
+ import OpenSiteTree from "../src/OpenSiteTree.js";
4
+ import { Tree } from "../src/internal.js";
5
+
6
+ const textDecoder = new TextDecoder();
7
+ const textEncoder = new TextEncoder();
8
+
9
+ const mockHost = "https://mock";
10
+
11
+ const mockResponses = {
12
+ "/.keys.json": {
13
+ data: JSON.stringify(["about/", "index.html"]),
14
+ },
15
+ "/about": {
16
+ redirected: true,
17
+ status: 301,
18
+ url: "https://mock/about/",
19
+ },
20
+ "/about/.keys.json": {
21
+ data: JSON.stringify(["Alice.html", "Bob.html", "Carol.html"]),
22
+ },
23
+ "/about/Alice.html": {
24
+ data: "Hello, Alice!",
25
+ },
26
+ "/about/Bob.html": {
27
+ data: "Hello, Bob!",
28
+ },
29
+ "/about/Carol.html": {
30
+ data: "Hello, Carol!",
31
+ },
32
+ "/index.html": {
33
+ data: "Home page",
34
+ },
35
+ };
36
+
37
+ describe("OpenSiteTree", () => {
38
+ beforeEach(() => {
39
+ mock.method(global, "fetch", mockFetch);
40
+ });
41
+
42
+ test("can get the keys of a tree", async () => {
43
+ const fixture = new OpenSiteTree(mockHost);
44
+ const keys = await fixture.keys();
45
+ assert.deepEqual(Array.from(keys), ["about/", "index.html"]);
46
+ });
47
+
48
+ test("can get a plain value for a key", async () => {
49
+ const fixture = new OpenSiteTree(mockHost);
50
+ const arrayBuffer = await fixture.get("index.html");
51
+ const text = textDecoder.decode(arrayBuffer);
52
+ assert.equal(text, "Home page");
53
+ });
54
+
55
+ test("getting an unsupported key returns undefined", async () => {
56
+ const fixture = new OpenSiteTree(mockHost);
57
+ assert.equal(await fixture.get("xyz"), undefined);
58
+ });
59
+
60
+ test("getting a null/undefined key throws an exception", async () => {
61
+ const fixture = new OpenSiteTree(mockHost);
62
+ await assert.rejects(async () => {
63
+ await fixture.get(null);
64
+ });
65
+ await assert.rejects(async () => {
66
+ await fixture.get(undefined);
67
+ });
68
+ });
69
+
70
+ test("can return a new tree for a key that redirects", async () => {
71
+ const fixture = new OpenSiteTree(mockHost);
72
+ const about = await fixture.get("about");
73
+ assert(about instanceof OpenSiteTree);
74
+ assert.equal(about.href, "https://mock/about/");
75
+ });
76
+
77
+ test("can convert a site to a plain object", async () => {
78
+ const fixture = new OpenSiteTree(mockHost);
79
+ // Convert buffers to strings.
80
+ const strings = Tree.map(fixture, (value) => textDecoder.decode(value));
81
+ assert.deepEqual(await Tree.plain(strings), {
82
+ about: {
83
+ "Alice.html": "Hello, Alice!",
84
+ "Bob.html": "Hello, Bob!",
85
+ "Carol.html": "Hello, Carol!",
86
+ },
87
+ "index.html": "Home page",
88
+ });
89
+ });
90
+ });
91
+
92
+ async function mockFetch(href) {
93
+ if (!href.startsWith(mockHost)) {
94
+ return { status: 404 };
95
+ }
96
+ const path = href.slice(mockHost.length);
97
+ const mockedResponse = mockResponses[path];
98
+ if (mockedResponse) {
99
+ return Object.assign(
100
+ {
101
+ arrayBuffer: () => textEncoder.encode(mockedResponse.data).buffer,
102
+ ok: true,
103
+ status: 200,
104
+ text: () => mockedResponse.data,
105
+ },
106
+ mockedResponse
107
+ );
108
+ }
109
+ return {
110
+ ok: false,
111
+ status: 404,
112
+ };
113
+ }
@@ -1,7 +1,6 @@
1
1
  import assert from "node:assert";
2
2
  import { beforeEach, describe, mock, test } from "node:test";
3
3
  import SiteTree from "../src/SiteTree.js";
4
- import { Tree } from "../src/internal.js";
5
4
 
6
5
  const textDecoder = new TextDecoder();
7
6
  const textEncoder = new TextEncoder();
@@ -9,17 +8,11 @@ const textEncoder = new TextEncoder();
9
8
  const mockHost = "https://mock";
10
9
 
11
10
  const mockResponses = {
12
- "/.keys.json": {
13
- data: JSON.stringify(["about/"]),
14
- },
15
11
  "/about": {
16
12
  redirected: true,
17
13
  status: 301,
18
14
  url: "https://mock/about/",
19
15
  },
20
- "/about/.keys.json": {
21
- data: JSON.stringify(["Alice.html", "Bob.html", "Carol.html"]),
22
- },
23
16
  "/about/Alice.html": {
24
17
  data: "Hello, Alice!",
25
18
  },
@@ -29,6 +22,9 @@ const mockResponses = {
29
22
  "/about/Carol.html": {
30
23
  data: "Hello, Carol!",
31
24
  },
25
+ "/index.html": {
26
+ data: "Home page",
27
+ },
32
28
  };
33
29
 
34
30
  describe("SiteTree", () => {
@@ -36,29 +32,24 @@ describe("SiteTree", () => {
36
32
  mock.method(global, "fetch", mockFetch);
37
33
  });
38
34
 
39
- test("resolve() returns a new SiteTree for the given relative route", () => {
35
+ test("returns an empty array as the keys of a tree", async () => {
40
36
  const fixture = new SiteTree(mockHost);
41
- const about = fixture.resolve("about");
42
- assert.equal(about.href, "https://mock/about/");
37
+ const keys = await fixture.keys();
38
+ assert.deepEqual(Array.from(keys), []);
43
39
  });
44
40
 
45
- test("can get the keys of the tree", async () => {
41
+ test("can get a plain value for a key", async () => {
46
42
  const fixture = new SiteTree(mockHost);
47
- const about = fixture.resolve("about");
48
- const keys = await about.keys();
49
- assert.deepEqual(Array.from(keys), [
50
- "Alice.html",
51
- "Bob.html",
52
- "Carol.html",
53
- ]);
43
+ const arrayBuffer = await fixture.get("index.html");
44
+ const text = textDecoder.decode(arrayBuffer);
45
+ assert.equal(text, "Home page");
54
46
  });
55
47
 
56
- test("can get the value for a key", async () => {
48
+ test("immediately return a new tree for a key with a trailing slash", async () => {
57
49
  const fixture = new SiteTree(mockHost);
58
- const about = fixture.resolve("about");
59
- const arrayBuffer = await about.get("Alice.html");
60
- const text = textDecoder.decode(arrayBuffer);
61
- assert.equal(text, "Hello, Alice!");
50
+ const about = await fixture.get("about/");
51
+ assert(about instanceof SiteTree);
52
+ assert.equal(about.href, "https://mock/about/");
62
53
  });
63
54
 
64
55
  test("getting an unsupported key returns undefined", async () => {
@@ -75,32 +66,6 @@ describe("SiteTree", () => {
75
66
  await fixture.get(undefined);
76
67
  });
77
68
  });
78
-
79
- test("a redirect on a site with keys returns a SiteTree for the new URL", async () => {
80
- const fixture = new SiteTree(mockHost);
81
- const about = await fixture.get("about");
82
- assert.equal(about.href, "https://mock/about/");
83
- });
84
-
85
- test("can determine whether a key is for a subtree", async () => {
86
- const fixture = new SiteTree(mockHost);
87
- assert.equal(await fixture.isKeyForSubtree("about"), true);
88
- const about = fixture.resolve("about");
89
- assert.equal(await about.isKeyForSubtree("Alice.html"), false);
90
- });
91
-
92
- test("can convert a SiteGraph to a plain object", async () => {
93
- const fixture = new SiteTree(mockHost);
94
- // Convert buffers to strings.
95
- const strings = Tree.map(fixture, (value) => textDecoder.decode(value));
96
- assert.deepEqual(await Tree.plain(strings), {
97
- about: {
98
- "Alice.html": "Hello, Alice!",
99
- "Bob.html": "Hello, Bob!",
100
- "Carol.html": "Hello, Carol!",
101
- },
102
- });
103
- });
104
69
  });
105
70
 
106
71
  async function mockFetch(href) {