@weborigami/async-tree 0.5.8 → 0.6.1

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 (182) hide show
  1. package/browser.js +1 -1
  2. package/index.ts +43 -35
  3. package/main.js +1 -2
  4. package/package.json +4 -7
  5. package/shared.js +74 -12
  6. package/src/Tree.js +11 -2
  7. package/src/drivers/AsyncMap.js +237 -0
  8. package/src/drivers/{BrowserFileTree.js → BrowserFileMap.js} +54 -38
  9. package/src/drivers/{calendarTree.js → CalendarMap.js} +80 -63
  10. package/src/drivers/ConstantMap.js +28 -0
  11. package/src/drivers/{ExplorableSiteTree.js → ExplorableSiteMap.js} +7 -7
  12. package/src/drivers/FileMap.js +238 -0
  13. package/src/drivers/{FunctionTree.js → FunctionMap.js} +19 -22
  14. package/src/drivers/ObjectMap.js +151 -0
  15. package/src/drivers/SetMap.js +13 -0
  16. package/src/drivers/{SiteTree.js → SiteMap.js} +17 -20
  17. package/src/drivers/SyncMap.js +260 -0
  18. package/src/jsonKeys.d.ts +2 -2
  19. package/src/jsonKeys.js +20 -5
  20. package/src/operations/addNextPrevious.js +35 -36
  21. package/src/operations/assign.js +27 -23
  22. package/src/operations/cache.js +30 -36
  23. package/src/operations/cachedKeyFunctions.js +1 -1
  24. package/src/operations/calendar.js +5 -0
  25. package/src/operations/child.js +35 -0
  26. package/src/operations/clear.js +13 -12
  27. package/src/operations/constant.js +5 -0
  28. package/src/operations/deepEntries.js +23 -0
  29. package/src/operations/deepMap.js +9 -9
  30. package/src/operations/deepMerge.js +36 -25
  31. package/src/operations/deepReverse.js +23 -16
  32. package/src/operations/deepTake.js +7 -7
  33. package/src/operations/deepText.js +4 -4
  34. package/src/operations/deepValues.js +3 -6
  35. package/src/operations/deepValuesIterator.js +11 -11
  36. package/src/operations/delete.js +8 -12
  37. package/src/operations/entries.js +17 -10
  38. package/src/operations/filter.js +9 -7
  39. package/src/operations/first.js +12 -10
  40. package/src/operations/forEach.js +10 -13
  41. package/src/operations/from.js +30 -39
  42. package/src/operations/globKeys.js +22 -17
  43. package/src/operations/group.js +2 -2
  44. package/src/operations/groupBy.js +24 -22
  45. package/src/operations/has.js +7 -9
  46. package/src/operations/indent.js +2 -2
  47. package/src/operations/inners.js +19 -15
  48. package/src/operations/invokeFunctions.js +22 -10
  49. package/src/operations/isAsyncMutableTree.js +5 -12
  50. package/src/operations/isAsyncTree.js +5 -20
  51. package/src/operations/isMap.js +39 -0
  52. package/src/operations/isMaplike.js +34 -0
  53. package/src/operations/isReadOnlyMap.js +14 -0
  54. package/src/operations/isTraversable.js +3 -3
  55. package/src/operations/isTreelike.js +5 -30
  56. package/src/operations/json.js +4 -12
  57. package/src/operations/keys.js +17 -8
  58. package/src/operations/length.js +9 -8
  59. package/src/operations/map.js +28 -30
  60. package/src/operations/mapExtension.js +20 -16
  61. package/src/operations/mapReduce.js +38 -24
  62. package/src/operations/mask.js +54 -29
  63. package/src/operations/match.js +13 -9
  64. package/src/operations/merge.js +43 -35
  65. package/src/operations/paginate.js +26 -18
  66. package/src/operations/parent.js +7 -7
  67. package/src/operations/paths.js +20 -22
  68. package/src/operations/plain.js +6 -6
  69. package/src/operations/reduce.js +16 -0
  70. package/src/operations/regExpKeys.js +21 -12
  71. package/src/operations/reverse.js +21 -15
  72. package/src/operations/root.js +6 -5
  73. package/src/operations/scope.js +31 -26
  74. package/src/operations/set.js +20 -0
  75. package/src/operations/shuffle.js +23 -16
  76. package/src/operations/size.js +13 -0
  77. package/src/operations/sort.js +55 -40
  78. package/src/operations/sync.js +14 -0
  79. package/src/operations/take.js +23 -11
  80. package/src/operations/text.js +4 -4
  81. package/src/operations/toFunction.js +7 -7
  82. package/src/operations/traverse.js +4 -4
  83. package/src/operations/traverseOrThrow.js +18 -9
  84. package/src/operations/traversePath.js +2 -2
  85. package/src/operations/values.js +18 -9
  86. package/src/operations/withKeys.js +22 -16
  87. package/src/symbols.js +1 -0
  88. package/src/utilities/castArraylike.js +24 -13
  89. package/src/utilities/getMapArgument.js +38 -0
  90. package/src/utilities/getParent.js +2 -2
  91. package/src/utilities/isStringlike.js +7 -5
  92. package/src/utilities/setParent.js +7 -7
  93. package/src/utilities/toFunction.js +2 -2
  94. package/src/utilities/toPlainValue.js +21 -19
  95. package/test/SampleAsyncMap.js +34 -0
  96. package/test/browser/assert.js +20 -0
  97. package/test/browser/index.html +53 -21
  98. package/test/drivers/AsyncMap.test.js +119 -0
  99. package/test/drivers/{BrowserFileTree.test.js → BrowserFileMap.test.js} +50 -33
  100. package/test/drivers/{calendarTree.test.js → CalendarMap.test.js} +17 -19
  101. package/test/drivers/ConstantMap.test.js +15 -0
  102. package/test/drivers/{ExplorableSiteTree.test.js → ExplorableSiteMap.test.js} +29 -14
  103. package/test/drivers/FileMap.test.js +156 -0
  104. package/test/drivers/FunctionMap.test.js +56 -0
  105. package/test/drivers/ObjectMap.test.js +194 -0
  106. package/test/drivers/SetMap.test.js +35 -0
  107. package/test/drivers/{SiteTree.test.js → SiteMap.test.js} +14 -10
  108. package/test/drivers/SyncMap.test.js +335 -0
  109. package/test/jsonKeys.test.js +18 -6
  110. package/test/operations/addNextPrevious.test.js +3 -2
  111. package/test/operations/assign.test.js +30 -35
  112. package/test/operations/cache.test.js +17 -12
  113. package/test/operations/cachedKeyFunctions.test.js +12 -9
  114. package/test/operations/child.test.js +34 -0
  115. package/test/operations/clear.test.js +6 -27
  116. package/test/operations/deepEntries.test.js +32 -0
  117. package/test/operations/deepMerge.test.js +23 -16
  118. package/test/operations/deepReverse.test.js +2 -2
  119. package/test/operations/deepTake.test.js +2 -2
  120. package/test/operations/deepText.test.js +4 -4
  121. package/test/operations/deepValuesIterator.test.js +2 -2
  122. package/test/operations/delete.test.js +2 -2
  123. package/test/operations/extensionKeyFunctions.test.js +6 -5
  124. package/test/operations/filter.test.js +3 -3
  125. package/test/operations/from.test.js +25 -31
  126. package/test/operations/globKeys.test.js +9 -9
  127. package/test/operations/groupBy.test.js +6 -5
  128. package/test/operations/inners.test.js +17 -14
  129. package/test/operations/invokeFunctions.test.js +2 -2
  130. package/test/operations/isMap.test.js +15 -0
  131. package/test/operations/isMaplike.test.js +15 -0
  132. package/test/operations/json.test.js +2 -2
  133. package/test/operations/keys.test.js +16 -3
  134. package/test/operations/map.test.js +40 -30
  135. package/test/operations/mapExtension.test.js +6 -6
  136. package/test/operations/mapReduce.test.js +14 -12
  137. package/test/operations/mask.test.js +16 -3
  138. package/test/operations/match.test.js +2 -2
  139. package/test/operations/merge.test.js +20 -14
  140. package/test/operations/paginate.test.js +5 -5
  141. package/test/operations/parent.test.js +3 -3
  142. package/test/operations/paths.test.js +20 -27
  143. package/test/operations/plain.test.js +8 -8
  144. package/test/operations/regExpKeys.test.js +22 -18
  145. package/test/operations/reverse.test.js +4 -3
  146. package/test/operations/scope.test.js +6 -5
  147. package/test/operations/set.test.js +11 -0
  148. package/test/operations/shuffle.test.js +3 -2
  149. package/test/operations/sort.test.js +7 -10
  150. package/test/operations/sync.test.js +43 -0
  151. package/test/operations/take.test.js +2 -2
  152. package/test/operations/toFunction.test.js +2 -2
  153. package/test/operations/traverse.test.js +17 -5
  154. package/test/operations/withKeys.test.js +2 -2
  155. package/test/utilities/castArrayLike.test.js +53 -0
  156. package/test/utilities/setParent.test.js +6 -6
  157. package/test/utilities/toFunction.test.js +2 -2
  158. package/test/utilities/toPlainValue.test.js +51 -12
  159. package/src/drivers/DeepMapTree.js +0 -23
  160. package/src/drivers/DeepObjectTree.js +0 -18
  161. package/src/drivers/DeferredTree.js +0 -81
  162. package/src/drivers/FileTree.js +0 -276
  163. package/src/drivers/MapTree.js +0 -70
  164. package/src/drivers/ObjectTree.js +0 -158
  165. package/src/drivers/SetTree.js +0 -34
  166. package/src/drivers/constantTree.js +0 -19
  167. package/src/drivers/limitConcurrency.js +0 -63
  168. package/src/internal.js +0 -16
  169. package/src/utilities/getTreeArgument.js +0 -43
  170. package/test/drivers/DeepMapTree.test.js +0 -17
  171. package/test/drivers/DeepObjectTree.test.js +0 -35
  172. package/test/drivers/DeferredTree.test.js +0 -22
  173. package/test/drivers/FileTree.test.js +0 -192
  174. package/test/drivers/FunctionTree.test.js +0 -46
  175. package/test/drivers/MapTree.test.js +0 -59
  176. package/test/drivers/ObjectTree.test.js +0 -163
  177. package/test/drivers/SetTree.test.js +0 -44
  178. package/test/drivers/constantTree.test.js +0 -13
  179. package/test/drivers/limitConcurrency.test.js +0 -41
  180. package/test/operations/isAsyncMutableTree.test.js +0 -17
  181. package/test/operations/isAsyncTree.test.js +0 -26
  182. package/test/operations/isTreelike.test.js +0 -13
