@weborigami/async-tree 0.0.63 → 0.0.64-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.
package/index.ts CHANGED
@@ -25,7 +25,7 @@ export type PlainObject = {
25
25
  [key: string]: any;
26
26
  };
27
27
 
28
- export type ReduceFn = (values: any[], keys: any[]) => Promise<any>;
28
+ export type ReduceFn = (values: any[], keys: any[], tree: AsyncTree) => Promise<any>;
29
29
 
30
30
  export type StringLike = string | HasString;
31
31
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weborigami/async-tree",
3
- "version": "0.0.63",
3
+ "version": "0.0.64-beta.2",
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.5.3"
12
12
  },
13
13
  "dependencies": {
14
- "@weborigami/types": "0.0.63"
14
+ "@weborigami/types": "0.0.64-beta.2"
15
15
  },
16
16
  "scripts": {
17
17
  "test": "node --test --test-reporter=spec",
package/src/Tree.d.ts CHANGED
@@ -14,7 +14,7 @@ export function isTraversable(obj: any): boolean;
14
14
  export function isTreelike(obj: any): obj is Treelike;
15
15
  export function map(tree: Treelike, valueFn: ValueKeyFn): AsyncTree;
16
16
  export function mapReduce(tree: Treelike, mapFn: ValueKeyFn | null, reduceFn: ReduceFn): Promise<any>;
17
- export function paths(tree: Treelike, base: string): string[];
17
+ export function paths(tree: Treelike, base?: string): string[];
18
18
  export function plain(tree: Treelike): Promise<PlainObject>;
19
19
  export function remove(AsyncTree: AsyncMutableTree, key: any): Promise<boolean>;
20
20
  export function toFunction(tree: Treelike): Function;
package/src/Tree.js CHANGED
@@ -166,7 +166,14 @@ export async function has(tree, key) {
166
166
  * @returns {obj is AsyncTree}
167
167
  */
168
168
  export function isAsyncTree(obj) {
169
- return obj && typeof obj.get === "function" && typeof obj.keys === "function";
169
+ return (
170
+ obj &&
171
+ typeof obj.get === "function" &&
172
+ typeof obj.keys === "function" &&
173
+ // JavaScript Map look like trees but can't be extended the same way, so we
174
+ // report false.
175
+ !(obj instanceof Map)
176
+ );
170
177
  }
171
178
 
172
179
  /**
@@ -231,8 +238,9 @@ export function isTraversable(object) {
231
238
  export function isTreelike(obj) {
232
239
  return (
233
240
  isAsyncTree(obj) ||
234
- obj instanceof Function ||
235
241
  obj instanceof Array ||
242
+ obj instanceof Function ||
243
+ obj instanceof Map ||
236
244
  obj instanceof Set ||
237
245
  isPlainObject(obj)
238
246
  );
@@ -286,14 +294,14 @@ export async function mapReduce(treelike, valueFn, reduceFn) {
286
294
  const values = await Promise.all(promises);
287
295
 
288
296
  // Reduce the values to a single result.
289
- return reduceFn(values, keys);
297
+ return reduceFn(values, keys, tree);
290
298
  }
291
299
 
292
300
  /**
293
301
  * Returns slash-separated paths for all values in the tree.
294
302
  *
295
303
  * @param {Treelike} treelike
296
- * @param {string} base
304
+ * @param {string?} base
297
305
  */
298
306
  export async function paths(treelike, base = "") {
299
307
  const tree = from(treelike);
@@ -310,6 +318,7 @@ export async function paths(treelike, base = "") {
310
318
  }
311
319
  return result;
312
320
  }
321
+
313
322
  /**
314
323
  * Converts an asynchronous tree into a synchronous plain JavaScript object.
315
324
  *
@@ -320,7 +329,11 @@ export async function paths(treelike, base = "") {
320
329
  * @returns {Promise<PlainObject|Array>}
321
330
  */
322
331
  export async function plain(treelike) {
323
- return mapReduce(treelike, null, (values, keys) => {
332
+ return mapReduce(treelike, null, (values, keys, tree) => {
333
+ // Special case for an empty tree: if based on array, return array.
334
+ if (tree instanceof ObjectTree && keys.length === 0) {
335
+ return tree.object instanceof Array ? [] : {};
336
+ }
324
337
  const object = {};
325
338
  for (let i = 0; i < keys.length; i++) {
326
339
  object[keys[i]] = values[i];
@@ -1,6 +1,7 @@
1
1
  import assert from "node:assert";
2
2
  import { describe, test } from "node:test";
3
3
  import MapTree from "../src/MapTree.js";
4
+ import * as symbols from "../src/symbols.js";
4
5
 
5
6
  describe("MapTree", () => {
6
7
  test("can get the keys of the tree", async () => {
@@ -18,7 +19,7 @@ describe("MapTree", () => {
18
19
  const map = new Map([["more", new Map([["a", 1]])]]);
19
20
  const fixture = new MapTree(map);
20
21
  const more = await fixture.get("more");
21
- assert.equal(more.parent, fixture);
22
+ assert.equal(more[symbols.parent], fixture);
22
23
  });
23
24
 
24
25
  test("getting an unsupported key returns undefined", async () => {
package/test/Tree.test.js CHANGED
@@ -261,6 +261,13 @@ describe("Tree", () => {
261
261
  assert.deepEqual(plain, original);
262
262
  });
263
263
 
264
+ test("plain() returns empty array or object for ObjectTree as necessary", async () => {
265
+ const tree = new ObjectTree({});
266
+ assert.deepEqual(await Tree.plain(tree), {});
267
+ const arrayTree = new ObjectTree([]);
268
+ assert.deepEqual(await Tree.plain(arrayTree), []);
269
+ });
270
+
264
271
  test("plain() awaits async properties", async () => {
265
272
  const object = {
266
273
  get name() {