@weborigami/async-tree 0.5.4 → 0.5.6

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 (153) hide show
  1. package/index.ts +16 -6
  2. package/package.json +2 -2
  3. package/shared.js +20 -29
  4. package/src/Tree.js +59 -513
  5. package/src/constants.js +2 -0
  6. package/src/drivers/BrowserFileTree.js +9 -10
  7. package/src/drivers/DeepMapTree.js +3 -3
  8. package/src/drivers/DeepObjectTree.js +4 -5
  9. package/src/drivers/DeferredTree.js +2 -2
  10. package/src/drivers/FileTree.js +11 -33
  11. package/src/drivers/FunctionTree.js +3 -3
  12. package/src/drivers/MapTree.js +6 -6
  13. package/src/drivers/ObjectTree.js +6 -8
  14. package/src/drivers/SetTree.js +1 -1
  15. package/src/drivers/SiteTree.js +1 -1
  16. package/src/drivers/constantTree.js +1 -1
  17. package/src/extension.js +5 -3
  18. package/src/jsonKeys.js +5 -7
  19. package/src/operations/addNextPrevious.js +10 -9
  20. package/src/operations/assign.js +40 -0
  21. package/src/operations/cache.js +18 -12
  22. package/src/operations/cachedKeyFunctions.js +15 -4
  23. package/src/operations/clear.js +20 -0
  24. package/src/operations/deepMap.js +25 -0
  25. package/src/operations/deepMerge.js +11 -25
  26. package/src/operations/deepReverse.js +6 -7
  27. package/src/operations/deepTake.js +6 -7
  28. package/src/operations/deepText.js +4 -4
  29. package/src/operations/deepValuesIterator.js +8 -6
  30. package/src/operations/delete.js +20 -0
  31. package/src/operations/entries.js +16 -0
  32. package/src/operations/extensionKeyFunctions.js +1 -1
  33. package/src/operations/filter.js +7 -8
  34. package/src/operations/first.js +18 -0
  35. package/src/operations/forEach.js +20 -0
  36. package/src/operations/from.js +77 -0
  37. package/src/operations/globKeys.js +8 -8
  38. package/src/operations/group.js +3 -46
  39. package/src/operations/groupBy.js +51 -0
  40. package/src/operations/has.js +16 -0
  41. package/src/operations/indent.js +4 -2
  42. package/src/operations/inners.js +29 -0
  43. package/src/operations/invokeFunctions.js +5 -4
  44. package/src/operations/isAsyncMutableTree.js +15 -0
  45. package/src/operations/isAsyncTree.js +21 -0
  46. package/src/operations/isTraversable.js +15 -0
  47. package/src/operations/isTreelike.js +33 -0
  48. package/src/operations/json.js +4 -3
  49. package/src/operations/keys.js +14 -0
  50. package/src/operations/length.js +15 -0
  51. package/src/operations/map.js +156 -95
  52. package/src/operations/mapExtension.js +78 -0
  53. package/src/operations/mapReduce.js +44 -0
  54. package/src/operations/mask.js +18 -16
  55. package/src/operations/match.js +74 -0
  56. package/src/operations/merge.js +22 -20
  57. package/src/operations/paginate.js +3 -5
  58. package/src/operations/parent.js +13 -0
  59. package/src/operations/paths.js +51 -0
  60. package/src/operations/plain.js +34 -0
  61. package/src/operations/regExpKeys.js +4 -5
  62. package/src/operations/reverse.js +4 -6
  63. package/src/operations/root.js +17 -0
  64. package/src/operations/scope.js +4 -6
  65. package/src/operations/shuffle.js +46 -0
  66. package/src/operations/sort.js +19 -12
  67. package/src/operations/take.js +3 -5
  68. package/src/operations/text.js +3 -3
  69. package/src/operations/toFunction.js +14 -0
  70. package/src/operations/traverse.js +24 -0
  71. package/src/operations/traverseOrThrow.js +59 -0
  72. package/src/operations/traversePath.js +16 -0
  73. package/src/operations/values.js +15 -0
  74. package/src/operations/withKeys.js +33 -0
  75. package/src/utilities/TypedArray.js +2 -0
  76. package/src/utilities/box.js +20 -0
  77. package/src/utilities/castArraylike.js +38 -0
  78. package/src/utilities/getParent.js +33 -0
  79. package/src/utilities/getRealmObjectPrototype.js +19 -0
  80. package/src/utilities/getTreeArgument.js +43 -0
  81. package/src/utilities/isPacked.js +20 -0
  82. package/src/utilities/isPlainObject.js +29 -0
  83. package/src/utilities/isPrimitive.js +13 -0
  84. package/src/utilities/isStringlike.js +25 -0
  85. package/src/utilities/isUnpackable.js +13 -0
  86. package/src/utilities/keysFromPath.js +34 -0
  87. package/src/utilities/naturalOrder.js +9 -0
  88. package/src/utilities/pathFromKeys.js +18 -0
  89. package/src/utilities/setParent.js +38 -0
  90. package/src/utilities/toFunction.js +40 -0
  91. package/src/utilities/toPlainValue.js +95 -0
  92. package/src/utilities/toString.js +37 -0
  93. package/test/drivers/ExplorableSiteTree.test.js +1 -1
  94. package/test/drivers/FileTree.test.js +1 -1
  95. package/test/drivers/calendarTree.test.js +1 -1
  96. package/test/jsonKeys.test.js +1 -1
  97. package/test/operations/assign.test.js +54 -0
  98. package/test/operations/cache.test.js +1 -1
  99. package/test/operations/cachedKeyFunctions.test.js +16 -16
  100. package/test/operations/clear.test.js +34 -0
  101. package/test/operations/deepMerge.test.js +2 -6
  102. package/test/operations/deepReverse.test.js +1 -1
  103. package/test/operations/delete.test.js +20 -0
  104. package/test/operations/entries.test.js +18 -0
  105. package/test/operations/extensionKeyFunctions.test.js +10 -10
  106. package/test/operations/first.test.js +15 -0
  107. package/test/operations/fixtures/README.md +1 -0
  108. package/test/operations/forEach.test.js +22 -0
  109. package/test/operations/from.test.js +67 -0
  110. package/test/operations/globKeys.test.js +3 -3
  111. package/test/operations/{group.test.js → groupBy.test.js} +4 -4
  112. package/test/operations/has.test.js +15 -0
  113. package/test/operations/inners.test.js +30 -0
  114. package/test/operations/invokeFunctions.test.js +1 -1
  115. package/test/operations/isAsyncMutableTree.test.js +17 -0
  116. package/test/operations/isAsyncTree.test.js +26 -0
  117. package/test/operations/isTreelike.test.js +13 -0
  118. package/test/operations/keys.test.js +15 -0
  119. package/test/operations/length.test.js +15 -0
  120. package/test/operations/map.test.js +39 -70
  121. package/test/operations/mapExtension.test.js +53 -0
  122. package/test/operations/mapReduce.test.js +23 -0
  123. package/test/operations/mask.test.js +1 -1
  124. package/test/operations/match.test.js +33 -0
  125. package/test/operations/merge.test.js +23 -9
  126. package/test/operations/paginate.test.js +1 -1
  127. package/test/operations/parent.test.js +15 -0
  128. package/test/operations/paths.test.js +40 -0
  129. package/test/operations/plain.test.js +69 -0
  130. package/test/operations/reverse.test.js +1 -1
  131. package/test/operations/scope.test.js +1 -1
  132. package/test/operations/shuffle.test.js +18 -0
  133. package/test/operations/sort.test.js +3 -3
  134. package/test/operations/toFunction.test.js +16 -0
  135. package/test/operations/traverse.test.js +43 -0
  136. package/test/operations/traversePath.test.js +16 -0
  137. package/test/operations/values.test.js +18 -0
  138. package/test/operations/withKeys.test.js +21 -0
  139. package/test/utilities/box.test.js +26 -0
  140. package/test/utilities/getRealmObjectPrototype.test.js +11 -0
  141. package/test/utilities/isPlainObject.test.js +13 -0
  142. package/test/utilities/keysFromPath.test.js +14 -0
  143. package/test/utilities/naturalOrder.test.js +11 -0
  144. package/test/utilities/pathFromKeys.test.js +12 -0
  145. package/test/utilities/setParent.test.js +34 -0
  146. package/test/utilities/toFunction.test.js +34 -0
  147. package/test/utilities/toPlainValue.test.js +27 -0
  148. package/test/utilities/toString.test.js +22 -0
  149. package/src/Tree.d.ts +0 -24
  150. package/src/utilities.d.ts +0 -21
  151. package/src/utilities.js +0 -443
  152. package/test/Tree.test.js +0 -407
  153. package/test/utilities.test.js +0 -141
