@weborigami/async-tree 0.0.54 → 0.0.55
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/main.js +3 -0
- package/package.json +2 -2
- package/src/transforms/deepReverse.js +29 -0
- package/src/transforms/invokeFunctions.js +18 -0
- package/src/transforms/reverse.js +25 -0
- package/src/utilities.d.ts +3 -1
- package/src/utilities.js +40 -0
- package/test/transforms/deepReverse.test.js +24 -0
- package/test/transforms/invokeFunctions.test.js +17 -0
- package/test/transforms/reverse.test.js +23 -0
- package/test/utilities.test.js +25 -0
package/main.js
CHANGED
|
@@ -23,8 +23,11 @@ export { default as sort } from "./src/operations/sort.js";
|
|
|
23
23
|
export { default as take } from "./src/operations/take.js";
|
|
24
24
|
export * as symbols from "./src/symbols.js";
|
|
25
25
|
export { default as cachedKeyFunctions } from "./src/transforms/cachedKeyFunctions.js";
|
|
26
|
+
export { default as deepReverse } from "./src/transforms/deepReverse.js";
|
|
27
|
+
export { default as invokeFunctions } from "./src/transforms/invokeFunctions.js";
|
|
26
28
|
export { default as keyFunctionsForExtensions } from "./src/transforms/keyFunctionsForExtensions.js";
|
|
27
29
|
export { default as mapFn } from "./src/transforms/mapFn.js";
|
|
30
|
+
export { default as reverse } from "./src/transforms/reverse.js";
|
|
28
31
|
export { default as sortFn } from "./src/transforms/sortFn.js";
|
|
29
32
|
export { default as takeFn } from "./src/transforms/takeFn.js";
|
|
30
33
|
export * from "./src/utilities.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/async-tree",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.55",
|
|
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.4.5"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@weborigami/types": "0.0.
|
|
14
|
+
"@weborigami/types": "0.0.55"
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
17
|
"test": "node --test --test-reporter=spec",
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Tree } from "../internal.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Reverse the order of keys at all levels of the tree.
|
|
5
|
+
*
|
|
6
|
+
* @typedef {import("@weborigami/types").AsyncTree} AsyncTree
|
|
7
|
+
* @typedef {import("../../index.ts").Treelike} Treelike
|
|
8
|
+
*
|
|
9
|
+
* @param {Treelike} treelike
|
|
10
|
+
* @returns {AsyncTree}
|
|
11
|
+
*/
|
|
12
|
+
export default function deepReverse(treelike) {
|
|
13
|
+
const tree = Tree.from(treelike);
|
|
14
|
+
return {
|
|
15
|
+
async get(key) {
|
|
16
|
+
let value = await tree.get(key);
|
|
17
|
+
if (Tree.isAsyncTree(value)) {
|
|
18
|
+
value = deepReverse(value);
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
async keys() {
|
|
24
|
+
const keys = Array.from(await tree.keys());
|
|
25
|
+
keys.reverse();
|
|
26
|
+
return keys;
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Tree } from "../internal.js";
|
|
2
|
+
|
|
3
|
+
export default function invokeFunctions(treelike) {
|
|
4
|
+
const tree = Tree.from(treelike);
|
|
5
|
+
return {
|
|
6
|
+
async get(key) {
|
|
7
|
+
let value = await tree.get(key);
|
|
8
|
+
if (typeof value === "function") {
|
|
9
|
+
value = value();
|
|
10
|
+
}
|
|
11
|
+
return value;
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
async keys() {
|
|
15
|
+
return tree.keys();
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Tree } from "../internal.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Reverse the order of the top-level keys in the tree.
|
|
5
|
+
*
|
|
6
|
+
* @typedef {import("@weborigami/types").AsyncTree} AsyncTree
|
|
7
|
+
* @typedef {import("../../index.ts").Treelike} Treelike
|
|
8
|
+
*
|
|
9
|
+
* @param {Treelike} treelike
|
|
10
|
+
* @returns {AsyncTree}
|
|
11
|
+
*/
|
|
12
|
+
export default function reverse(treelike) {
|
|
13
|
+
const tree = Tree.from(treelike);
|
|
14
|
+
return {
|
|
15
|
+
async get(key) {
|
|
16
|
+
return tree.get(key);
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
async keys() {
|
|
20
|
+
const keys = Array.from(await tree.keys());
|
|
21
|
+
keys.reverse();
|
|
22
|
+
return keys;
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
package/src/utilities.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export const hiddenFileNames: string[];
|
|
|
6
6
|
export function isPacked(object: any): object is Packed;
|
|
7
7
|
export function isPlainObject(object: any): object is PlainObject;
|
|
8
8
|
export function isUnpackable(object): object is { unpack: () => any };
|
|
9
|
-
export function isStringLike(
|
|
9
|
+
export function isStringLike(object: any): object is StringLike;
|
|
10
10
|
export function keysFromPath(path: string): string[];
|
|
11
11
|
export const naturalOrder: (a: string, b: string) => number;
|
|
12
|
+
export function pipeline(start: any, ...functions: Function[]): Promise<any>;
|
|
13
|
+
export function toString(object: any): string;
|
package/src/utilities.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const textDecoder = new TextDecoder();
|
|
1
2
|
const TypedArray = Object.getPrototypeOf(Uint8Array);
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -142,3 +143,42 @@ export function keysFromPath(pathname) {
|
|
|
142
143
|
export const naturalOrder = new Intl.Collator(undefined, {
|
|
143
144
|
numeric: true,
|
|
144
145
|
}).compare;
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Apply a series of functions to a value, passing the result of each function
|
|
149
|
+
* to the next one.
|
|
150
|
+
*
|
|
151
|
+
* @param {any} start
|
|
152
|
+
* @param {...Function} fns
|
|
153
|
+
*/
|
|
154
|
+
export async function pipeline(start, ...fns) {
|
|
155
|
+
return fns.reduce(async (acc, fn) => fn(await acc), start);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Return a string form of the object, handling cases not generally handled by
|
|
160
|
+
* the standard JavaScript `toString()` method:
|
|
161
|
+
*
|
|
162
|
+
* 1. If the object is an ArrayBuffer or TypedArray, decode the array as UTF-8.
|
|
163
|
+
* 2. If the object is otherwise a plain JavaScript object with the useless
|
|
164
|
+
* default toString() method, return null instead of "[object Object]". In
|
|
165
|
+
* practice, it's generally more useful to have this method fail than to
|
|
166
|
+
* return a useless string.
|
|
167
|
+
*
|
|
168
|
+
* @param {any} object
|
|
169
|
+
* @returns {string|null}
|
|
170
|
+
*/
|
|
171
|
+
export function toString(object) {
|
|
172
|
+
if (object instanceof ArrayBuffer || object instanceof TypedArray) {
|
|
173
|
+
// Treat the buffer as UTF-8 text.
|
|
174
|
+
const decoded = textDecoder.decode(object);
|
|
175
|
+
// If the result appears to contain non-printable characters, it's probably not a string.
|
|
176
|
+
// https://stackoverflow.com/a/1677660/76472
|
|
177
|
+
const hasNonPrintableCharacters = /[\x00-\x08\x0E-\x1F]/.test(decoded);
|
|
178
|
+
return hasNonPrintableCharacters ? null : decoded;
|
|
179
|
+
} else if (isStringLike(object)) {
|
|
180
|
+
return String(object);
|
|
181
|
+
} else {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Tree } from "@weborigami/async-tree";
|
|
2
|
+
import assert from "node:assert";
|
|
3
|
+
import { describe, test } from "node:test";
|
|
4
|
+
import deepReverse from "../../src/transforms/deepReverse.js";
|
|
5
|
+
|
|
6
|
+
describe("deepReverse", () => {
|
|
7
|
+
test("reverses keys at all levels of a tree", async () => {
|
|
8
|
+
const tree = {
|
|
9
|
+
a: 1,
|
|
10
|
+
b: {
|
|
11
|
+
c: 2,
|
|
12
|
+
d: 3,
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
const reversed = deepReverse.call(null, tree);
|
|
16
|
+
assert.deepEqual(await Tree.plain(reversed), {
|
|
17
|
+
b: {
|
|
18
|
+
d: 3,
|
|
19
|
+
c: 2,
|
|
20
|
+
},
|
|
21
|
+
a: 1,
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import { Tree } from "../../src/internal.js";
|
|
4
|
+
import invokeFunctions from "../../src/transforms/invokeFunctions.js";
|
|
5
|
+
|
|
6
|
+
describe("invokeFunctions", () => {
|
|
7
|
+
test("invokes function values, leaves other values as is", async () => {
|
|
8
|
+
const fixture = invokeFunctions({
|
|
9
|
+
a: 1,
|
|
10
|
+
b: () => 2,
|
|
11
|
+
});
|
|
12
|
+
assert.deepEqual(await Tree.plain(fixture), {
|
|
13
|
+
a: 1,
|
|
14
|
+
b: 2,
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Tree } from "@weborigami/async-tree";
|
|
2
|
+
import assert from "node:assert";
|
|
3
|
+
import { describe, test } from "node:test";
|
|
4
|
+
import reverse from "../../src/transforms/reverse.js";
|
|
5
|
+
|
|
6
|
+
describe("reverse", () => {
|
|
7
|
+
test("reverses a tree's top-level keys", async () => {
|
|
8
|
+
const tree = {
|
|
9
|
+
a: "A",
|
|
10
|
+
b: "B",
|
|
11
|
+
c: "C",
|
|
12
|
+
};
|
|
13
|
+
const reversed = reverse.call(null, tree);
|
|
14
|
+
// @ts-ignore
|
|
15
|
+
assert.deepEqual(Array.from(await reversed.keys()), ["c", "b", "a"]);
|
|
16
|
+
// @ts-ignore
|
|
17
|
+
assert.deepEqual(await Tree.plain(reversed), {
|
|
18
|
+
c: "C",
|
|
19
|
+
b: "B",
|
|
20
|
+
a: "A",
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
});
|
package/test/utilities.test.js
CHANGED
|
@@ -27,4 +27,29 @@ describe("utilities", () => {
|
|
|
27
27
|
strings.sort(utilities.naturalOrder);
|
|
28
28
|
assert.deepEqual(strings, ["file1", "file9", "file10"]);
|
|
29
29
|
});
|
|
30
|
+
|
|
31
|
+
test("pipeline applies a series of functions to a value", async () => {
|
|
32
|
+
const addOne = (n) => n + 1;
|
|
33
|
+
const double = (n) => n * 2;
|
|
34
|
+
const square = (n) => n * n;
|
|
35
|
+
const result = await utilities.pipeline(1, addOne, double, square);
|
|
36
|
+
assert.equal(result, 16);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("toString returns the value of an object's `toString` method", () => {
|
|
40
|
+
const object = {
|
|
41
|
+
toString: () => "text",
|
|
42
|
+
};
|
|
43
|
+
assert.equal(utilities.toString(object), "text");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("toString returns null for an object with no useful `toString`", () => {
|
|
47
|
+
const object = {};
|
|
48
|
+
assert.equal(utilities.toString(object), null);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("toString decodes an ArrayBuffer as UTF-8", () => {
|
|
52
|
+
const buffer = Buffer.from("text", "utf8");
|
|
53
|
+
assert.equal(utilities.toString(buffer), "text");
|
|
54
|
+
});
|
|
30
55
|
});
|