@@ -1,35 +0,0 @@
1
- import assert from "node:assert";
2
- import { describe, test } from "node:test";
3
- import { DeepObjectTree, Tree } from "../../src/internal.js";
4
-
5
- describe("DeepObjectTree", () => {
6
- test("returns an ObjectTree for value that's a plain sub-object or sub-array", async () => {
7
- const tree = createFixture();
8
-
9
- const object = await tree.get("object");
10
- assert.equal(object instanceof DeepObjectTree, true);
11
- assert.deepEqual(await Tree.plain(object), { b: 2 });
12
- assert.equal(object.parent, tree);
13
-
14
- const array = await tree.get("array");
15
- assert.equal(array instanceof DeepObjectTree, true);
16
- assert.deepEqual(await Tree.plain(array), [3]);
17
- assert.equal(array.parent, tree);
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
- });
26
-
27
- function createFixture() {
28
- return new DeepObjectTree({
29
- a: 1,
30
- object: {
31
- b: 2,
32
- },
33
- array: [3],
34
- });
35
- }
@@ -1,22 +0,0 @@
1
- import assert from "node:assert";
2
- import { describe, test } from "node:test";
3
- import DeferredTree from "../../src/drivers/DeferredTree.js";
4
- import { ObjectTree, Tree } from "../../src/internal.js";
5
-
6
- describe("DeferredTree", () => {
7
- test("lazy-loads a treelike object", async () => {
8
- const tree = new DeferredTree(async () => ({ a: 1, b: 2, c: 3 }));
9
- assert.deepEqual(await Tree.plain(tree), { a: 1, b: 2, c: 3 });
10
- });
11
-
12
- test("sets parent on subtrees", async () => {
13
- const object = {
14
- a: 1,
15
- };
16
- const parent = new ObjectTree({});
17
- const fixture = new DeferredTree(() => object);
18
- fixture.parent = parent;
19
- const tree = await fixture.tree();
20
- assert.equal(tree.parent, parent);
21
- });
22
- });
@@ -1,192 +0,0 @@
1
- import assert from "node:assert";
2
- import * as fs from "node:fs/promises";
3
- import path from "node:path";
4
- import { describe, test } from "node:test";
5
- import { fileURLToPath } from "node:url";
6
- import FileTree from "../../src/drivers/FileTree.js";
7
- import { ObjectTree, Tree } from "../../src/internal.js";
8
-
9
- const dirname = path.dirname(fileURLToPath(import.meta.url));
10
- const tempDirectory = path.join(dirname, "fixtures/temp");
11
-
12
- const textDecoder = new TextDecoder();
13
-
14
- describe("FileTree", async () => {
15
- test("can get the keys of the tree", async () => {
16
- const fixture = createFixture("fixtures/markdown");
17
- assert.deepEqual(Array.from(await fixture.keys()), [
18
- "Alice.md",
19
- "Bob.md",
20
- "Carol.md",
21
- "subfolder/",
22
- ]);
23
- });
24
-
25
- test("can get the value for a key", async () => {
26
- const fixture = createFixture("fixtures/markdown");
27
- const buffer = await fixture.get("Alice.md");
28
- const text = textDecoder.decode(buffer);
29
- assert.equal(text, "Hello, **Alice**.");
30
- });
31
-
32
- test("getting an unsupported key returns undefined", async () => {
33
- const fixture = createFixture("fixtures/markdown");
34
- assert.equal(await fixture.get("xyz"), undefined);
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
-
42
- test("getting a null/undefined key throws an exception", async () => {
43
- const fixture = createFixture("fixtures/markdown");
44
- await assert.rejects(async () => {
45
- await fixture.get(null);
46
- });
47
- await assert.rejects(async () => {
48
- await fixture.get(undefined);
49
- });
50
- });
51
-
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/"));
58
- });
59
-
60
- test("sets parent on subtrees", async () => {
61
- const fixture = createFixture("fixtures");
62
- const markdown = await fixture.get("markdown");
63
- assert.equal(markdown.parent, fixture);
64
- });
65
-
66
- test("can write out a file via set()", async () => {
67
- await createTempDirectory();
68
-
69
- // Write out a file.
70
- const fileName = "file1";
71
- const fileText = "This is the first file.";
72
- const tempFiles = new FileTree(tempDirectory);
73
- await tempFiles.set(fileName, fileText);
74
-
75
- // Read it back in.
76
- const filePath = path.join(tempDirectory, fileName);
77
- const actualText = String(await fs.readFile(filePath));
78
-
79
- assert.equal(fileText, actualText);
80
-
81
- await removeTempDirectory();
82
- });
83
-
84
- test("create subfolder via set() with empty object value", async () => {
85
- await createTempDirectory();
86
-
87
- // Write out new, empty folder called "empty".
88
- const tempFiles = new FileTree(tempDirectory);
89
- await tempFiles.set("empty", {});
90
-
91
- // Verify folder exists and has no contents.
92
- const folderPath = path.join(tempDirectory, "empty");
93
- const stats = await fs.stat(folderPath);
94
- assert(stats.isDirectory());
95
- const files = await fs.readdir(folderPath);
96
- assert.deepEqual(files, []);
97
-
98
- await removeTempDirectory();
99
- });
100
-
101
- test("create subfolder via set() with empty tree value", async () => {
102
- await createTempDirectory();
103
-
104
- // Write out new, empty folder called "empty".
105
- const tempFiles = new FileTree(tempDirectory);
106
- await tempFiles.set("empty", new ObjectTree({}));
107
-
108
- // Verify folder exists and has no contents.
109
- const folderPath = path.join(tempDirectory, "empty");
110
- const stats = await fs.stat(folderPath);
111
- assert(stats.isDirectory());
112
- const files = await fs.readdir(folderPath);
113
- assert.deepEqual(files, []);
114
-
115
- await removeTempDirectory();
116
- });
117
-
118
- test("can write out subfolder via set()", async () => {
119
- await createTempDirectory();
120
-
121
- // Create a tiny set of "files".
122
- const obj = {
123
- file1: "This is the first file.",
124
- subfolder: {
125
- file2: "This is the second file.",
126
- },
127
- };
128
-
129
- // Write out files as a new folder called "folder".
130
- const tempFiles = new FileTree(tempDirectory);
131
- await tempFiles.set("folder", obj);
132
-
133
- // Read them back in.
134
- const actualFiles = await tempFiles.get("folder");
135
- const strings = await Tree.map(actualFiles, {
136
- deep: true,
137
- value: (buffer) => textDecoder.decode(buffer),
138
- });
139
- const plain = await Tree.plain(strings);
140
- assert.deepEqual(plain, obj);
141
-
142
- await removeTempDirectory();
143
- });
144
-
145
- test("can delete a file via set()", async () => {
146
- await createTempDirectory();
147
- const tempFile = path.join(tempDirectory, "file");
148
- await fs.writeFile(tempFile, "");
149
- const tempFiles = new FileTree(tempDirectory);
150
- await tempFiles.set("file", undefined);
151
- let stats;
152
- try {
153
- stats = await fs.stat(tempFile);
154
- } catch (/** @type {any} */ error) {
155
- if (error.code !== "ENOENT") {
156
- throw error;
157
- }
158
- }
159
- assert(stats === undefined);
160
- await removeTempDirectory();
161
- });
162
-
163
- test("can delete a folder via set()", async () => {
164
- await createTempDirectory();
165
- const folder = path.join(tempDirectory, "folder");
166
- await fs.mkdir(folder);
167
- const tempFiles = new FileTree(tempDirectory);
168
- await tempFiles.set("folder", undefined);
169
- let stats;
170
- try {
171
- stats = await fs.stat(folder);
172
- } catch (/** @type {any} */ error) {
173
- if (error.code !== "ENOENT") {
174
- throw error;
175
- }
176
- }
177
- assert(stats === undefined);
178
- await removeTempDirectory();
179
- });
180
- });
181
-
182
- function createFixture(fixturePath) {
183
- return new FileTree(path.join(dirname, fixturePath));
184
- }
185
-
186
- async function createTempDirectory() {
187
- await fs.mkdir(tempDirectory, { recursive: true });
188
- }
189
-
190
- async function removeTempDirectory() {
191
- await fs.rm(tempDirectory, { recursive: true });
192
- }
@@ -1,46 +0,0 @@
1
- import assert from "node:assert";
2
- import { describe, test } from "node:test";
3
- import FunctionTree from "../../src/drivers/FunctionTree.js";
4
-
5
- describe("FunctionTree", async () => {
6
- test("can get the keys of the tree", async () => {
7
- const fixture = createFixture();
8
- assert.deepEqual(Array.from(await fixture.keys()), [
9
- "Alice.md",
10
- "Bob.md",
11
- "Carol.md",
12
- ]);
13
- });
14
-
15
- test("can get the value for a key", async () => {
16
- const fixture = createFixture();
17
- const alice = await fixture.get("Alice.md");
18
- assert.equal(alice, "Hello, **Alice**.");
19
- });
20
-
21
- test("getting a value from function with multiple arguments curries the function", async () => {
22
- const fixture = new FunctionTree((a, b, c) => a + b + c);
23
- const fnA = await fixture.get(1);
24
- const fnAB = await fnA.get(2);
25
- const result = await fnAB.get(3);
26
- assert.equal(result, 6);
27
- });
28
-
29
- test("getting an unsupported key returns undefined", async () => {
30
- const fixture = createFixture();
31
- assert.equal(await fixture.get("xyz"), undefined);
32
- });
33
- });
34
-
35
- function createFixture() {
36
- return new FunctionTree(
37
- (key) => {
38
- if (key?.endsWith?.(".md")) {
39
- const name = key.slice(0, -3);
40
- return `Hello, **${name}**.`;
41
- }
42
- return undefined;
43
- },
44
- ["Alice.md", "Bob.md", "Carol.md"]
45
- );
46
- }
@@ -1,59 +0,0 @@
1
- import assert from "node:assert";
2
- import { describe, test } from "node:test";
3
- import MapTree from "../../src/drivers/MapTree.js";
4
- import * as symbols from "../../src/symbols.js";
5
-
6
- describe("MapTree", () => {
7
- test("can get the keys of the tree", async () => {
8
- const fixture = createFixture();
9
- assert.deepEqual(Array.from(await fixture.keys()), ["a", "b", "c"]);
10
- });
11
-
12
- test("can get the value for a key", async () => {
13
- const fixture = createFixture();
14
- const a = await fixture.get("a");
15
- assert.equal(a, 1);
16
- });
17
-
18
- test("sets parent on subtrees", async () => {
19
- const map = new Map([["more", new Map([["a", 1]])]]);
20
- const fixture = new MapTree(map);
21
- const more = await fixture.get("more");
22
- assert.equal(more[symbols.parent], fixture);
23
- });
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
-
46
- test("getting an unsupported key returns undefined", async () => {
47
- const fixture = createFixture();
48
- assert.equal(await fixture.get("d"), undefined);
49
- });
50
- });
51
-
52
- function createFixture() {
53
- const map = new Map([
54
- ["a", 1],
55
- ["b", 2],
56
- ["c", 3],
57
- ]);
58
- return new MapTree(map);
59
- }
@@ -1,163 +0,0 @@
1
- import assert from "node:assert";
2
- import { describe, test } from "node:test";
3
- import { ObjectTree, Tree } from "../../src/internal.js";
4
- import * as symbols from "../../src/symbols.js";
5
-
6
- describe("ObjectTree", () => {
7
- test("can get the keys of the tree", async () => {
8
- const fixture = createFixture();
9
- assert.deepEqual(Array.from(await fixture.keys()), [
10
- "Alice.md",
11
- "Bob.md",
12
- "Carol.md",
13
- ]);
14
- });
15
-
16
- test("can get the value for a key", async () => {
17
- const fixture = createFixture();
18
- const alice = await fixture.get("Alice.md");
19
- assert.equal(alice, "Hello, **Alice**.");
20
- });
21
-
22
- test("getting an unsupported key returns undefined", async () => {
23
- const fixture = createFixture();
24
- assert.equal(await fixture.get("xyz"), undefined);
25
- });
26
-
27
- test("getting a null/undefined key throws an exception", async () => {
28
- const fixture = createFixture();
29
- await assert.rejects(async () => {
30
- await fixture.get(null);
31
- });
32
- await assert.rejects(async () => {
33
- await fixture.get(undefined);
34
- });
35
- });
36
-
37
- test("can set a value", async () => {
38
- const tree = new ObjectTree({
39
- a: 1,
40
- b: 2,
41
- c: 3,
42
- });
43
-
44
- // Update existing key
45
- await tree.set("a", 4);
46
-
47
- // Delete key
48
- await tree.set("b", undefined);
49
-
50
- // Overwrite key with trailing slash
51
- await tree.set("c/", {});
52
-
53
- // New key
54
- await tree.set("d", 5);
55
-
56
- assert.deepEqual(await Tree.entries(tree), [
57
- ["a", 4],
58
- ["c/", {}],
59
- ["d", 5],
60
- ]);
61
- });
62
-
63
- test("can wrap a class instance", async () => {
64
- class Foo {
65
- constructor() {
66
- this.a = 1;
67
- }
68
-
69
- get prop() {
70
- return this._prop;
71
- }
72
- set prop(prop) {
73
- this._prop = prop;
74
- }
75
- }
76
- class Bar extends Foo {
77
- method() {}
78
- }
79
- const bar = new Bar();
80
- /** @type {any} */ (bar).extra = "Hello";
81
- const fixture = new ObjectTree(bar);
82
- assert.deepEqual(await Tree.entries(fixture), [
83
- ["a", 1],
84
- ["extra", "Hello"],
85
- ["prop", undefined],
86
- ]);
87
- assert.equal(await fixture.get("a"), 1);
88
- await fixture.set("prop", "Goodbye");
89
- assert.equal(bar.prop, "Goodbye");
90
- assert.equal(await fixture.get("prop"), "Goodbye");
91
- });
92
-
93
- test("sets parent symbol on subobjects", async () => {
94
- const fixture = new ObjectTree({
95
- sub: {},
96
- });
97
- const sub = await fixture.get("sub");
98
- assert.equal(sub[symbols.parent], fixture);
99
- });
100
-
101
- test("sets parent on subtrees", async () => {
102
- const fixture = new ObjectTree({
103
- a: 1,
104
- more: new ObjectTree({
105
- b: 2,
106
- }),
107
- });
108
- const more = await fixture.get("more");
109
- assert.equal(more.parent, fixture);
110
- });
111
-
112
- test("adds trailing slashes to keys for subtrees", async () => {
113
- const tree = new ObjectTree({
114
- a1: 1,
115
- a2: new ObjectTree({
116
- b1: 2,
117
- }),
118
- a3: 3,
119
- a4: new ObjectTree({
120
- b2: 4,
121
- }),
122
- });
123
- const keys = Array.from(await tree.keys());
124
- assert.deepEqual(keys, ["a1", "a2/", "a3", "a4/"]);
125
- });
126
-
127
- test("can retrieve values with optional trailing slash", async () => {
128
- const subtree = {
129
- async get(key) {},
130
- async keys() {},
131
- };
132
- const tree = new ObjectTree({
133
- a: 1,
134
- subtree,
135
- });
136
- assert.equal(await tree.get("a"), 1);
137
- assert.equal(await tree.get("a/"), 1);
138
- assert.equal(await tree.get("subtree"), subtree);
139
- assert.equal(await tree.get("subtree/"), subtree);
140
- });
141
-
142
- test("method on an object is bound to the object", async () => {
143
- const n = new Number(123);
144
- const tree = new ObjectTree(n);
145
- const method = await tree.get("toString");
146
- assert.equal(method(), "123");
147
- });
148
-
149
- test("defers to symbols.keys for keys if defined", async () => {
150
- const tree = new ObjectTree({
151
- [symbols.keys]: () => ["a", "b", "c"],
152
- });
153
- assert.deepEqual(Array.from(await tree.keys()), ["a", "b", "c"]);
154
- });
155
- });
156
-
157
- function createFixture() {
158
- return new ObjectTree({
159
- "Alice.md": "Hello, **Alice**.",
160
- "Bob.md": "Hello, **Bob**.",
161
- "Carol.md": "Hello, **Carol**.",
162
- });
163
- }
@@ -1,44 +0,0 @@
1
- import assert from "node:assert";
2
- import { describe, test } from "node:test";
3
- import SetTree from "../../src/drivers/SetTree.js";
4
- import { ObjectTree } from "../../src/internal.js";
5
-
6
- describe("SetTree", () => {
7
- test("can get the keys of the tree", async () => {
8
- const set = new Set(["a", "b", "c"]);
9
- const fixture = new SetTree(set);
10
- assert.deepEqual(Array.from(await fixture.keys()), [0, 1, 2]);
11
- });
12
-
13
- test("can get the value for a key", async () => {
14
- const set = new Set(["a", "b", "c"]);
15
- const fixture = new SetTree(set);
16
- const a = await fixture.get(0);
17
- assert.equal(a, "a");
18
- });
19
-
20
- test("getting an unsupported key returns undefined", async () => {
21
- const set = new Set(["a", "b", "c"]);
22
- const fixture = new SetTree(set);
23
- assert.equal(await fixture.get(3), undefined);
24
- });
25
-
26
- test("getting a null/undefined key throws an exception", async () => {
27
- const set = new Set(["a", "b", "c"]);
28
- const fixture = new SetTree(set);
29
- await assert.rejects(async () => {
30
- await fixture.get(null);
31
- });
32
- await assert.rejects(async () => {
33
- await fixture.get(undefined);
34
- });
35
- });
36
-
37
- test("sets parent on subtrees", async () => {
38
- const set = new Set();
39
- set.add(new ObjectTree({}));
40
- const fixture = new SetTree(set);
41
- const subtree = await fixture.get(0);
42
- assert.equal(subtree.parent, fixture);
43
- });
44
- });
@@ -1,13 +0,0 @@
1
- import assert from "node:assert";
2
- import { describe, test } from "node:test";
3
- import constantTree from "../../src/drivers/constantTree.js";
4
- import { Tree } from "../../src/internal.js";
5
-
6
- describe("constantTree", () => {
7
- test("returns a deep tree that returns constant for all keys", async () => {
8
- const fixture = constantTree(1);
9
- assert.equal(await fixture.get("a"), 1);
10
- assert.equal(await fixture.get("b"), 1);
11
- assert.equal(await Tree.traverse(fixture, "c/", "d/", "e"), 1);
12
- });
13
- });
@@ -1,41 +0,0 @@
1
- import assert from "node:assert";
2
- import { before, describe, test } from "node:test";
3
- import limitConcurrency from "../../src/drivers/limitConcurrency.js";
4
-
5
- describe("limitConcurrency", async () => {
6
- before(async () => {
7
- // Confirm our limited functions throws on too many calls
8
- const fn = createFixture();
9
- try {
10
- const array = Array.from({ length: 10 }, (_, index) => index);
11
- await Promise.all(array.map((index) => fn(index)));
12
- } catch (/** @type {any} */ error) {
13
- assert.equal(error.message, "Too many calls");
14
- }
15
- });
16
-
17
- test("limits the number of concurrent calls", async () => {
18
- const fn = createFixture();
19
- const limitedFn = limitConcurrency(fn, 3);
20
- const array = Array.from({ length: 10 }, (_, index) => index);
21
- const result = await Promise.all(array.map((index) => limitedFn(index)));
22
- assert.deepEqual(result, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
23
- });
24
- });
25
-
26
- // Return a function that only permits a limited number of concurrent calls and
27
- // simulates a delay for each request.
28
- function createFixture() {
29
- let activeCalls = 0;
30
- const maxActiveCalls = 3;
31
-
32
- return async function (n) {
33
- if (activeCalls >= maxActiveCalls) {
34
- throw new Error("Too many calls");
35
- }
36
- activeCalls++;
37
- await new Promise((resolve) => setTimeout(resolve, 10));
38
- activeCalls--;
39
- return n;
40
- };
41
- }
@@ -1,17 +0,0 @@
1
- import assert from "node:assert";
2
- import { describe, test } from "node:test";
3
- import ObjectTree from "../../src/drivers/ObjectTree.js";
4
- import isAsyncMutableTree from "../../src/operations/isAsyncMutableTree.js";
5
-
6
- describe("isAsyncMutableTree", () => {
7
- test("returns true if the object is a mutable tree", () => {
8
- assert.equal(
9
- isAsyncMutableTree({
10
- get() {},
11
- keys() {},
12
- }),
13
- false
14
- );
15
- assert.equal(isAsyncMutableTree(new ObjectTree({})), true);
16
- });
17
- });
@@ -1,26 +0,0 @@
1
- import assert from "node:assert";
2
- import { describe, test } from "node:test";
3
- import isAsyncTree from "../../src/operations/isAsyncTree.js";
4
-
5
- describe("isAsyncTree", () => {
6
- test("returns true if the object is a tree", () => {
7
- const missingGetAndKeys = {};
8
- assert(!isAsyncTree(missingGetAndKeys));
9
-
10
- const missingIterator = {
11
- async get() {},
12
- };
13
- assert(!isAsyncTree(missingIterator));
14
-
15
- const missingGet = {
16
- async keys() {},
17
- };
18
- assert(!isAsyncTree(missingGet));
19
-
20
- const hasGetAndKeys = {
21
- async get() {},
22
- async keys() {},
23
- };
24
- assert(isAsyncTree(hasGetAndKeys));
25
- });
26
- });
@@ -1,13 +0,0 @@
1
- import assert from "node:assert";
2
- import { describe, test } from "node:test";
3
- import isTreelike from "../../src/operations/isTreelike.js";
4
-
5
- describe("Fixture name goes here", () => {
6
- test("isTreelike() returns true if the argument can be cast to an async tree", () => {
7
- assert(!isTreelike(null));
8
- assert(isTreelike({}));
9
- assert(isTreelike([]));
10
- assert(isTreelike(new Map()));
11
- assert(isTreelike(new Set()));
12
- });
13
- });