@weborigami/async-tree 0.0.66-beta.1 → 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 +0 -1
  13. package/src/Tree.js +18 -38
  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,7 +1,7 @@
1
1
  import assert from "node:assert";
2
2
  import { describe, test } from "node:test";
3
- import { toPlainValue } from "../main.js";
4
3
  import calendarTree from "../src/calendarTree.js";
4
+ import { toPlainValue } from "../src/utilities.js";
5
5
 
6
6
  describe("calendarTree", () => {
7
7
  test("without a start or end, returns a tree for today", async () => {
@@ -0,0 +1 @@
1
+ This file exists to force the creation of the parent folder.
@@ -4,15 +4,6 @@ import { describe, test } from "node:test";
4
4
  import * as jsonKeys from "../src/jsonKeys.js";
5
5
 
6
6
  describe("jsonKeys", () => {
7
- test("parses JSON Keys", async () => {
8
- const json = '["index.html","about/"]';
9
- const parsed = jsonKeys.parse(json);
10
- assert.deepStrictEqual(parsed, {
11
- "index.html": false,
12
- about: true,
13
- });
14
- });
15
-
16
7
  test("stringifies JSON Keys", async () => {
17
8
  const tree = new DeepObjectTree({
18
9
  about: {},
@@ -19,7 +19,7 @@ describe("cache", () => {
19
19
  );
20
20
 
21
21
  const keys = [...(await fixture.keys())];
22
- assert.deepEqual(keys, ["a", "b", "c", "more"]);
22
+ assert.deepEqual(keys, ["a", "b", "c", "more/"]);
23
23
 
24
24
  assert.equal(await objectCache.get("a"), undefined);
25
25
  assert.equal(await fixture.get("a"), 1);
@@ -1,6 +1,6 @@
1
1
  import assert from "node:assert";
2
2
  import { describe, test } from "node:test";
3
- import { Tree } from "../../src/internal.js";
3
+ import { DeepObjectTree, ObjectTree, Tree } from "../../src/internal.js";
4
4
  import merge from "../../src/operations/merge.js";
5
5
  import * as symbols from "../../src/symbols.js";
6
6
 
@@ -42,4 +42,23 @@ describe("merge", () => {
42
42
  const b = await fixture.get("b");
43
43
  assert.equal(b[symbols.parent], fixture);
44
44
  });
45
+
46
+ test("subtree can overwrite a leaf node", async () => {
47
+ const fixture = merge(
48
+ new ObjectTree({
49
+ a: 1,
50
+ }),
51
+ new DeepObjectTree({
52
+ a: {
53
+ b: 2,
54
+ },
55
+ })
56
+ );
57
+ assert.deepEqual([...(await fixture.keys())], ["a/"]);
58
+ assert.deepEqual(await Tree.plain(fixture), {
59
+ a: {
60
+ b: 2,
61
+ },
62
+ });
63
+ });
45
64
  });
@@ -0,0 +1,36 @@
1
+ import assert from "node:assert";
2
+ import { describe, test } from "node:test";
3
+ import { add, has, remove, toggle } from "../src/trailingSlash.js";
4
+
5
+ describe("trailingSlash", () => {
6
+ test("add adds a trailing slash to a string key for a truthy value", () => {
7
+ assert.equal(add("key"), "key/");
8
+ assert.equal(add("key/"), "key/");
9
+ assert.equal(add(1), 1);
10
+ });
11
+
12
+ test("has returns true if a string key has a trailing slash", () => {
13
+ assert.equal(has("key/"), true);
14
+ assert.equal(has("key"), false);
15
+ assert.equal(has(1), false);
16
+ });
17
+
18
+ test("remove removes a trailing slash from a string key", () => {
19
+ assert.equal(remove("key/"), "key");
20
+ assert.equal(remove("key"), "key");
21
+ assert.equal(remove(1), 1);
22
+ });
23
+
24
+ test("toggle removes a slash if present, adds one if not", () => {
25
+ assert.equal(toggle("key/"), "key");
26
+ assert.equal(toggle("key"), "key/");
27
+ assert.equal(toggle(1), 1);
28
+ });
29
+
30
+ test("toggle can force toggling on or off", () => {
31
+ assert.equal(toggle("key/", false), "key");
32
+ assert.equal(toggle("key/", true), "key/");
33
+ assert.equal(toggle("key", false), "key");
34
+ assert.equal(toggle("key", true), "key/");
35
+ });
36
+ });
@@ -0,0 +1,90 @@
1
+ import assert from "node:assert";
2
+ import { describe, test } from "node:test";
3
+ import { DeepObjectTree, ObjectTree } from "../../src/internal.js";
4
+ import cachedKeyFunctions from "../../src/transforms/cachedKeyFunctions.js";
5
+
6
+ describe("cachedKeyFunctions", () => {
7
+ test("maps keys with caching", async () => {
8
+ const tree = new ObjectTree({
9
+ a: "letter a",
10
+ b: "letter b",
11
+ });
12
+
13
+ let callCount = 0;
14
+ const addUnderscore = async (sourceKey, tree) => {
15
+ callCount++;
16
+ return `_${sourceKey}`;
17
+ };
18
+
19
+ const { inverseKey, key } = cachedKeyFunctions(addUnderscore);
20
+
21
+ assert.equal(await inverseKey("_a", tree), "a"); // Cache miss
22
+ assert.equal(callCount, 1);
23
+ assert.equal(await inverseKey("_a", tree), "a");
24
+ assert.equal(callCount, 1);
25
+ assert.equal(await inverseKey("_b", tree), "b"); // Cache miss
26
+ assert.equal(callCount, 2);
27
+
28
+ assert.equal(await key("a", tree), "_a");
29
+ assert.equal(await key("a", tree), "_a");
30
+ assert.equal(await key("b", tree), "_b");
31
+ assert.equal(callCount, 2);
32
+
33
+ // `c` isn't in tree, so we should get undefined.
34
+ assert.equal(await inverseKey("_c", tree), undefined);
35
+ // But key mapping is still possible.
36
+ assert.equal(await key("c", tree), "_c");
37
+ // And now we have a cache hit.
38
+ assert.equal(await inverseKey("_c", tree), "c");
39
+ assert.equal(callCount, 3);
40
+ });
41
+
42
+ test("maps keys with caching and deep option", async () => {
43
+ const tree = new DeepObjectTree({
44
+ a: "letter a",
45
+ b: {
46
+ c: "letter c",
47
+ },
48
+ });
49
+
50
+ let callCount = 0;
51
+ const addUnderscore = async (sourceKey, tree) => {
52
+ callCount++;
53
+ return `_${sourceKey}`;
54
+ };
55
+
56
+ const { inverseKey, key } = cachedKeyFunctions(addUnderscore, true);
57
+
58
+ assert.equal(await inverseKey("_a", tree), "a"); // Cache miss
59
+ assert.equal(await inverseKey("_a", tree), "a");
60
+ assert.equal(callCount, 1);
61
+
62
+ // Subtree key left alone
63
+ assert.equal(await inverseKey("_b", tree), undefined);
64
+ assert.equal(await inverseKey("b", tree), "b");
65
+ assert.equal(await inverseKey("b/", tree), "b/");
66
+ assert.equal(callCount, 1);
67
+
68
+ assert.equal(await key("a", tree), "_a");
69
+ assert.equal(await key("a", tree), "_a");
70
+ assert.equal(callCount, 1);
71
+
72
+ assert.equal(await key("b/", tree), "b/");
73
+ assert.equal(await key("b", tree), "b");
74
+ assert.equal(callCount, 1);
75
+ });
76
+
77
+ test("preserves trailing slashes", async () => {
78
+ const tree = new ObjectTree({
79
+ a: "letter a",
80
+ });
81
+ const addUnderscore = async (sourceKey) => `_${sourceKey}`;
82
+ const { inverseKey, key } = cachedKeyFunctions(addUnderscore);
83
+
84
+ assert.equal(await key("a/", tree), "_a/");
85
+ assert.equal(await key("a", tree), "_a");
86
+
87
+ assert.equal(await inverseKey("_a/", tree), "a/");
88
+ assert.equal(await inverseKey("_a", tree), "a");
89
+ });
90
+ });
@@ -10,18 +10,22 @@ describe("keyMapsForExtensions", () => {
10
10
  sourceExtension: "txt",
11
11
  });
12
12
  assert.equal(await inverseKey("file.txt"), "file.txt");
13
+ assert.equal(await inverseKey("file.txt/"), "file.txt");
13
14
  assert.equal(await key("file.txt"), "file.txt");
15
+ assert.equal(await key("file.txt/"), "file.txt/");
14
16
  assert.equal(await inverseKey("file.foo"), undefined);
15
17
  assert.equal(await key("file.foo"), undefined);
16
18
  });
17
19
 
18
20
  test("returns key functions that can map extensions", async () => {
19
21
  const { inverseKey, key } = keyFunctionsForExtensions({
20
- resultExtension: "html",
22
+ resultExtension: "json",
21
23
  sourceExtension: "md",
22
24
  });
23
- assert.equal(await inverseKey("file.html"), "file.md");
24
- assert.equal(await key("file.md"), "file.html");
25
+ assert.equal(await inverseKey("file.json"), "file.md");
26
+ assert.equal(await inverseKey("file.json/"), "file.md");
27
+ assert.equal(await key("file.md"), "file.json");
28
+ assert.equal(await key("file.md/"), "file.json/");
25
29
  assert.equal(await inverseKey("file.foo"), undefined);
26
30
  assert.equal(await key("file.foo"), undefined);
27
31
  });
@@ -2,6 +2,7 @@ import assert from "node:assert";
2
2
  import { describe, test } from "node:test";
3
3
  import FunctionTree from "../../src/FunctionTree.js";
4
4
  import { DeepObjectTree, ObjectTree, Tree } from "../../src/internal.js";
5
+ import * as trailingSlash from "../../src/trailingSlash.js";
5
6
  import mapFn from "../../src/transforms/mapFn.js";
6
7
 
7
8
  describe("mapFn", () => {
@@ -59,11 +60,11 @@ describe("mapFn", () => {
59
60
  a: "letter a",
60
61
  b: "letter b",
61
62
  };
62
- const doubleKeys = mapFn({
63
- key: async (sourceKey, tree) => `_${sourceKey}`,
64
- inverseKey: async (resultKey, tree) => resultKey.slice(1),
63
+ const underscopeKeys = mapFn({
64
+ key: addUnderscore,
65
+ inverseKey: removeUnderscore,
65
66
  });
66
- const mapped = doubleKeys(tree);
67
+ const mapped = underscopeKeys(tree);
67
68
  assert.deepEqual(await Tree.plain(mapped), {
68
69
  _a: "letter a",
69
70
  _b: "letter b",
@@ -75,12 +76,12 @@ describe("mapFn", () => {
75
76
  a: "letter a",
76
77
  b: "letter b",
77
78
  };
78
- const doubleKeysUppercaseValues = mapFn({
79
- key: async (sourceKey, tree) => `_${sourceKey}`,
80
- inverseKey: async (resultKey, tree) => resultKey.slice(1),
79
+ const underscoreKeysUppercaseValues = mapFn({
80
+ key: addUnderscore,
81
+ inverseKey: removeUnderscore,
81
82
  value: async (sourceValue, sourceKey, tree) => sourceValue.toUpperCase(),
82
83
  });
83
- const mapped = doubleKeysUppercaseValues(tree);
84
+ const mapped = underscoreKeysUppercaseValues(tree);
84
85
  assert.deepEqual(await Tree.plain(mapped), {
85
86
  _a: "LETTER A",
86
87
  _b: "LETTER B",
@@ -94,12 +95,12 @@ describe("mapFn", () => {
94
95
  b: "letter b",
95
96
  },
96
97
  };
97
- const doubleKeys = mapFn({
98
+ const underscopeKeys = mapFn({
98
99
  key: async (sourceKey, tree) => `_${sourceKey}`,
99
100
  inverseKey: async (resultKey, tree) => resultKey.slice(1),
100
101
  value: async (sourceValue, sourceKey, tree) => sourceKey,
101
102
  });
102
- const mapped = doubleKeys(tree);
103
+ const mapped = underscopeKeys(tree);
103
104
  assert.deepEqual(await Tree.plain(mapped), {
104
105
  _a: "a",
105
106
  _more: "more",
@@ -108,8 +109,8 @@ describe("mapFn", () => {
108
109
 
109
110
  test("value can provide a default key and inverse key functions", async () => {
110
111
  const uppercase = (s) => s.toUpperCase();
111
- uppercase.key = (sourceKey) => `_${sourceKey}`;
112
- uppercase.inverseKey = (resultKey) => resultKey.slice(1);
112
+ uppercase.key = addUnderscore;
113
+ uppercase.inverseKey = removeUnderscore;
113
114
  const tree = {
114
115
  a: "letter a",
115
116
  b: "letter b",
@@ -148,12 +149,12 @@ describe("mapFn", () => {
148
149
  b: "letter b",
149
150
  },
150
151
  });
151
- const doubleKeys = mapFn({
152
+ const underscoreKeys = mapFn({
152
153
  deep: true,
153
- key: async (sourceKey, tree) => `_${sourceKey}`,
154
- inverseKey: async (resultKey, tree) => resultKey.slice(1),
154
+ key: addUnderscore,
155
+ inverseKey: removeUnderscore,
155
156
  });
156
- const mapped = doubleKeys(tree);
157
+ const mapped = underscoreKeys(tree);
157
158
  assert.deepEqual(await Tree.plain(mapped), {
158
159
  _a: "letter a",
159
160
  more: {
@@ -169,13 +170,13 @@ describe("mapFn", () => {
169
170
  b: "letter b",
170
171
  },
171
172
  });
172
- const doubleKeysUppercaseValues = mapFn({
173
+ const underscoreKeysUppercaseValues = mapFn({
173
174
  deep: true,
174
- key: async (sourceKey, tree) => `_${sourceKey}`,
175
- inverseKey: async (resultKey, tree) => resultKey.slice(1),
175
+ key: addUnderscore,
176
+ inverseKey: removeUnderscore,
176
177
  value: async (sourceValue, sourceKey, tree) => sourceValue.toUpperCase(),
177
178
  });
178
- const mapped = doubleKeysUppercaseValues(tree);
179
+ const mapped = underscoreKeysUppercaseValues(tree);
179
180
  assert.deepEqual(await Tree.plain(mapped), {
180
181
  _a: "LETTER A",
181
182
  more: {
@@ -201,3 +202,11 @@ describe("mapFn", () => {
201
202
  assert(!flag);
202
203
  });
203
204
  });
205
+
206
+ function addUnderscore(key) {
207
+ return `_${key}`;
208
+ }
209
+
210
+ function removeUnderscore(key) {
211
+ return trailingSlash.has(key) ? key : key.slice(1);
212
+ }
@@ -41,8 +41,12 @@ describe("utilities", () => {
41
41
  });
42
42
 
43
43
  test("keysFromPath() returns the keys from a slash-separated path", () => {
44
- assert.deepEqual(utilities.keysFromPath("a/b/c"), ["a", "b", "c"]);
45
- assert.deepEqual(utilities.keysFromPath("foo/"), ["foo", ""]);
44
+ assert.deepEqual(utilities.keysFromPath(""), []);
45
+ assert.deepEqual(utilities.keysFromPath("/"), []);
46
+ assert.deepEqual(utilities.keysFromPath("a/b/c"), ["a/", "b/", "c"]);
47
+ assert.deepEqual(utilities.keysFromPath("a/b/c/"), ["a/", "b/", "c/"]);
48
+ assert.deepEqual(utilities.keysFromPath("/foo/"), ["foo/"]);
49
+ assert.deepEqual(utilities.keysFromPath("a///b"), ["a/", "b"]);
46
50
  });
47
51
 
48
52
  test("naturalOrder compares strings in natural order", () => {
@@ -1,41 +0,0 @@
1
- import assert from "node:assert";
2
- import { describe, test } from "node:test";
3
- import { ObjectTree } from "../../src/internal.js";
4
- import cachedKeyFunctions from "../../src/transforms/cachedKeyFunctions.js";
5
-
6
- describe("cachedKeyFunctions", () => {
7
- test("maps keys with caching", async () => {
8
- const tree = new ObjectTree({
9
- a: "letter a",
10
- b: "letter b",
11
- });
12
-
13
- let callCount = 0;
14
- const underscoreKeys = async (sourceKey, tree) => {
15
- callCount++;
16
- return `_${sourceKey}`;
17
- };
18
-
19
- const { inverseKey, key } = cachedKeyFunctions(underscoreKeys);
20
-
21
- assert.equal(await inverseKey("_a", tree), "a"); // Cache miss
22
- assert.equal(callCount, 1);
23
- assert.equal(await inverseKey("_a", tree), "a");
24
- assert.equal(callCount, 1);
25
- assert.equal(await inverseKey("_b", tree), "b"); // Cache miss
26
- assert.equal(callCount, 2);
27
-
28
- assert.equal(await key("a", tree), "_a");
29
- assert.equal(await key("a", tree), "_a");
30
- assert.equal(await key("b", tree), "_b");
31
- assert.equal(callCount, 2);
32
-
33
- // `c` isn't in tree, so we should get undefined.
34
- assert.equal(await inverseKey("_c", tree), undefined);
35
- // But key mapping is still possible.
36
- assert.equal(await key("c", tree), "_c");
37
- // And now we have a cache hit.
38
- assert.equal(await inverseKey("_c", tree), "c");
39
- assert.equal(callCount, 3);
40
- });
41
- });