@weborigami/async-tree 0.5.1 → 0.5.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 +6 -0
- package/package.json +2 -2
- package/src/Tree.d.ts +1 -1
- package/src/Tree.js +28 -5
- package/src/utilities.d.ts +1 -0
- package/src/utilities.js +30 -0
- package/test/Tree.test.js +21 -0
package/index.ts
CHANGED
|
@@ -20,6 +20,7 @@ export type HasString = {
|
|
|
20
20
|
* an HTTP response via response.write, or readily converted to such a form.
|
|
21
21
|
*/
|
|
22
22
|
export type Packed = (ArrayBuffer | Buffer | ReadableStream | string | String | TypedArray) & {
|
|
23
|
+
parent?: AsyncTree|null;
|
|
23
24
|
unpack?(): Promise<any>;
|
|
24
25
|
};
|
|
25
26
|
|
|
@@ -70,4 +71,9 @@ export type Unpackable<T> = {
|
|
|
70
71
|
unpack(): Promise<T>
|
|
71
72
|
};
|
|
72
73
|
|
|
74
|
+
/**
|
|
75
|
+
* A function that converts a value from a persistent form into a live value.
|
|
76
|
+
*/
|
|
77
|
+
export type UnpackFunction = (input: Packed, options?: any) => any;
|
|
78
|
+
|
|
73
79
|
export type ValueKeyFn = (value: any, key: any, innerTree: AsyncTree) => any;
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/async-tree",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
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
|
"dependencies": {
|
|
10
|
-
"@weborigami/types": "0.5.
|
|
10
|
+
"@weborigami/types": "0.5.2"
|
|
11
11
|
},
|
|
12
12
|
"devDependencies": {
|
|
13
13
|
"@types/node": "24.3.0",
|
package/src/Tree.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export function isTraversable(obj: any): boolean;
|
|
|
13
13
|
export function isTreelike(obj: any): obj is Treelike;
|
|
14
14
|
export function map(tree: Treelike, options: TreeMapOptions|ValueKeyFn): AsyncTree;
|
|
15
15
|
export function mapReduce(tree: Treelike, mapFn: ValueKeyFn | null, reduceFn: ReduceFn): Promise<any>;
|
|
16
|
-
export function paths(tree: Treelike, base?: string): string[];
|
|
16
|
+
export function paths(tree: Treelike, options?: { assumeSlashes?: boolean, base?: string }): string[];
|
|
17
17
|
export function plain(tree: Treelike): Promise<PlainObject>;
|
|
18
18
|
export function root(tree: Treelike): AsyncTree;
|
|
19
19
|
export function remove(AsyncTree: AsyncMutableTree, key: any): Promise<boolean>;
|
package/src/Tree.js
CHANGED
|
@@ -291,18 +291,41 @@ export async function mapReduce(treelike, valueFn, reduceFn) {
|
|
|
291
291
|
/**
|
|
292
292
|
* Returns slash-separated paths for all values in the tree.
|
|
293
293
|
*
|
|
294
|
+
* The `base` argument is prepended to all paths.
|
|
295
|
+
*
|
|
296
|
+
* If `assumeSlashes` is true, then keys are assumed to have trailing slashes to
|
|
297
|
+
* indicate subtrees. The default value of this option is false.
|
|
298
|
+
*
|
|
294
299
|
* @param {Treelike} treelike
|
|
295
|
-
* @param {string
|
|
300
|
+
* @param {{ assumeSlashes?: boolean, base?: string }} options
|
|
296
301
|
*/
|
|
297
|
-
export async function paths(treelike,
|
|
302
|
+
export async function paths(treelike, options = {}) {
|
|
298
303
|
const tree = from(treelike);
|
|
304
|
+
const base = options.base ?? "";
|
|
305
|
+
const assumeSlashes = options.assumeSlashes ?? false;
|
|
299
306
|
const result = [];
|
|
300
307
|
for (const key of await tree.keys()) {
|
|
301
308
|
const separator = trailingSlash.has(base) ? "" : "/";
|
|
302
309
|
const valuePath = base ? `${base}${separator}${key}` : key;
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
310
|
+
let isSubtree;
|
|
311
|
+
let value;
|
|
312
|
+
if (assumeSlashes) {
|
|
313
|
+
// Subtree needs to have a trailing slash
|
|
314
|
+
isSubtree = trailingSlash.has(key);
|
|
315
|
+
if (isSubtree) {
|
|
316
|
+
// We'll need the value to recurse
|
|
317
|
+
value = await tree.get(key);
|
|
318
|
+
}
|
|
319
|
+
} else {
|
|
320
|
+
// Get value and check
|
|
321
|
+
value = await tree.get(key);
|
|
322
|
+
}
|
|
323
|
+
if (value) {
|
|
324
|
+
// If we got the value we can check if it's a subtree
|
|
325
|
+
isSubtree = isAsyncTree(value);
|
|
326
|
+
}
|
|
327
|
+
if (isSubtree) {
|
|
328
|
+
const subPaths = await paths(value, { assumeSlashes, base: valuePath });
|
|
306
329
|
result.push(...subPaths);
|
|
307
330
|
} else {
|
|
308
331
|
result.push(valuePath);
|
package/src/utilities.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { Packed, PlainObject, StringLike } from "../index.ts";
|
|
|
4
4
|
export function assertIsTreelike(object: any, operation: string, position?: number): void;
|
|
5
5
|
export function box(value: any): any;
|
|
6
6
|
export function castArrayLike(keys: any[], values: any[]): any;
|
|
7
|
+
export function getParent(object: any, options?: any): AsyncTree|null;
|
|
7
8
|
export function getRealmObjectPrototype(object: any): any;
|
|
8
9
|
export const hiddenFileNames: string[];
|
|
9
10
|
export function isPacked(obj: any): obj is Packed;
|
package/src/utilities.js
CHANGED
|
@@ -87,6 +87,36 @@ export function castArrayLike(keys, values) {
|
|
|
87
87
|
: Object.fromEntries(keys.map((key, i) => [key, values[i]]));
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Return a suitable parent for the packed file.
|
|
92
|
+
*
|
|
93
|
+
* This is intended to be called by unpack functions.
|
|
94
|
+
*
|
|
95
|
+
* @param {any} packed
|
|
96
|
+
* @param {any} [options]
|
|
97
|
+
* @returns {AsyncTree|null}
|
|
98
|
+
*/
|
|
99
|
+
export function getParent(packed, options = {}) {
|
|
100
|
+
// Prefer parent set on options
|
|
101
|
+
if (options?.parent) {
|
|
102
|
+
return options.parent;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// If the packed object has a `parent` property, use that. Exception: Node
|
|
106
|
+
// Buffer objects have a `parent` property that we ignore.
|
|
107
|
+
if (packed.parent && !(packed instanceof Buffer)) {
|
|
108
|
+
return packed.parent;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// If the packed object has a parent symbol, use that.
|
|
112
|
+
if (packed[symbols.parent]) {
|
|
113
|
+
return packed[symbols.parent];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Otherwise, return null.
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
|
|
90
120
|
/**
|
|
91
121
|
* Return the Object prototype at the root of the object's prototype chain.
|
|
92
122
|
*
|
package/test/Tree.test.js
CHANGED
|
@@ -232,6 +232,27 @@ describe("Tree", () => {
|
|
|
232
232
|
assert.deepEqual(await Tree.paths(tree), ["a", "b", "c/d", "c/e"]);
|
|
233
233
|
});
|
|
234
234
|
|
|
235
|
+
test("paths can focus just on keys with trailing slashes", async () => {
|
|
236
|
+
const tree = new ObjectTree({
|
|
237
|
+
a: 1,
|
|
238
|
+
b: 2,
|
|
239
|
+
// This is a shallow ObjectTree, so `c` won't have a trailing slash
|
|
240
|
+
c: {
|
|
241
|
+
d: 3,
|
|
242
|
+
},
|
|
243
|
+
// Explicitly include a trailing slash to signal a subtree
|
|
244
|
+
"d/": new ObjectTree({
|
|
245
|
+
e: 4,
|
|
246
|
+
}),
|
|
247
|
+
});
|
|
248
|
+
assert.deepEqual(await Tree.paths(tree, { assumeSlashes: true }), [
|
|
249
|
+
"a",
|
|
250
|
+
"b",
|
|
251
|
+
"c",
|
|
252
|
+
"d/e",
|
|
253
|
+
]);
|
|
254
|
+
});
|
|
255
|
+
|
|
235
256
|
test("plain() produces a plain object version of a tree", async () => {
|
|
236
257
|
const tree = new ObjectTree({
|
|
237
258
|
a: 1,
|