@@ -9,28 +9,28 @@ describe("keyMapsForExtensions", () => {
9
9
  const { inverseKey, key } = extensionKeyFunctions(".txt");
10
10
  assert.equal(await inverseKey("file.txt"), "file.txt");
11
11
  assert.equal(await inverseKey("file.txt/"), "file.txt");
12
- assert.equal(await key("file.txt"), "file.txt");
13
- assert.equal(await key("file.txt/"), "file.txt/");
12
+ assert.equal(await key(null, "file.txt"), "file.txt");
13
+ assert.equal(await key(null, "file.txt/"), "file.txt/");
14
14
  assert.equal(await inverseKey("file.foo"), undefined);
15
- assert.equal(await key("file.foo"), undefined);
15
+ assert.equal(await key(null, "file.foo"), undefined);
16
16
  });
17
17
 
18
18
  test("returns key functions that can map extensions", async () => {
19
19
  const { inverseKey, key } = extensionKeyFunctions(".md", ".json");
20
20
  assert.equal(await inverseKey("file.json"), "file.md");
21
21
  assert.equal(await inverseKey("file.json/"), "file.md");
22
- assert.equal(await key("file.md"), "file.json");
23
- assert.equal(await key("file.md/"), "file.json/");
22
+ assert.equal(await key(null, "file.md"), "file.json");
23
+ assert.equal(await key(null, "file.md/"), "file.json/");
24
24
  assert.equal(await inverseKey("file.foo"), undefined);
25
- assert.equal(await key("file.foo"), undefined);
25
+ assert.equal(await key(null, "file.foo"), undefined);
26
26
  });
