@weborigami/async-tree 0.5.8 → 0.6.0
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/browser.js +1 -1
- package/index.ts +31 -35
- package/main.js +1 -2
- package/package.json +4 -7
- package/shared.js +77 -12
- package/src/Tree.js +8 -2
- package/src/drivers/AsyncMap.js +210 -0
- package/src/drivers/{BrowserFileTree.js → BrowserFileMap.js} +36 -27
- package/src/drivers/{calendarTree.js → CalendarMap.js} +81 -62
- package/src/drivers/ConstantMap.js +30 -0
- package/src/drivers/DeepObjectMap.js +27 -0
- package/src/drivers/{ExplorableSiteTree.js → ExplorableSiteMap.js} +7 -7
- package/src/drivers/FileMap.js +245 -0
- package/src/drivers/{FunctionTree.js → FunctionMap.js} +19 -22
- package/src/drivers/ObjectMap.js +139 -0
- package/src/drivers/SetMap.js +13 -0
- package/src/drivers/{SiteTree.js → SiteMap.js} +16 -17
- package/src/drivers/SyncMap.js +245 -0
- package/src/jsonKeys.d.ts +2 -2
- package/src/jsonKeys.js +6 -5
- package/src/operations/addNextPrevious.js +35 -36
- package/src/operations/assign.js +30 -21
- package/src/operations/cache.js +29 -35
- package/src/operations/cachedKeyFunctions.js +1 -1
- package/src/operations/calendar.js +5 -0
- package/src/operations/clear.js +13 -12
- package/src/operations/constant.js +5 -0
- package/src/operations/deepEntries.js +23 -0
- package/src/operations/deepMap.js +9 -9
- package/src/operations/deepMerge.js +36 -25
- package/src/operations/deepReverse.js +23 -16
- package/src/operations/deepTake.js +7 -7
- package/src/operations/deepText.js +4 -4
- package/src/operations/deepValues.js +3 -6
- package/src/operations/deepValuesIterator.js +11 -11
- package/src/operations/delete.js +8 -12
- package/src/operations/entries.js +17 -10
- package/src/operations/filter.js +9 -7
- package/src/operations/first.js +12 -10
- package/src/operations/forEach.js +10 -13
- package/src/operations/from.js +31 -39
- package/src/operations/globKeys.js +22 -17
- package/src/operations/group.js +2 -2
- package/src/operations/groupBy.js +24 -22
- package/src/operations/has.js +7 -9
- package/src/operations/indent.js +2 -2
- package/src/operations/inners.js +19 -15
- package/src/operations/invokeFunctions.js +22 -10
- package/src/operations/isAsyncMutableTree.js +5 -12
- package/src/operations/isAsyncTree.js +5 -20
- package/src/operations/isMap.js +39 -0
- package/src/operations/isMaplike.js +34 -0
- package/src/operations/isReadOnlyMap.js +14 -0
- package/src/operations/isTraversable.js +3 -3
- package/src/operations/isTreelike.js +5 -30
- package/src/operations/json.js +4 -12
- package/src/operations/keys.js +17 -8
- package/src/operations/length.js +9 -8
- package/src/operations/map.js +27 -30
- package/src/operations/mapExtension.js +20 -16
- package/src/operations/mapReduce.js +22 -17
- package/src/operations/mask.js +31 -22
- package/src/operations/match.js +13 -9
- package/src/operations/merge.js +43 -35
- package/src/operations/paginate.js +26 -18
- package/src/operations/parent.js +7 -7
- package/src/operations/paths.js +8 -8
- package/src/operations/plain.js +6 -6
- package/src/operations/regExpKeys.js +21 -12
- package/src/operations/reverse.js +21 -15
- package/src/operations/root.js +6 -5
- package/src/operations/scope.js +31 -26
- package/src/operations/shuffle.js +23 -16
- package/src/operations/size.js +13 -0
- package/src/operations/sort.js +55 -40
- package/src/operations/sync.js +21 -0
- package/src/operations/take.js +23 -11
- package/src/operations/text.js +4 -4
- package/src/operations/toFunction.js +7 -7
- package/src/operations/traverse.js +4 -4
- package/src/operations/traverseOrThrow.js +13 -9
- package/src/operations/traversePath.js +2 -2
- package/src/operations/values.js +18 -9
- package/src/operations/withKeys.js +22 -16
- package/src/symbols.js +1 -0
- package/src/utilities/castArraylike.js +10 -2
- package/src/utilities/getMapArgument.js +38 -0
- package/src/utilities/getParent.js +2 -2
- package/src/utilities/isStringlike.js +7 -5
- package/src/utilities/setParent.js +7 -7
- package/src/utilities/toFunction.js +2 -2
- package/src/utilities/toPlainValue.js +22 -18
- package/test/SampleAsyncMap.js +34 -0
- package/test/browser/assert.js +20 -0
- package/test/browser/index.html +54 -21
- package/test/drivers/AsyncMap.test.js +119 -0
- package/test/drivers/{BrowserFileTree.test.js → BrowserFileMap.test.js} +42 -23
- package/test/drivers/{calendarTree.test.js → CalendarMap.test.js} +17 -19
- package/test/drivers/ConstantMap.test.js +15 -0
- package/test/drivers/DeepObjectMap.test.js +36 -0
- package/test/drivers/{ExplorableSiteTree.test.js → ExplorableSiteMap.test.js} +29 -14
- package/test/drivers/FileMap.test.js +185 -0
- package/test/drivers/FunctionMap.test.js +56 -0
- package/test/drivers/ObjectMap.test.js +166 -0
- package/test/drivers/SetMap.test.js +35 -0
- package/test/drivers/{SiteTree.test.js → SiteMap.test.js} +14 -10
- package/test/drivers/SyncMap.test.js +321 -0
- package/test/jsonKeys.test.js +2 -2
- package/test/operations/addNextPrevious.test.js +3 -2
- package/test/operations/assign.test.js +30 -35
- package/test/operations/cache.test.js +8 -6
- package/test/operations/cachedKeyFunctions.test.js +6 -5
- package/test/operations/clear.test.js +6 -27
- package/test/operations/deepEntries.test.js +32 -0
- package/test/operations/deepMerge.test.js +6 -5
- package/test/operations/deepReverse.test.js +2 -2
- package/test/operations/deepTake.test.js +2 -2
- package/test/operations/deepText.test.js +4 -4
- package/test/operations/deepValuesIterator.test.js +2 -2
- package/test/operations/delete.test.js +2 -2
- package/test/operations/extensionKeyFunctions.test.js +6 -5
- package/test/operations/filter.test.js +3 -3
- package/test/operations/from.test.js +23 -31
- package/test/operations/globKeys.test.js +9 -9
- package/test/operations/groupBy.test.js +6 -5
- package/test/operations/inners.test.js +4 -4
- package/test/operations/invokeFunctions.test.js +2 -2
- package/test/operations/isMap.test.js +15 -0
- package/test/operations/isMaplike.test.js +15 -0
- package/test/operations/json.test.js +2 -2
- package/test/operations/keys.test.js +16 -3
- package/test/operations/map.test.js +20 -18
- package/test/operations/mapExtension.test.js +6 -6
- package/test/operations/mapReduce.test.js +2 -2
- package/test/operations/mask.test.js +4 -3
- package/test/operations/match.test.js +2 -2
- package/test/operations/merge.test.js +15 -11
- package/test/operations/paginate.test.js +5 -5
- package/test/operations/parent.test.js +3 -3
- package/test/operations/paths.test.js +6 -6
- package/test/operations/plain.test.js +8 -8
- package/test/operations/regExpKeys.test.js +12 -11
- package/test/operations/reverse.test.js +4 -3
- package/test/operations/scope.test.js +6 -5
- package/test/operations/shuffle.test.js +3 -2
- package/test/operations/sort.test.js +7 -10
- package/test/operations/sync.test.js +43 -0
- package/test/operations/take.test.js +2 -2
- package/test/operations/toFunction.test.js +2 -2
- package/test/operations/traverse.test.js +4 -5
- package/test/operations/withKeys.test.js +2 -2
- package/test/utilities/setParent.test.js +6 -6
- package/test/utilities/toFunction.test.js +2 -2
- package/test/utilities/toPlainValue.test.js +51 -12
- package/src/drivers/DeepMapTree.js +0 -23
- package/src/drivers/DeepObjectTree.js +0 -18
- package/src/drivers/DeferredTree.js +0 -81
- package/src/drivers/FileTree.js +0 -276
- package/src/drivers/MapTree.js +0 -70
- package/src/drivers/ObjectTree.js +0 -158
- package/src/drivers/SetTree.js +0 -34
- package/src/drivers/constantTree.js +0 -19
- package/src/drivers/limitConcurrency.js +0 -63
- package/src/internal.js +0 -16
- package/src/utilities/getTreeArgument.js +0 -43
- package/test/drivers/DeepMapTree.test.js +0 -17
- package/test/drivers/DeepObjectTree.test.js +0 -35
- package/test/drivers/DeferredTree.test.js +0 -22
- package/test/drivers/FileTree.test.js +0 -192
- package/test/drivers/FunctionTree.test.js +0 -46
- package/test/drivers/MapTree.test.js +0 -59
- package/test/drivers/ObjectTree.test.js +0 -163
- package/test/drivers/SetTree.test.js +0 -44
- package/test/drivers/constantTree.test.js +0 -13
- package/test/drivers/limitConcurrency.test.js +0 -41
- package/test/operations/isAsyncMutableTree.test.js +0 -17
- package/test/operations/isAsyncTree.test.js +0 -26
- package/test/operations/isTreelike.test.js +0 -13
package/browser.js
CHANGED
package/index.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import AsyncMap from "./src/drivers/AsyncMap.js";
|
|
2
2
|
|
|
3
3
|
export * from "./main.js";
|
|
4
4
|
|
|
5
|
-
export type Invocable = Function |
|
|
5
|
+
export type Invocable = Function | Maplike | Unpackable;
|
|
6
6
|
|
|
7
|
-
export type KeyFn = (key: any,
|
|
7
|
+
export type KeyFn = (key: any, map: SyncOrAsyncMap) => any;
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* An object with a non-trivial `toString` method.
|
|
@@ -17,36 +17,23 @@ export type HasString = {
|
|
|
17
17
|
toString(): string;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
unpack?(): Promise<any>;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export type PlainObject = {
|
|
30
|
-
[key: string]: any;
|
|
20
|
+
export type MapExtensionOptions = {
|
|
21
|
+
deep?: boolean;
|
|
22
|
+
description?: string;
|
|
23
|
+
extension?: string;
|
|
24
|
+
needsSourceValue?: boolean;
|
|
25
|
+
value?: ValueKeyFn;
|
|
31
26
|
};
|
|
32
27
|
|
|
33
|
-
export type
|
|
34
|
-
|
|
35
|
-
export type Stringlike = string | HasString;
|
|
36
|
-
|
|
37
|
-
export type NativeTreelike =
|
|
28
|
+
export type Maplike =
|
|
38
29
|
any[] |
|
|
39
|
-
|
|
30
|
+
Iterator<any> |
|
|
40
31
|
Function |
|
|
41
|
-
|
|
32
|
+
SyncOrAsyncMap |
|
|
42
33
|
PlainObject |
|
|
43
34
|
Set<any>;
|
|
44
35
|
|
|
45
|
-
export type
|
|
46
|
-
NativeTreelike |
|
|
47
|
-
Unpackable;
|
|
48
|
-
|
|
49
|
-
export type TreeMapOptions = {
|
|
36
|
+
export type MapOptions = {
|
|
50
37
|
deep?: boolean;
|
|
51
38
|
description?: string;
|
|
52
39
|
extension?: string;
|
|
@@ -56,15 +43,24 @@ export type TreeMapOptions = {
|
|
|
56
43
|
value?: ValueKeyFn;
|
|
57
44
|
};
|
|
58
45
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
46
|
+
/**
|
|
47
|
+
* A packed value is one that can be written to a file via fs.writeFile or into
|
|
48
|
+
* an HTTP response via response.write, or readily converted to such a form.
|
|
49
|
+
*/
|
|
50
|
+
export type Packed = (ArrayBuffer | Buffer | ReadableStream | string | String | TypedArray) & {
|
|
51
|
+
parent?: SyncOrAsyncMap|null;
|
|
52
|
+
unpack?(): Promise<any>;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export type PlainObject = {
|
|
56
|
+
[key: string]: any;
|
|
65
57
|
};
|
|
66
|
-
|
|
67
|
-
export type
|
|
58
|
+
|
|
59
|
+
export type ReduceFn = (values: any[], keys: any[], map: SyncOrAsyncMap) => any | Promise<any>;
|
|
60
|
+
|
|
61
|
+
export type Stringlike = string | HasString;
|
|
62
|
+
|
|
63
|
+
export type SyncOrAsyncMap = Map<any, any> | AsyncMap;
|
|
68
64
|
|
|
69
65
|
export type TypedArray =
|
|
70
66
|
Float32Array |
|
|
@@ -86,4 +82,4 @@ export type Unpackable = {
|
|
|
86
82
|
*/
|
|
87
83
|
export type UnpackFunction = (input: Packed, options?: any) => any;
|
|
88
84
|
|
|
89
|
-
export type ValueKeyFn = (value: any, key: any,
|
|
85
|
+
export type ValueKeyFn = (value: any, key: any, map: SyncOrAsyncMap) => any;
|
package/main.js
CHANGED
package/package.json
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/async-tree",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
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
|
-
"dependencies": {
|
|
10
|
-
"@weborigami/types": "0.5.8"
|
|
11
|
-
},
|
|
12
9
|
"devDependencies": {
|
|
13
|
-
"@types/node": "24.
|
|
14
|
-
"puppeteer": "24.
|
|
15
|
-
"typescript": "5.9.
|
|
10
|
+
"@types/node": "24.10.1",
|
|
11
|
+
"puppeteer": "24.30.0",
|
|
12
|
+
"typescript": "5.9.3"
|
|
16
13
|
},
|
|
17
14
|
"scripts": {
|
|
18
15
|
"headlessTest": "node test/browser/headlessTest.js",
|
package/shared.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
// Exports for both Node.js and browser
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export { default as
|
|
12
|
-
export { default as
|
|
13
|
-
export { default as
|
|
3
|
+
import { default as DeepObjectMap } from "./src/drivers/DeepObjectMap.js";
|
|
4
|
+
import { default as ExplorableSiteMap } from "./src/drivers/ExplorableSiteMap.js";
|
|
5
|
+
import { default as FileMap } from "./src/drivers/FileMap.js";
|
|
6
|
+
import { default as FunctionMap } from "./src/drivers/FunctionMap.js";
|
|
7
|
+
import { default as ObjectMap } from "./src/drivers/ObjectMap.js";
|
|
8
|
+
import { default as SetMap } from "./src/drivers/SetMap.js";
|
|
9
|
+
import { default as SiteMap } from "./src/drivers/SiteMap.js";
|
|
10
|
+
|
|
11
|
+
export { default as AsyncMap } from "./src/drivers/AsyncMap.js";
|
|
12
|
+
export { default as CalendarMap } from "./src/drivers/CalendarMap.js";
|
|
13
|
+
export { default as ConstantMap } from "./src/drivers/ConstantMap.js";
|
|
14
|
+
export { default as SyncMap } from "./src/drivers/SyncMap.js";
|
|
15
|
+
export * as extension from "./src/extension.js";
|
|
14
16
|
export * as jsonKeys from "./src/jsonKeys.js";
|
|
15
17
|
export { default as scope } from "./src/operations/scope.js";
|
|
16
18
|
export * as symbols from "./src/symbols.js";
|
|
@@ -19,9 +21,9 @@ export { default as TraverseError } from "./src/TraverseError.js";
|
|
|
19
21
|
export * as Tree from "./src/Tree.js";
|
|
20
22
|
export { default as box } from "./src/utilities/box.js";
|
|
21
23
|
export { default as castArraylike } from "./src/utilities/castArraylike.js";
|
|
24
|
+
export { default as getTreeArgument } from "./src/utilities/getMapArgument.js";
|
|
22
25
|
export { default as getParent } from "./src/utilities/getParent.js";
|
|
23
26
|
export { default as getRealmObjectPrototype } from "./src/utilities/getRealmObjectPrototype.js";
|
|
24
|
-
export { default as getTreeArgument } from "./src/utilities/getTreeArgument.js";
|
|
25
27
|
export { default as isPacked } from "./src/utilities/isPacked.js";
|
|
26
28
|
export { default as isPlainObject } from "./src/utilities/isPlainObject.js";
|
|
27
29
|
export { default as isStringlike } from "./src/utilities/isStringlike.js";
|
|
@@ -32,3 +34,66 @@ export { default as pathFromKeys } from "./src/utilities/pathFromKeys.js";
|
|
|
32
34
|
export { default as setParent } from "./src/utilities/setParent.js";
|
|
33
35
|
export { default as toPlainValue } from "./src/utilities/toPlainValue.js";
|
|
34
36
|
export { default as toString } from "./src/utilities/toString.js";
|
|
37
|
+
|
|
38
|
+
export {
|
|
39
|
+
DeepObjectMap,
|
|
40
|
+
ExplorableSiteMap,
|
|
41
|
+
FileMap,
|
|
42
|
+
FunctionMap,
|
|
43
|
+
ObjectMap,
|
|
44
|
+
SetMap,
|
|
45
|
+
SiteMap,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export class ObjectTree extends ObjectMap {
|
|
49
|
+
constructor(...args) {
|
|
50
|
+
super(...args);
|
|
51
|
+
console.warn("ObjectTree is deprecated. Please use ObjectMap instead.");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export class DeepObjectTree extends DeepObjectMap {
|
|
56
|
+
constructor(...args) {
|
|
57
|
+
super(...args);
|
|
58
|
+
console.warn(
|
|
59
|
+
"DeepObjectTree is deprecated. Please use DeepObjectMap instead."
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export class ExplorableSiteTree extends ExplorableSiteMap {
|
|
65
|
+
constructor(href) {
|
|
66
|
+
super(href);
|
|
67
|
+
console.warn(
|
|
68
|
+
"ExplorableSiteTree is deprecated. Please use ExplorableSiteMap instead."
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export class FileTree extends FileMap {
|
|
74
|
+
constructor(...args) {
|
|
75
|
+
super(...args);
|
|
76
|
+
console.warn("FileTree is deprecated. Please use FileMap instead.");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export class FunctionTree extends FunctionMap {
|
|
81
|
+
constructor(...args) {
|
|
82
|
+
super(...args);
|
|
83
|
+
console.warn("FunctionTree is deprecated. Please use FunctionMap instead.");
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export class SetTree extends SetMap {
|
|
88
|
+
constructor(set) {
|
|
89
|
+
super(set);
|
|
90
|
+
console.warn("SetTree is deprecated. Please use SetMap instead.");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export class SiteTree extends SiteMap {
|
|
95
|
+
constructor(...args) {
|
|
96
|
+
super(...args);
|
|
97
|
+
console.warn("SiteTree is deprecated. Please use SiteMap instead.");
|
|
98
|
+
}
|
|
99
|
+
}
|
package/src/Tree.js
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
* Collection of functions for working with async trees
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
export { default as calendar } from "./drivers/calendarTree.js";
|
|
6
|
-
export { default as constant } from "./drivers/constantTree.js";
|
|
7
5
|
export { default as addNextPrevious } from "./operations/addNextPrevious.js";
|
|
8
6
|
export { default as assign } from "./operations/assign.js";
|
|
9
7
|
export { default as cache } from "./operations/cache.js";
|
|
8
|
+
export { default as calendar } from "./operations/calendar.js";
|
|
10
9
|
export { default as clear } from "./operations/clear.js";
|
|
10
|
+
export { default as constant } from "./operations/constant.js";
|
|
11
|
+
export { default as deepEntries } from "./operations/deepEntries.js";
|
|
11
12
|
export { default as deepMap } from "./operations/deepMap.js";
|
|
12
13
|
export { default as deepMerge } from "./operations/deepMerge.js";
|
|
13
14
|
export { default as deepReverse } from "./operations/deepReverse.js";
|
|
@@ -30,6 +31,9 @@ export { default as inners } from "./operations/inners.js";
|
|
|
30
31
|
export { default as invokeFunctions } from "./operations/invokeFunctions.js";
|
|
31
32
|
export { default as isAsyncMutableTree } from "./operations/isAsyncMutableTree.js";
|
|
32
33
|
export { default as isAsyncTree } from "./operations/isAsyncTree.js";
|
|
34
|
+
export { default as isMap } from "./operations/isMap.js";
|
|
35
|
+
export { default as isMaplike } from "./operations/isMaplike.js";
|
|
36
|
+
export { default as isReadOnlyMap } from "./operations/isReadOnlyMap.js";
|
|
33
37
|
export { default as isTraversable } from "./operations/isTraversable.js";
|
|
34
38
|
export { default as isTreelike } from "./operations/isTreelike.js";
|
|
35
39
|
export { default as json } from "./operations/json.js";
|
|
@@ -50,7 +54,9 @@ export { default as reverse } from "./operations/reverse.js";
|
|
|
50
54
|
export { default as root } from "./operations/root.js";
|
|
51
55
|
export { default as scope } from "./operations/scope.js";
|
|
52
56
|
export { default as shuffle } from "./operations/shuffle.js";
|
|
57
|
+
export { default as size } from "./operations/size.js";
|
|
53
58
|
export { default as sort } from "./operations/sort.js";
|
|
59
|
+
export { default as sync } from "./operations/sync.js";
|
|
54
60
|
export { default as take } from "./operations/take.js";
|
|
55
61
|
export { default as text } from "./operations/text.js";
|
|
56
62
|
export { default as toFunction } from "./operations/toFunction.js";
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import * as trailingSlash from "../trailingSlash.js";
|
|
2
|
+
|
|
3
|
+
export default class AsyncMap {
|
|
4
|
+
/** @type {AsyncMap|null} */
|
|
5
|
+
_parent = null;
|
|
6
|
+
|
|
7
|
+
_readOnly;
|
|
8
|
+
|
|
9
|
+
[Symbol.asyncIterator]() {
|
|
10
|
+
return this.entries();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Remove all key/value entries from the map.
|
|
15
|
+
*
|
|
16
|
+
* This method invokes the `keys()` and `delete()` methods.
|
|
17
|
+
*/
|
|
18
|
+
async clear() {
|
|
19
|
+
for await (const key of this.keys()) {
|
|
20
|
+
await this.delete(key);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Removes the entry for the given key, return true if an entry was removed
|
|
26
|
+
* and false if there was no entry for the key.
|
|
27
|
+
*
|
|
28
|
+
* @param {any} key
|
|
29
|
+
* @returns {Promise<boolean>}
|
|
30
|
+
*/
|
|
31
|
+
async delete(key) {
|
|
32
|
+
throw new Error("delete() not implemented");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static EMPTY = Symbol("EMPTY");
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Returns a new `AsyncIterator` object that contains a two-member array of
|
|
39
|
+
* [key, value] for each element in the map in insertion order.
|
|
40
|
+
*
|
|
41
|
+
* This method invokes the `keys()` and `get()` methods.
|
|
42
|
+
*
|
|
43
|
+
* @returns {AsyncIterableIterator<[any, any]>}
|
|
44
|
+
*/
|
|
45
|
+
async *entries() {
|
|
46
|
+
const keys = [];
|
|
47
|
+
const valuePromises = [];
|
|
48
|
+
// Invoke get() calls without waiting; some may take longer than others
|
|
49
|
+
for await (const key of this.keys()) {
|
|
50
|
+
keys.push(key);
|
|
51
|
+
valuePromises.push(this.get(key));
|
|
52
|
+
}
|
|
53
|
+
// Now wait for all promises to resolve
|
|
54
|
+
const values = await Promise.all(valuePromises);
|
|
55
|
+
for (let i = 0; i < keys.length; i++) {
|
|
56
|
+
yield [keys[i], values[i]];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Calls `callback` once for each key/value pair in the map, in insertion order.
|
|
62
|
+
*
|
|
63
|
+
* This method invokes the `entries()` method.
|
|
64
|
+
*
|
|
65
|
+
* @param {(value: any, key: any, thisArg: any) => Promise<void>} callback
|
|
66
|
+
* @param {any?} thisArg
|
|
67
|
+
*/
|
|
68
|
+
async forEach(callback, thisArg = this) {
|
|
69
|
+
for await (const [key, value] of this.entries()) {
|
|
70
|
+
await callback(value, key, thisArg);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Returns the value associated with the key, or undefined if there is none.
|
|
76
|
+
*
|
|
77
|
+
* @param {any} key
|
|
78
|
+
* @returns {Promise<any>}
|
|
79
|
+
*/
|
|
80
|
+
async get(key) {
|
|
81
|
+
throw new Error("get() not implemented");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Groups items from an async iterable into an AsyncMap according to the keys
|
|
86
|
+
* returned by the given function.
|
|
87
|
+
*
|
|
88
|
+
* @param {Iterable<any>|AsyncIterable<any>} iterable
|
|
89
|
+
* @param {(element: any, index: any) => Promise<any>} keyFn
|
|
90
|
+
* @returns {Promise<Map>}
|
|
91
|
+
*/
|
|
92
|
+
static async groupBy(iterable, keyFn) {
|
|
93
|
+
const map = new Map();
|
|
94
|
+
let index = 0;
|
|
95
|
+
for await (const element of iterable) {
|
|
96
|
+
const key = await keyFn(element, index);
|
|
97
|
+
if (!map.has(key)) {
|
|
98
|
+
map.set(key, []);
|
|
99
|
+
}
|
|
100
|
+
map.get(key).push(element);
|
|
101
|
+
index++;
|
|
102
|
+
}
|
|
103
|
+
return map;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Returns true if the given key appears in the set returned by keys().
|
|
108
|
+
*
|
|
109
|
+
* It doesn't matter whether the value returned by get() is defined or not.
|
|
110
|
+
*
|
|
111
|
+
* If the requested key has a trailing slash but has no associated value, but
|
|
112
|
+
* the alternate form with a slash does appear, this returns true.
|
|
113
|
+
*
|
|
114
|
+
* @param {any} key
|
|
115
|
+
*/
|
|
116
|
+
async has(key) {
|
|
117
|
+
const alternateKey = !trailingSlash.has(key)
|
|
118
|
+
? trailingSlash.add(key)
|
|
119
|
+
: null;
|
|
120
|
+
for await (const k of this.keys()) {
|
|
121
|
+
if (k === key) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
if (alternateKey && k === alternateKey) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Returns a new `AsyncIterator` object that contains the keys for each
|
|
133
|
+
* element in the map in insertion order.
|
|
134
|
+
*
|
|
135
|
+
* @returns {AsyncIterableIterator<any>}
|
|
136
|
+
*/
|
|
137
|
+
async *keys() {
|
|
138
|
+
throw new Error("keys() not implemented");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* The parent of this node in a tree.
|
|
143
|
+
*/
|
|
144
|
+
get parent() {
|
|
145
|
+
return this._parent;
|
|
146
|
+
}
|
|
147
|
+
set parent(parent) {
|
|
148
|
+
this._parent = parent;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* True if the object is read-only. This will be true if `get()` has been
|
|
153
|
+
* overridden but `set()` and `delete()` have not.
|
|
154
|
+
*/
|
|
155
|
+
get readOnly() {
|
|
156
|
+
return (
|
|
157
|
+
this.get !== AsyncMap.prototype.get &&
|
|
158
|
+
(this.set === AsyncMap.prototype.set ||
|
|
159
|
+
this.delete === AsyncMap.prototype.delete)
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Sets the value for the given key.
|
|
165
|
+
*
|
|
166
|
+
* @param {any} key
|
|
167
|
+
* @param {any} value
|
|
168
|
+
* @returns {Promise<AsyncMap>}
|
|
169
|
+
*/
|
|
170
|
+
async set(key, value) {
|
|
171
|
+
throw new Error("set() not implemented");
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Returns the number of keys in the map.
|
|
176
|
+
*
|
|
177
|
+
* The `size` property invokes an overridden `keys()` to ensure proper
|
|
178
|
+
* behavior in subclasses. Because a subclass may not enforce a direct
|
|
179
|
+
* correspondence between `keys()` and `get()`, the size may not reflect the
|
|
180
|
+
* number of values that can be retrieved.
|
|
181
|
+
*
|
|
182
|
+
* @type {Promise<number>}
|
|
183
|
+
*/
|
|
184
|
+
get size() {
|
|
185
|
+
return (async () => {
|
|
186
|
+
let count = 0;
|
|
187
|
+
for await (const _ of this.keys()) {
|
|
188
|
+
count++;
|
|
189
|
+
}
|
|
190
|
+
return count;
|
|
191
|
+
})();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Returns a new `AsyncIterator` object that contains the values for each
|
|
196
|
+
* element in the map in insertion order.
|
|
197
|
+
*
|
|
198
|
+
* @returns {AsyncIterableIterator<any>}
|
|
199
|
+
*/
|
|
200
|
+
async *values() {
|
|
201
|
+
const valuePromises = [];
|
|
202
|
+
// Invoke get() calls without waiting; some may take longer than others
|
|
203
|
+
for await (const key of this.keys()) {
|
|
204
|
+
valuePromises.push(this.get(key));
|
|
205
|
+
}
|
|
206
|
+
// Now wait for all promises to resolve
|
|
207
|
+
const values = await Promise.all(valuePromises);
|
|
208
|
+
yield* values;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
import { hiddenFileNames } from "../constants.js";
|
|
2
2
|
import assign from "../operations/assign.js";
|
|
3
|
-
import
|
|
3
|
+
import isMaplike from "../operations/isMaplike.js";
|
|
4
4
|
import * as trailingSlash from "../trailingSlash.js";
|
|
5
5
|
import isStringlike from "../utilities/isStringlike.js";
|
|
6
6
|
import naturalOrder from "../utilities/naturalOrder.js";
|
|
7
7
|
import setParent from "../utilities/setParent.js";
|
|
8
|
+
import AsyncMap from "./AsyncMap.js";
|
|
8
9
|
|
|
9
10
|
const TypedArray = Object.getPrototypeOf(Uint8Array);
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
|
-
* A
|
|
13
|
+
* A map of files backed by a browser-hosted file system such as the standard
|
|
13
14
|
* Origin Private File System or the (as of October 2023) experimental File
|
|
14
15
|
* System Access API.
|
|
15
|
-
*
|
|
16
|
-
* @typedef {import("@weborigami/types").AsyncMutableTree} AsyncMutableTree
|
|
17
|
-
* @implements {AsyncMutableTree}
|
|
18
16
|
*/
|
|
19
|
-
export default class
|
|
17
|
+
export default class BrowserFileMap extends AsyncMap {
|
|
20
18
|
/**
|
|
21
|
-
* Construct a
|
|
19
|
+
* Construct a map of files backed by a browser-hosted file system.
|
|
22
20
|
*
|
|
23
21
|
* The directory handle can be obtained via any of the [methods that return a
|
|
24
22
|
* FileSystemDirectoryHandle](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryHandle).
|
|
@@ -28,11 +26,28 @@ export default class BrowserFileTree {
|
|
|
28
26
|
* @param {FileSystemDirectoryHandle} [directoryHandle]
|
|
29
27
|
*/
|
|
30
28
|
constructor(directoryHandle) {
|
|
31
|
-
|
|
32
|
-
* @ts-ignore */
|
|
29
|
+
super();
|
|
33
30
|
this.directory = directoryHandle;
|
|
34
31
|
}
|
|
35
32
|
|
|
33
|
+
async delete(key) {
|
|
34
|
+
const baseKey = trailingSlash.remove(key);
|
|
35
|
+
const directory = await this.getDirectory();
|
|
36
|
+
|
|
37
|
+
// Delete file.
|
|
38
|
+
try {
|
|
39
|
+
await directory.removeEntry(baseKey);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
// If the file didn't exist, ignore the error.
|
|
42
|
+
if (error instanceof DOMException && error.name === "NotFoundError") {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
|
|
36
51
|
async get(key) {
|
|
37
52
|
if (key == null) {
|
|
38
53
|
// Reject nullish key.
|
|
@@ -90,7 +105,7 @@ export default class BrowserFileTree {
|
|
|
90
105
|
return this.directory;
|
|
91
106
|
}
|
|
92
107
|
|
|
93
|
-
async keys() {
|
|
108
|
+
async *keys() {
|
|
94
109
|
const directory = await this.getDirectory();
|
|
95
110
|
let keys = [];
|
|
96
111
|
// @ts-ignore
|
|
@@ -110,28 +125,13 @@ export default class BrowserFileTree {
|
|
|
110
125
|
keys = keys.filter((key) => !hiddenFileNames.includes(key));
|
|
111
126
|
keys.sort(naturalOrder);
|
|
112
127
|
|
|
113
|
-
|
|
128
|
+
yield* keys;
|
|
114
129
|
}
|
|
115
130
|
|
|
116
131
|
async set(key, value) {
|
|
117
132
|
const baseKey = trailingSlash.remove(key);
|
|
118
133
|
const directory = await this.getDirectory();
|
|
119
134
|
|
|
120
|
-
if (value === undefined) {
|
|
121
|
-
// Delete file.
|
|
122
|
-
try {
|
|
123
|
-
await directory.removeEntry(baseKey);
|
|
124
|
-
} catch (error) {
|
|
125
|
-
// If the file didn't exist, ignore the error.
|
|
126
|
-
if (
|
|
127
|
-
!(error instanceof DOMException && error.name === "NotFoundError")
|
|
128
|
-
) {
|
|
129
|
-
throw error;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
return this;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
135
|
// Treat null value as empty string; will create an empty file.
|
|
136
136
|
if (value === null) {
|
|
137
137
|
value = "";
|
|
@@ -158,7 +158,12 @@ export default class BrowserFileTree {
|
|
|
158
158
|
const writable = await fileHandle.createWritable();
|
|
159
159
|
await writable.write(value);
|
|
160
160
|
await writable.close();
|
|
161
|
-
} else if (
|
|
161
|
+
} else if (value === /** @type {any} */ (this.constructor).EMPTY) {
|
|
162
|
+
// Create empty subtree.
|
|
163
|
+
await directory.getDirectoryHandle(baseKey, {
|
|
164
|
+
create: true,
|
|
165
|
+
});
|
|
166
|
+
} else if (isMaplike(value)) {
|
|
162
167
|
// Treat value as a tree and write it out as a subdirectory.
|
|
163
168
|
const subdirectory = await directory.getDirectoryHandle(baseKey, {
|
|
164
169
|
create: true,
|
|
@@ -172,4 +177,8 @@ export default class BrowserFileTree {
|
|
|
172
177
|
|
|
173
178
|
return this;
|
|
174
179
|
}
|
|
180
|
+
|
|
181
|
+
get trailingSlashKeys() {
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
175
184
|
}
|