@weborigami/async-tree 0.0.37 → 0.0.39

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,14 +1,14 @@
1
1
  {
2
2
  "name": "@weborigami/async-tree",
3
- "version": "0.0.37",
3
+ "version": "0.0.39",
4
4
  "description": "Asynchronous tree drivers based on standard JavaScript classes",
5
5
  "type": "module",
6
6
  "main": "./main.js",
7
7
  "browser": "./browser.js",
8
8
  "types": "./index.ts",
9
9
  "devDependencies": {
10
- "@types/node": "20.8.10",
11
- "typescript": "5.2.2"
10
+ "@types/node": "20.11.3",
11
+ "typescript": "5.3.3"
12
12
  },
13
13
  "dependencies": {
14
14
  "@weborigami/types": "*"
@@ -32,9 +32,9 @@ export default function treeCache(source, cacheTree, filter) {
32
32
  // Cache miss or interior node cache hit.
33
33
  let value = await source.get(key);
34
34
  if (value !== undefined) {
35
- // Does this key match the filter?
36
- const filterValue = filter ? await filter.get(key) : true;
37
- const filterMatch = filterValue !== undefined;
35
+ // If a filter is defined, does the key match the filter?
36
+ const filterValue = await filter?.get(key);
37
+ const filterMatch = !filter || filterValue !== undefined;
38
38
  if (filterMatch) {
39
39
  if (Tree.isAsyncTree(value)) {
40
40
  // Construct merged tree for a tree result.
@@ -6,25 +6,35 @@ import * as Tree from "../Tree.js";
6
6
  * @typedef {import("../../index.ts").KeyFn} KeyFn
7
7
  * @typedef {import("../../index.ts").ValueKeyFn} ValueKeyFn
8
8
  *
9
- * @param {ValueKeyFn|{ deep?: boolean, description?: string, inverseKeyMap?: KeyFn, keyMap?: KeyFn, valueMap?: ValueKeyFn }} options
9
+ * @param {ValueKeyFn|{ deep?: boolean, description?: string, needsSourceValue?: boolean, inverseKeyMap?: KeyFn, keyMap?: KeyFn, valueMap?: ValueKeyFn }} options
10
10
  */
11
11
  export default function createMapTransform(options) {
12
12
  let deep;
13
13
  let description;
14
14
  let inverseKeyMap;
15
15
  let keyMap;
16
+ let needsSourceValue;
16
17
  let valueMap;
17
18
  if (typeof options === "function") {
18
19
  // Take the single function argument as the valueMap
19
20
  valueMap = options;
20
21
  } else {
21
- deep = options.deep ?? false;
22
- description = options.description ?? "key/value map";
22
+ deep = options.deep;
23
+ description = options.description;
23
24
  inverseKeyMap = options.inverseKeyMap;
24
25
  keyMap = options.keyMap;
26
+ needsSourceValue = options.needsSourceValue;
25
27
  valueMap = options.valueMap;
26
28
  }
27
29
 
30
+ deep ??= false;
31
+ description ??= "key/value map";
32
+ // @ts-ignore
33
+ inverseKeyMap ??= valueMap?.inverseKeyMap;
34
+ // @ts-ignore
35
+ keyMap ??= valueMap?.keyMap;
36
+ needsSourceValue ??= true;
37
+
28
38
  if ((keyMap && !inverseKeyMap) || (!keyMap && inverseKeyMap)) {
29
39
  throw new TypeError(
30
40
  `map: You must specify both keyMap and inverseKeyMap, or neither.`
@@ -58,11 +68,18 @@ export default function createMapTransform(options) {
58
68
  }
59
69
 
60
70
  // Step 2: Get the source value.
61
- const sourceValue = await tree.get(sourceKey);
71
+ let sourceValue;
72
+ if (needsSourceValue) {
73
+ // Normal case: get the value from the source tree.
74
+ sourceValue = await tree.get(sourceKey);
75
+ } else if (deep && (await Tree.isKeyForSubtree(tree, sourceKey))) {
76
+ // Only get the source value if it's a subtree.
77
+ sourceValue = tree;
78
+ }
62
79
 
63
80
  // Step 3: Map the source value to the result value.
64
81
  let resultValue;
65
- if (sourceValue === undefined) {
82
+ if (needsSourceValue && sourceValue === undefined) {
66
83
  // No source value means no result value.
67
84
  resultValue = undefined;
68
85
  } else if (deep && Tree.isAsyncTree(sourceValue)) {
@@ -1,5 +1,6 @@
1
1
  import assert from "node:assert";
2
2
  import { describe, test } from "node:test";
3
+ import FunctionTree from "../../src/FunctionTree.js";
3
4
  import ObjectTree from "../../src/ObjectTree.js";
4
5
  import * as Tree from "../../src/Tree.js";
5
6
  import map from "../../src/transforms/map.js";
@@ -108,6 +109,21 @@ describe("map", () => {
108
109
  });
109
110
  });
110
111
 
112
+ test("valueMap can provide a default keyMap and inverseKeyMap", async () => {
113
+ const uppercase = (s) => s.toUpperCase();
114
+ uppercase.keyMap = (sourceKey) => `_${sourceKey}`;
115
+ uppercase.inverseKeyMap = (resultKey) => resultKey.slice(1);
116
+ const tree = new ObjectTree({
117
+ a: "letter a",
118
+ b: "letter b",
119
+ });
120
+ const mapped = map(uppercase)(tree);
121
+ assert.deepEqual(await Tree.plain(mapped), {
122
+ _a: "LETTER A",
123
+ _b: "LETTER B",
124
+ });
125
+ });
126
+
111
127
  test("deep maps values", async () => {
112
128
  const tree = new ObjectTree({
113
129
  a: "letter a",
@@ -171,4 +187,21 @@ describe("map", () => {
171
187
  },
172
188
  });
173
189
  });
190
+
191
+ test("needsSourceValue can be set to false in cases where the value isn't necessary", async () => {
192
+ let flag = false;
193
+ const tree = new FunctionTree(() => {
194
+ flag = true;
195
+ }, ["a", "b", "c"]);
196
+ const mapped = map({
197
+ needsSourceValue: false,
198
+ valueMap: () => "X",
199
+ })(tree);
200
+ assert.deepEqual(await Tree.plain(mapped), {
201
+ a: "X",
202
+ b: "X",
203
+ c: "X",
204
+ });
205
+ assert(!flag);
206
+ });
174
207
  });