27
27
 
28
28
  test("key functions can handle a slash as an explicit extension", async () => {
29
29
  const { inverseKey, key } = extensionKeyFunctions("/", ".html");
30
30
  assert.equal(await inverseKey("file.html"), "file/");
31
31
  assert.equal(await inverseKey("file.html/"), "file/");
32
- assert.equal(await key("file"), undefined);
33
- assert.equal(await key("file/"), "file.html");
32
+ assert.equal(await key(null, "file"), undefined);
33
+ assert.equal(await key(null, "file/"), "file.html");
34
34
  });
35
35
 
36
36
  test("works with map to handle keys that end in a given resultExtension", async () => {
@@ -40,7 +40,7 @@ describe("keyMapsForExtensions", () => {
40
40
  "file3.foo": "won't be mapped",
41
41
  });
42
42
  const { inverseKey, key } = extensionKeyFunctions(".txt");
43
- const fixture = map(files, {
43
+ const fixture = await map(files, {
44
44
  inverseKey,
45
45
  key,
46
46
  value: (sourceValue, sourceKey, tree) => sourceValue.toUpperCase(),
@@ -57,7 +57,7 @@ describe("keyMapsForExtensions", () => {
57
57
  "file3.foo": "won't be mapped",
58
58
  });
59
59
  const { inverseKey, key } = extensionKeyFunctions(".txt", ".upper");
60
- const fixture = map(files, {
60
+ const fixture = await map(files, {
61
61
  inverseKey,
62
62
  key,
63
63
  value: (sourceValue, sourceKey, tree) => sourceValue.toUpperCase(),
@@ -0,0 +1,15 @@
1
+ import assert from "node:assert";
2
+ import { describe, test } from "node:test";
3
+ import first from "../../src/operations/first.js";
4
+
5
+ describe("first", () => {
6
+ test("returns the first value in the tree", async () => {
7
+ const obj = {
8
+ a: 1,
9
+ b: 2,
10
+ c: 3,
11
+ };
12
+ const result = await first(obj);
13
+ assert.equal(result, 1);
14
+ });
15
+ });
@@ -0,0 +1 @@
1
+ This folder is used as a temp directory by some tests
@@ -0,0 +1,22 @@
1
+ import assert from "node:assert";
2
+ import { describe, test } from "node:test";
3
+ import forEach from "../../src/operations/forEach.js";
4
+
5
+ describe("forEach", () => {
6
+ test("invokes a callback for each entry", async () => {
7
+ const fixture = {
8
+ "Alice.md": "Hello, **Alice**.",
9
+ "Bob.md": "Hello, **Bob**.",
10
+ "Carol.md": "Hello, **Carol**.",
11
+ };
12
+ const results = {};
13
+ await forEach(fixture, async (value, key) => {
14
+ results[key] = value;
15
+ });
16
+ assert.deepEqual(results, {
17
+ "Alice.md": "Hello, **Alice**.",
18
+ "Bob.md": "Hello, **Bob**.",
19
+ "Carol.md": "Hello, **Carol**.",
20
+ });
21
+ });
22
+ });
@@ -0,0 +1,67 @@
1
+ import assert from "node:assert";
2
+ import { describe, test } from "node:test";
3
+ import DeepObjectTree from "../../src/drivers/DeepObjectTree.js";
4
+ import ObjectTree from "../../src/drivers/ObjectTree.js";
5
+ import from from "../../src/operations/from.js";
6
+ import plain from "../../src/operations/plain.js";
7
+ import * as symbols from "../../src/symbols.js";
8
+
9
+ describe("from", () => {
10
+ test("returns an async tree as is", async () => {
11
+ const tree1 = new ObjectTree({
12
+ a: "Hello, a.",
13
+ });
14
+ const tree2 = from(tree1);
15
+ assert.equal(tree2, tree1);
16
+ });
17
+
18
+ test("uses an object's unpack() method if defined", async () => {
19
+ const obj = new String();
20
+ /** @type {any} */ (obj).unpack = () => ({
21
+ a: "Hello, a.",
22
+ });
23
+ const tree = from(obj);
24
+ assert.deepEqual(await plain(tree), {
25
+ a: "Hello, a.",
26
+ });
27
+ });
28
+
29
+ test("returns a deep object tree if deep option is true", async () => {
30
+ const obj = {
31
+ sub: {
32
+ a: 1,
33
+ },
34
+ };
35
+ const tree = from(obj, { deep: true });
36
+ assert(tree instanceof DeepObjectTree);
37
+ });
38
+
39
+ test("returns a deep object tree if object has [deep] symbol set", async () => {
40
+ const obj = {
41
+ sub: {
42
+ a: 1,
43
+ },
44
+ };
45
+ Object.defineProperty(obj, symbols.deep, { value: true });
46
+ const tree = from(obj);
47
+ assert(tree instanceof DeepObjectTree);
48
+ });
49
+
50
+ test("creates a deferred tree if unpack() returns a promise", async () => {
51
+ const obj = new String();
52
+ /** @type {any} */ (obj).unpack = async () => ({
53
+ a: "Hello, a.",
54
+ });
55
+ const tree = from(obj);
56
+ assert.deepEqual(await plain(tree), {
57
+ a: "Hello, a.",
58
+ });
59
+ });
60
+
61
+ test("autoboxes primitive values", async () => {
62
+ const tree = from("Hello, world.");
63
+ const slice = await tree.get("slice");
64
+ const result = await slice(0, 5);
65
+ assert.equal(result, "Hello");
66
+ });
67
+ });
@@ -5,7 +5,7 @@ import globKeys from "../../src/operations/globKeys.js";
5
5
 
6
6
  describe("globKeys", () => {
7
7
  test("matches globs", async () => {
8
- const globTree = globKeys({
8
+ const globTree = await globKeys({
9
9
  "*.txt": true,
10
10
  "*.js": false,
11
11
  "*.jsx": true,
@@ -20,7 +20,7 @@ describe("globKeys", () => {
20
20
  });
21
21
 
22
22
  test("matches nested globs", async () => {
23
- const globTree = globKeys({
23
+ const globTree = await globKeys({
24
24
  sub: {
25
25
  foo: "bar",
26
26
  "*": "default",
@@ -31,7 +31,7 @@ describe("globKeys", () => {
31
31
  });
32
32
 
33
33
  test("supports deep matches with globstar", async () => {
34
- const globTree = globKeys({
34
+ const globTree = await globKeys({
35
35
  "**": {
36
36
  "*.txt": true, // More specific glob pattern must come
37
37
  "*": false,
@@ -1,9 +1,9 @@
1
1
  import assert from "node:assert";
2
2
  import { describe, test } from "node:test";
3
3
  import { Tree } from "../../src/internal.js";
4
- import group from "../../src/operations/group.js";
4
+ import groupBy from "../../src/operations/groupBy.js";
5
5
 
6
- describe("group transform", () => {
6
+ describe("groupBy transform", () => {
7
7
  test("groups an array using a group key function", async () => {
8
8
  const fonts = [
9
9
  { name: "Aboreto", tags: ["Sans Serif"] },
@@ -12,7 +12,7 @@ describe("group transform", () => {
12
12
  { name: "Work Sans", tags: ["Grotesque", "Sans Serif"] },
13
13
  ];
14
14
  const tree = Tree.from(fonts);
15
- const grouped = await group(tree, (value, key, tree) => value.tags);
15
+ const grouped = await groupBy(tree, (value, key, tree) => value.tags);
16
16
  assert.deepEqual(await Tree.plain(grouped), {
17
17
  Geometric: [{ name: "Albert Sans", tags: ["Geometric", "Sans Serif"] }],
18
18
  Grotesque: [{ name: "Work Sans", tags: ["Grotesque", "Sans Serif"] }],
@@ -33,7 +33,7 @@ describe("group transform", () => {
33
33
  "Work Sans": { tags: ["Grotesque", "Sans Serif"] },
34
34
  };
35
35
  const tree = Tree.from(fonts);
36
- const grouped = await group(tree, (value, key, tree) => value.tags);
36
+ const grouped = await groupBy(tree, (value, key, tree) => value.tags);
37
37
  assert.deepEqual(await Tree.plain(grouped), {
38
38
  Geometric: {
39
39
  "Albert Sans": { tags: ["Geometric", "Sans Serif"] },
@@ -0,0 +1,15 @@
1
+ import assert from "node:assert";
2
+ import { describe, test } from "node:test";
3
+ import has from "../../src/operations/has.js";
4
+
5
+ describe("has", () => {
6
+ test("has returns true if the key exists", async () => {
7
+ const fixture = {
8
+ "Alice.md": "Hello, **Alice**.",
9
+ "Bob.md": "Hello, **Bob**.",
10
+ "Carol.md": "Hello, **Carol**.",
11
+ };
12
+ assert.equal(await has(fixture, "Alice.md"), true);
13
+ assert.equal(await has(fixture, "David.md"), false);
14
+ });
15
+ });
@@ -0,0 +1,30 @@
1
+ import assert from "node:assert";
2
+ import { describe, test } from "node:test";
3
+ import { DeepObjectTree, Tree } from "../../src/internal.js";
4
+ import inners from "../../src/operations/inners.js";
5
+
6
+ describe("inners", () => {
7
+ test("returns the interior nodes of a tree", async () => {
8
+ const obj = new DeepObjectTree({
9
+ a: 1,
10
+ b: {
11
+ c: 2,
12
+ d: {
13
+ e: 3,
14
+ },
15
+ },
16
+ f: 4,
17
+ g: {
18
+ h: 5,
19
+ },
20
+ });
21
+ const result = await inners(obj);
22
+ const plain = await Tree.plain(result);
23
+ assert.deepEqual(plain, {
24
+ b: {
25
+ d: {},
26
+ },
27
+ g: {},
28
+ });
29
+ });
30
+ });
@@ -5,7 +5,7 @@ import invokeFunctions from "../../src/operations/invokeFunctions.js";
5
5
 
6
6
  describe("invokeFunctions", () => {
7
7
  test("invokes function values, leaves other values as is", async () => {
8
- const fixture = invokeFunctions({
8
+ const fixture = await invokeFunctions({
9
9
  a: 1,
10
10
  b: () => 2,
11
11
  });
@@ -0,0 +1,17 @@
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
+ });
@@ -0,0 +1,26 @@
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
+ });
@@ -0,0 +1,13 @@
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
+ });
@@ -0,0 +1,15 @@
1
+ import assert from "node:assert";
2
+ import { describe, test } from "node:test";
3
+ import keys from "../../src/operations/keys.js";
4
+
5
+ describe("keys", () => {
6
+ test("returns the keys of a tree as an array", async () => {
7
+ const obj = {
8
+ a: 1,
9
+ b: 2,
10
+ c: 3,
11
+ };
12
+ const result = await keys(obj);
13
+ assert.deepEqual(result, ["a", "b", "c"]);
14
+ });
15
+ });
@@ -0,0 +1,15 @@
1
+ import assert from "node:assert";
2
+ import { describe, test } from "node:test";
3
+ import length from "../../src/operations/length.js";
4
+
5
+ describe("length", () => {
6
+ test("returns the number of keys in the tree", async () => {
7
+ const obj = {
8
+ a: 1,
9
+ b: 2,
10
+ c: 3,
11
+ };
12
+ const result = await length(obj);
13
+ assert.equal(result, 3);
14
+ });
15
+ });
@@ -1,6 +1,5 @@
1
1
  import assert from "node:assert";
2
2
  import { describe, test } from "node:test";
3
- import FunctionTree from "../../src/drivers/FunctionTree.js";
4
3
  import { DeepObjectTree, ObjectTree, Tree } from "../../src/internal.js";
5
4
  import map from "../../src/operations/map.js";
6
5
  import * as trailingSlash from "../../src/trailingSlash.js";
@@ -11,8 +10,8 @@ describe("map", () => {
11
10
  a: "letter a",
12
11
  b: "letter b",
13
12
  };
14
- assert.throws(() => {
15
- map(tree, {});
13
+ assert.rejects(async () => {
14
+ await map(tree, {});
16
15
  });
17
16
  });
18
17
 
@@ -22,7 +21,7 @@ describe("map", () => {
22
21
  b: "letter b",
23
22
  c: undefined, // Won't be mapped
24
23
  });
25
- const mapped = map(tree, {
24
+ const mapped = await map(tree, {
26
25
  value: (sourceValue, sourceKey, innerTree) => {
27
26
  assert(sourceKey === "a" || sourceKey === "b");
28
27
  assert.equal(innerTree, tree);
@@ -41,7 +40,7 @@ describe("map", () => {
41
40
  a: "letter a",
42
41
  b: "letter b",
43
42
  };
44
- const uppercaseValues = map(tree, (sourceValue, sourceKey, tree) => {
43
+ const uppercaseValues = await map(tree, (sourceValue, sourceKey, tree) => {
45
44
  assert(sourceKey === "a" || sourceKey === "b");
46
45
  return sourceValue.toUpperCase();
47
46
  });
@@ -56,7 +55,7 @@ describe("map", () => {
56
55
  a: "letter a",
57
56
  b: "letter b",
58
57
  };
59
- const underscoreKeys = map(tree, {
58
+ const underscoreKeys = await map(tree, {
60
59
  key: addUnderscore,
61
60
  inverseKey: removeUnderscore,
62
61
  });
@@ -71,7 +70,7 @@ describe("map", () => {
71
70
  a: "letter a",
72
71
  b: "letter b",
73
72
  };
74
- const underscoreKeys = map(tree, {
73
+ const underscoreKeys = await map(tree, {
75
74
  key: addUnderscore,
76
75
  });
77
76
  assert.deepEqual(await Tree.plain(underscoreKeys), {
@@ -81,18 +80,19 @@ describe("map", () => {
81
80
  });
82
81
 
83
82
  test("maps keys and values", async () => {
84
- const tree = {
85
- a: "letter a",
86
- b: "letter b",
87
- };
88
- const underscoreKeysUppercaseValues = map(tree, {
89
- key: addUnderscore,
90
- inverseKey: removeUnderscore,
91
- value: async (sourceValue, sourceKey, tree) => sourceValue.toUpperCase(),
92
- });
93
- assert.deepEqual(await Tree.plain(underscoreKeysUppercaseValues), {
94
- _a: "LETTER A",
95
- _b: "LETTER B",
83
+ const treelike = new ObjectTree([
84
+ { name: "Alice", age: 1 },
85
+ { name: "Bob", age: 2 },
86
+ { name: "Carol", age: 3 },
87
+ ]);
88
+ const result = await map(treelike, {
89
+ key: (value, key, tree) => value.name,
90
+ value: (value, key, tree) => value.age,
91
+ });
92
+ assert.deepEqual(await Tree.plain(result), {
93
+ Alice: 1,
94
+ Bob: 2,
95
+ Carol: 3,
96
96
  });
97
97
  });
98
98
 
@@ -103,8 +103,8 @@ describe("map", () => {
103
103
  b: "letter b",
104
104
  },
105
105
  };
106
- const underscoreKeys = map(tree, {
107
- key: async (sourceKey, tree) => `_${sourceKey}`,
106
+ const underscoreKeys = await map(tree, {
107
+ key: async (value, sourceKey, tree) => `_${sourceKey}`,
108
108
  inverseKey: async (resultKey, tree) => resultKey.slice(1),
109
109
  value: async (sourceValue, sourceKey, tree) => sourceKey,
110
110
  });
@@ -122,7 +122,7 @@ describe("map", () => {
122
122
  a: "letter a",
123
123
  b: "letter b",
124
124
  };
125
- const mapped = map(tree, uppercase);
125
+ const mapped = await map(tree, uppercase);
126
126
  assert.deepEqual(await Tree.plain(mapped), {
127
127
  _a: "LETTER A",
128
128
  _b: "LETTER B",
@@ -136,7 +136,7 @@ describe("map", () => {
136
136
  b: "letter b",
137
137
  },
138
138
  });
139
- const uppercaseValues = map(tree, {
139
+ const uppercaseValues = await map(tree, {
140
140
  deep: true,
141
141
  value: (sourceValue, sourceKey, tree) => sourceValue.toUpperCase(),
142
142
  });
@@ -155,7 +155,7 @@ describe("map", () => {
155
155
  b: "letter b",
156
156
  },
157
157
  });
158
- const underscoreKeys = map(tree, {
158
+ const underscoreKeys = await map(tree, {
159
159
  deep: true,
160
160
  key: addUnderscore,
161
161
  inverseKey: removeUnderscore,
@@ -175,7 +175,7 @@ describe("map", () => {
175
175
  b: "letter b",
176
176
  },
177
177
  });
178
- const underscoreKeysUppercaseValues = map(tree, {
178
+ const underscoreKeysUppercaseValues = await map(tree, {
179
179
  deep: true,
180
180
  key: addUnderscore,
181
181
  inverseKey: removeUnderscore,
@@ -189,59 +189,28 @@ describe("map", () => {
189
189
  });
190
190
  });
191
191
 
192
- test("can change a key's extension", async () => {
193
- const treelike = {
194
- "file1.lower": "will be mapped",
195
- file2: "won't be mapped",
196
- "file3.foo": "won't be mapped",
197
- };
198
- const fixture = await map(treelike, {
199
- extension: ".lower->.upper",
200
- value: (sourceValue) => sourceValue.toUpperCase(),
201
- });
202
- assert.deepEqual(await Tree.plain(fixture), {
203
- "file1.upper": "WILL BE MAPPED",
204
- });
205
- });
206
-
207
- test("can manipulate extensions deeply", async () => {
208
- const treelike = {
209
- "file1.txt": 1,
210
- more: {
211
- "file2.txt": 2,
212
- },
192
+ test("keyNeedsSourceValue can be set to false in cases where the value isn't necessary", async () => {
193
+ const tree = {
194
+ a: "letter a",
195
+ b: "letter b",
196
+ c: "letter c",
213
197
  };
214
- const fixture = await map(treelike, {
215
- deep: true,
216
- extension: ".txt->",
217
- });
218
- assert.deepEqual(await Tree.plain(fixture), {
219
- file1: 1,
220
- more: {
221
- file2: 2,
198
+ const mapped = await map(tree, {
199
+ keyNeedsSourceValue: false,
200
+ key: (value, key) => {
201
+ assert.equal(value, null);
202
+ return key.toUpperCase();
222
203
  },
223
204
  });
224
- });
225
-
226
- test("needsSourceValue can be set to false in cases where the value isn't necessary", async () => {
227
- let flag = false;
228
- const tree = new FunctionTree(() => {
229
- flag = true;
230
- }, ["a", "b", "c"]);
231
- const mapped = map(tree, {
232
- needsSourceValue: false,
233
- value: () => "X",
234
- });
235
205
  assert.deepEqual(await Tree.plain(mapped), {
236
- a: "X",
237
- b: "X",
238
- c: "X",
206
+ A: "letter a",
207
+ B: "letter b",
208
+ C: "letter c",
239
209
  });
240
- assert(!flag);
241
210
  });
242
211
  });
243
212
 
244
- function addUnderscore(key) {
213
+ function addUnderscore(value, key) {
245
214
  return `_${key}`;
246
215
  }
247
216
 
@@ -0,0 +1,53 @@
1
+ import assert from "node:assert";
2
+ import { describe, test } from "node:test";
3
+ import mapExtension from "../../src/operations/mapExtension.js";
4
+ import plain from "../../src/operations/plain.js";
5
+
6
+ describe("mapExtension", () => {
7
+ test("can add an extension to a key", async () => {
8
+ const treelike = {
9
+ "file0.txt": 1,
10
+ file1: 2,
11
+ file2: 3,
12
+ };
13
+ const fixture = await mapExtension(treelike, "->.data");
14
+ assert.deepEqual(await plain(fixture), {
15
+ "file0.txt.data": 1,
16
+ "file1.data": 2,
17
+ "file2.data": 3,
18
+ });
19
+ });
20
+
21
+ test("can change a key's extension", async () => {
22
+ const treelike = {
23
+ "file1.lower": "will be mapped",
24
+ file2: "won't be mapped",
25
+ "file3.foo": "won't be mapped",
26
+ };
27
+ const fixture = await mapExtension(treelike, {
28
+ extension: ".lower->.upper",
29
+ value: (sourceValue) => sourceValue.toUpperCase(),
30
+ });
31
+ assert.deepEqual(await plain(fixture), {
32
+ "file1.upper": "WILL BE MAPPED",
33
+ });
34
+ });
35
+
36
+ test("can manipulate extensions deeply", async () => {
37
+ const treelike = {
38
+ "file1.txt": 1,
39
+ more: {
40
+ "file2.txt": 2,
41
+ },
42
+ };
43
+ const fixture = await mapExtension(treelike, ".txt->", {
44
+ deep: true,
45
+ });
46
+ assert.deepEqual(await plain(fixture), {
47
+ file1: 1,
48
+ more: {
49
+ file2: 2,
50
+ },
51
+ });
52
+ });
53
+ });
@@ -0,0 +1,23 @@
1
+ import assert from "node:assert";
2
+ import { describe, test } from "node:test";
3
+ import DeepObjectTree from "../../src/drivers/DeepObjectTree.js";
4
+ import mapReduce from "../../src/operations/mapReduce.js";
5
+
6
+ describe("mapReduce", () => {
7
+ test("can map values and reduce them", async () => {
8
+ const tree = new DeepObjectTree({
9
+ a: 1,
10
+ b: 2,
11
+ more: {
12
+ c: 3,
13
+ },
14
+ d: 4,
15
+ });
16
+ const reduced = await mapReduce(
17
+ tree,
18
+ (value) => value,
19
+ async (values) => String.prototype.concat(...values)
20
+ );
21
+ assert.deepEqual(reduced, "1234");
22
+ });
23
+ });
@@ -5,7 +5,7 @@ import mask from "../../src/operations/mask.js";
5
5
 
6
6
  describe("mask", () => {
7
7
  test("removes keys and values whose mask values are falsy", async () => {
8
- const result = mask(
8
+ const result = await mask(
9
9
  {
10
10
  a: 1,
11
11
  b: 2,