@weborigami/async-tree 0.0.65-beta.2 → 0.0.66-beta.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weborigami/async-tree",
3
- "version": "0.0.65-beta.2",
3
+ "version": "0.0.66-beta.1",
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.4"
12
12
  },
13
13
  "dependencies": {
14
- "@weborigami/types": "0.0.65-beta.2"
14
+ "@weborigami/types": "0.0.66-beta.1"
15
15
  },
16
16
  "scripts": {
17
17
  "test": "node --test --test-reporter=spec",
package/src/MapTree.js CHANGED
@@ -23,13 +23,6 @@ export default class MapTree {
23
23
  }
24
24
 
25
25
  async get(key) {
26
- if (key == null) {
27
- // Reject nullish key.
28
- throw new ReferenceError(
29
- `${this.constructor.name}: Cannot get a null or undefined key.`
30
- );
31
- }
32
-
33
26
  const value = this.map.get(key);
34
27
  setParent(value, this);
35
28
  return value;
package/src/Tree.d.ts CHANGED
@@ -5,7 +5,7 @@ export function assign(target: Treelike, source: Treelike): Promise<AsyncTree>;
5
5
  export function clear(AsyncTree: AsyncMutableTree): Promise<void>;
6
6
  export function entries(AsyncTree: AsyncTree): Promise<IterableIterator<any>>;
7
7
  export function forEach(AsyncTree: AsyncTree, callbackfn: (value: any, key: any) => Promise<void>): Promise<void>;
8
- export function from(obj: any, options?: { deep: boolean }): AsyncTree;
8
+ export function from(obj: any, options?: { deep?: boolean, parent?: AsyncTree|null }): AsyncTree;
9
9
  export function has(AsyncTree: AsyncTree, key: any): Promise<boolean>;
10
10
  export function isAsyncMutableTree(obj: any): obj is AsyncMutableTree;
11
11
  export function isAsyncTree(obj: any): obj is AsyncTree;
package/src/Tree.js CHANGED
@@ -105,35 +105,38 @@ export async function forEach(tree, callbackFn) {
105
105
  *
106
106
  * If the object is a plain object, it will be converted to an ObjectTree. The
107
107
  * optional `deep` option can be set to `true` to convert a plain object to a
108
- * DeepObjectTree.
108
+ * DeepObjectTree. The optional `parent` parameter will be used as the default
109
+ * parent of the new tree.
109
110
  *
110
111
  * @param {Treelike | Object} object
111
- * @param {{ deep?: true }} [options]
112
+ * @param {{ deep?: true, parent?: AsyncTree|null }} [options]
112
113
  * @returns {AsyncTree}
113
114
  */
114
115
  export function from(object, options = {}) {
116
+ let tree;
115
117
  if (isAsyncTree(object)) {
116
118
  // Argument already supports the tree interface.
117
119
  // @ts-ignore
118
120
  return object;
119
121
  } else if (typeof object === "function") {
120
- return new FunctionTree(object);
122
+ tree = new FunctionTree(object);
121
123
  } else if (object instanceof Map) {
122
- return new MapTree(object);
124
+ tree = new MapTree(object);
123
125
  } else if (object instanceof Set) {
124
- return new SetTree(object);
126
+ tree = new SetTree(object);
125
127
  } else if (isPlainObject(object) || object instanceof Array) {
126
- return options.deep ? new DeepObjectTree(object) : new ObjectTree(object);
128
+ tree = options.deep ? new DeepObjectTree(object) : new ObjectTree(object);
127
129
  } else if (isUnpackable(object)) {
128
130
  async function AsyncFunction() {} // Sample async function
129
- return object.unpack instanceof AsyncFunction.constructor
130
- ? // Async unpack: return a deferred tree.
131
- new DeferredTree(object.unpack)
132
- : // Synchronous unpack: cast the result of unpack() to a tree.
133
- from(object.unpack());
131
+ tree =
132
+ object.unpack instanceof AsyncFunction.constructor
133
+ ? // Async unpack: return a deferred tree.
134
+ new DeferredTree(object.unpack)
135
+ : // Synchronous unpack: cast the result of unpack() to a tree.
136
+ from(object.unpack());
134
137
  } else if (object && typeof object === "object") {
135
138
  // An instance of some class.
136
- return new ObjectTree(object);
139
+ tree = new ObjectTree(object);
137
140
  } else if (
138
141
  typeof object === "string" ||
139
142
  typeof object === "number" ||
@@ -141,10 +144,15 @@ export function from(object, options = {}) {
141
144
  ) {
142
145
  // A primitive value; box it into an object and construct a tree.
143
146
  const boxed = utilities.box(object);
144
- return new ObjectTree(boxed);
147
+ tree = new ObjectTree(boxed);
148
+ } else {
149
+ throw new TypeError("Couldn't convert argument to an async tree");
145
150
  }
146
151
 
147
- throw new TypeError("Couldn't convert argument to an async tree");
152
+ if (!tree.parent && options.parent) {
153
+ tree.parent = options.parent;
154
+ }
155
+ return tree;
148
156
  }
149
157
 
150
158
  /**
@@ -416,7 +424,7 @@ export async function traverseOrThrow(treelike, ...keys) {
416
424
  let key;
417
425
  while (remainingKeys.length > 0) {
418
426
  if (value === undefined) {
419
- throw new TraverseError("Tried to traverse a null or undefined value", {
427
+ throw new TraverseError("A null or undefined value can't be traversed", {
420
428
  tree: treelike,
421
429
  keys,
422
430
  position,
@@ -23,6 +23,12 @@ export default function treeCache(
23
23
  cacheTreelike,
24
24
  filterTreelike
25
25
  ) {
26
+ if (!sourceTreelike) {
27
+ const error = new TypeError(`cache: The source tree isn't defined.`);
28
+ /** @type {any} */ (error).position = 0;
29
+ throw error;
30
+ }
31
+
26
32
  const source = Tree.from(sourceTreelike);
27
33
  const filter = filterTreelike ? Tree.from(filterTreelike) : undefined;
28
34
 
@@ -10,6 +10,12 @@ import deepValuesIterator from "./deepValuesIterator.js";
10
10
  * @param {import("../../index.ts").Treelike} treelike
11
11
  */
12
12
  export default async function concatTreeValues(treelike) {
13
+ if (!treelike) {
14
+ const error = new TypeError(`concat: The tree isn't defined.`);
15
+ /** @type {any} */ (error).position = 0;
16
+ throw error;
17
+ }
18
+
13
19
  const strings = [];
14
20
  for await (const value of deepValuesIterator(treelike, { expand: true })) {
15
21
  if (value) {
@@ -11,6 +11,12 @@ export default function deepTakeFn(count) {
11
11
  * @param {import("../../index.ts").Treelike} treelike
12
12
  */
13
13
  return async function deepTakeFn(treelike) {
14
+ if (!treelike) {
15
+ const error = new TypeError(`deepTake: The tree isn't defined.`);
16
+ /** @type {any} */ (error).position = 0;
17
+ throw error;
18
+ }
19
+
14
20
  const tree = await Tree.from(treelike, { deep: true });
15
21
  const { values } = await traverse(tree, count);
16
22
  return Tree.from(values);
@@ -14,6 +14,12 @@ export default async function* deepValuesIterator(
14
14
  treelike,
15
15
  options = { expand: false }
16
16
  ) {
17
+ if (!treelike) {
18
+ const error = new TypeError(`deepValues: The tree isn't defined.`);
19
+ /** @type {any} */ (error).position = 0;
20
+ throw error;
21
+ }
22
+
17
23
  const tree = Tree.from(treelike, { deep: true });
18
24
  for (const key of await tree.keys()) {
19
25
  let value = await tree.get(key);
@@ -11,6 +11,12 @@ export default function createGroupByTransform(groupKeyFn) {
11
11
  * @type {import("../../index.ts").TreeTransform}
12
12
  */
13
13
  return async function groupByTransform(treelike) {
14
+ if (!treelike) {
15
+ const error = new TypeError(`groupBy: The tree to group isn't defined.`);
16
+ /** @type {any} */ (error).position = 0;
17
+ throw error;
18
+ }
19
+
14
20
  const tree = Tree.from(treelike);
15
21
  const result = {};
16
22
  for (const key of await tree.keys()) {
@@ -11,6 +11,12 @@ import { Tree } from "../internal.js";
11
11
  * @returns {AsyncTree & {trees: AsyncTree[]}}
12
12
  */
13
13
  export default function scope(treelike) {
14
+ if (!treelike) {
15
+ const error = new TypeError(`scope: The tree isn't defined.`);
16
+ /** @type {any} */ (error).position = 0;
17
+ throw error;
18
+ }
19
+
14
20
  const tree = Tree.from(treelike);
15
21
 
16
22
  return {
@@ -10,6 +10,14 @@ import { Tree } from "../internal.js";
10
10
  * @returns {AsyncTree}
11
11
  */
12
12
  export default function deepReverse(treelike) {
13
+ if (!treelike) {
14
+ const error = new TypeError(
15
+ `deepReverse: The tree to reverse isn't defined.`
16
+ );
17
+ /** @type {any} */ (error).position = 0;
18
+ throw error;
19
+ }
20
+
13
21
  const tree = Tree.from(treelike);
14
22
  return {
15
23
  async get(key) {
@@ -46,6 +46,12 @@ export default function createMapTransform(options = {}) {
46
46
  * @type {import("../../index.ts").TreeTransform}
47
47
  */
48
48
  return function map(treelike) {
49
+ if (!treelike) {
50
+ const error = new TypeError(`map: The tree to map isn't defined.`);
51
+ /** @type {any} */ (error).position = 0;
52
+ throw error;
53
+ }
54
+
49
55
  const tree = Tree.from(treelike, { deep });
50
56
 
51
57
  // The transformed tree is actually an extension of the original tree's
@@ -11,6 +11,14 @@ import { Tree } from "../internal.js";
11
11
  * @type {import("../../index.ts").TreeTransform}
12
12
  */
13
13
  export default async function regExpKeys(treelike) {
14
+ if (!treelike) {
15
+ const error = new TypeError(
16
+ `regExpKeys: The tree of regular expressions isn't defined.`
17
+ );
18
+ /** @type {any} */ (error).position = 0;
19
+ throw error;
20
+ }
21
+
14
22
  const tree = Tree.from(treelike);
15
23
  const map = new Map();
16
24
 
@@ -21,6 +29,13 @@ export default async function regExpKeys(treelike) {
21
29
  description: "regExpKeys",
22
30
 
23
31
  async get(key) {
32
+ if (key == null) {
33
+ // Reject nullish key.
34
+ throw new ReferenceError(
35
+ `${this.constructor.name}: Cannot get a null or undefined key.`
36
+ );
37
+ }
38
+
24
39
  for (const [regExp, value] of map) {
25
40
  if (regExp.test(key)) {
26
41
  return value;
@@ -10,6 +10,12 @@ import { Tree } from "../internal.js";
10
10
  * @returns {AsyncTree}
11
11
  */
12
12
  export default function reverse(treelike) {
13
+ if (!treelike) {
14
+ const error = new TypeError(`reverse: The tree to reverse isn't defined.`);
15
+ /** @type {any} */ (error).position = 0;
16
+ throw error;
17
+ }
18
+
13
19
  const tree = Tree.from(treelike);
14
20
  return {
15
21
  async get(key) {
@@ -26,6 +26,12 @@ export default function sortFn(options) {
26
26
  * @type {import("../../index.ts").TreeTransform}
27
27
  */
28
28
  return function sort(treelike) {
29
+ if (!treelike) {
30
+ const error = new TypeError(`sort: The tree to sort isn't defined.`);
31
+ /** @type {any} */ (error).position = 0;
32
+ throw error;
33
+ }
34
+
29
35
  const tree = Tree.from(treelike);
30
36
  const transformed = Object.create(tree);
31
37
  transformed.keys = async () => {
@@ -10,6 +10,12 @@ export default function take(count) {
10
10
  * @type {import("../../index.ts").TreeTransform}
11
11
  */
12
12
  return (treelike) => {
13
+ if (!treelike) {
14
+ const error = new TypeError(`take: The tree to take from isn't defined.`);
15
+ /** @type {any} */ (error).position = 0;
16
+ throw error;
17
+ }
18
+
13
19
  const tree = Tree.from(treelike);
14
20
  return {
15
21
  async keys() {
@@ -26,16 +26,6 @@ describe("MapTree", () => {
26
26
  const fixture = createFixture();
27
27
  assert.equal(await fixture.get("d"), undefined);
28
28
  });
29
-
30
- test("getting a null/undefined key throws an exception", async () => {
31
- const fixture = createFixture();
32
- await assert.rejects(async () => {
33
- await fixture.get(null);
34
- });
35
- await assert.rejects(async () => {
36
- await fixture.get(undefined);
37
- });
38
- });
39
29
  });
40
30
 
41
31
  function createFixture() {