@weborigami/async-tree 0.2.7 → 0.2.9
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,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/async-tree",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
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": "22.
|
|
11
|
-
"typescript": "5.
|
|
10
|
+
"@types/node": "22.13.5",
|
|
11
|
+
"typescript": "5.8.2"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@weborigami/types": "0.2.
|
|
14
|
+
"@weborigami/types": "0.2.9"
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
17
|
"test": "node --test --test-reporter=spec",
|
package/src/extension.js
CHANGED
|
@@ -65,7 +65,7 @@ export function extname(path) {
|
|
|
65
65
|
* See if the key ends with the given extension. If it does, return the base
|
|
66
66
|
* name without the extension; if it doesn't return null.
|
|
67
67
|
*
|
|
68
|
-
* If the extension is
|
|
68
|
+
* If the extension is the empty string, this will match any key.
|
|
69
69
|
*
|
|
70
70
|
* If the extension is a slash, then the key must end with a slash for the match
|
|
71
71
|
* to succeed. Otherwise, a trailing slash in the key is ignored for purposes of
|
|
@@ -6,16 +6,16 @@ const treeToCaches = new Map();
|
|
|
6
6
|
* Given a key function, return a new key function and inverse key function that
|
|
7
7
|
* cache the results of the original.
|
|
8
8
|
*
|
|
9
|
-
* If `
|
|
10
|
-
*
|
|
9
|
+
* If `deep` is true, the inverse key function will skip any source keys that
|
|
10
|
+
* are keys for subtrees, returning the source key unmodified.
|
|
11
11
|
*
|
|
12
12
|
* @typedef {import("../../index.ts").KeyFn} KeyFn
|
|
13
13
|
*
|
|
14
14
|
* @param {KeyFn} keyFn
|
|
15
|
-
* @param {boolean?}
|
|
15
|
+
* @param {boolean?} deep
|
|
16
16
|
* @returns {{ key: KeyFn, inverseKey: KeyFn }}
|
|
17
17
|
*/
|
|
18
|
-
export default function cachedKeyFunctions(keyFn,
|
|
18
|
+
export default function cachedKeyFunctions(keyFn, deep = false) {
|
|
19
19
|
return {
|
|
20
20
|
async inverseKey(resultKey, tree) {
|
|
21
21
|
const { resultKeyToSourceKey, sourceKeyToResultKey } =
|
|
@@ -40,7 +40,7 @@ export default function cachedKeyFunctions(keyFn, skipSubtrees = false) {
|
|
|
40
40
|
const computedResultKey = await computeAndCacheResultKey(
|
|
41
41
|
tree,
|
|
42
42
|
keyFn,
|
|
43
|
-
|
|
43
|
+
deep,
|
|
44
44
|
sourceKey
|
|
45
45
|
);
|
|
46
46
|
|
|
@@ -48,8 +48,8 @@ export default function cachedKeyFunctions(keyFn, skipSubtrees = false) {
|
|
|
48
48
|
computedResultKey &&
|
|
49
49
|
trailingSlash.remove(computedResultKey) === resultKeyWithoutSlash
|
|
50
50
|
) {
|
|
51
|
-
// Match found
|
|
52
|
-
return
|
|
51
|
+
// Match found
|
|
52
|
+
return matchSlashHandling(computedResultKey, sourceKey, resultKey);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -67,7 +67,7 @@ export default function cachedKeyFunctions(keyFn, skipSubtrees = false) {
|
|
|
67
67
|
const resultKey = await computeAndCacheResultKey(
|
|
68
68
|
tree,
|
|
69
69
|
keyFn,
|
|
70
|
-
|
|
70
|
+
deep,
|
|
71
71
|
sourceKey
|
|
72
72
|
);
|
|
73
73
|
return resultKey;
|
|
@@ -75,12 +75,12 @@ export default function cachedKeyFunctions(keyFn, skipSubtrees = false) {
|
|
|
75
75
|
};
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
async function computeAndCacheResultKey(tree, keyFn,
|
|
78
|
+
async function computeAndCacheResultKey(tree, keyFn, deep, sourceKey) {
|
|
79
79
|
const { resultKeyToSourceKey, sourceKeyToResultKey } =
|
|
80
80
|
getKeyMapsForTree(tree);
|
|
81
81
|
|
|
82
82
|
const resultKey =
|
|
83
|
-
|
|
83
|
+
deep && trailingSlash.has(sourceKey)
|
|
84
84
|
? sourceKey
|
|
85
85
|
: await keyFn(sourceKey, tree);
|
|
86
86
|
|
|
@@ -104,19 +104,33 @@ function getKeyMapsForTree(tree) {
|
|
|
104
104
|
return keyMaps;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
//
|
|
108
|
-
//
|
|
109
|
-
|
|
107
|
+
// Given the input key passed to a function and the result of that function, and
|
|
108
|
+
// a requested key being searched for, determine whether we should add a slash
|
|
109
|
+
// to the output key.
|
|
110
|
+
function matchSlashHandling(inputKey, outputKey, requestedKey) {
|
|
111
|
+
if (trailingSlash.has(inputKey) !== trailingSlash.has(outputKey)) {
|
|
112
|
+
// The key function toggled the slash on the input key; return output as is
|
|
113
|
+
return outputKey;
|
|
114
|
+
} else {
|
|
115
|
+
// Match the slash handling of the requested key
|
|
116
|
+
return trailingSlash.toggle(outputKey, trailingSlash.has(requestedKey));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Search the given key map for the key. Ignore trailing slashes in the search.
|
|
121
|
+
function searchKeyMap(keyMap, requestedKey) {
|
|
110
122
|
// Check key as is
|
|
111
|
-
let
|
|
112
|
-
|
|
113
|
-
|
|
123
|
+
let resultKey;
|
|
124
|
+
let sourceKey = requestedKey;
|
|
125
|
+
if (keyMap.has(sourceKey)) {
|
|
126
|
+
resultKey = keyMap.get(requestedKey);
|
|
114
127
|
} else {
|
|
115
128
|
// Check alternative with/without slash
|
|
116
|
-
|
|
117
|
-
|
|
129
|
+
sourceKey = trailingSlash.toggle(requestedKey);
|
|
130
|
+
resultKey = keyMap.get(sourceKey);
|
|
131
|
+
}
|
|
132
|
+
if (resultKey === undefined) {
|
|
133
|
+
return undefined;
|
|
118
134
|
}
|
|
119
|
-
return
|
|
120
|
-
? trailingSlash.toggle(match, trailingSlash.has(key))
|
|
121
|
-
: undefined;
|
|
135
|
+
return matchSlashHandling(sourceKey, resultKey, requestedKey);
|
|
122
136
|
}
|
|
@@ -2,15 +2,14 @@ import * as extension from "../extension.js";
|
|
|
2
2
|
import * as trailingSlash from "../trailingSlash.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Given a source
|
|
5
|
+
* Given a source extension and a result extension, return a pair of key
|
|
6
6
|
* functions that map between them.
|
|
7
7
|
*
|
|
8
8
|
* The resulting `inverseKey` and `key` functions are compatible with those
|
|
9
9
|
* expected by map and other transforms.
|
|
10
10
|
*
|
|
11
11
|
* @typedef {import("@weborigami/types").AsyncTree} AsyncTree
|
|
12
|
-
* @param {{ resultExtension?: string, sourceExtension: string }}
|
|
13
|
-
* options
|
|
12
|
+
* @param {{ resultExtension?: string, sourceExtension: string }} options
|
|
14
13
|
*/
|
|
15
14
|
export default function keyFunctionsForExtensions({
|
|
16
15
|
resultExtension,
|
|
@@ -42,7 +41,7 @@ export default function keyFunctionsForExtensions({
|
|
|
42
41
|
function checkDeprecatedExtensionWithoutDot(extension) {
|
|
43
42
|
if (extension && extension !== "/" && !extension.startsWith(".")) {
|
|
44
43
|
throw new RangeError(
|
|
45
|
-
`
|
|
44
|
+
`The extension "${extension}" must start with a period.`
|
|
46
45
|
);
|
|
47
46
|
}
|
|
48
47
|
}
|
package/src/utilities.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export function getRealmObjectPrototype(object: any): any;
|
|
|
7
7
|
export const hiddenFileNames: string[];
|
|
8
8
|
export function isPacked(obj: any): obj is Packed;
|
|
9
9
|
export function isPlainObject(obj: any): obj is PlainObject;
|
|
10
|
+
export function isPrimitive(obj: any): boolean;
|
|
10
11
|
export function isStringLike(obj: any): obj is StringLike;
|
|
11
12
|
export function isUnpackable(obj): obj is { unpack: () => any };
|
|
12
13
|
export function keysFromPath(path: string): string[];
|
package/test/extension.test.js
CHANGED
|
@@ -19,6 +19,7 @@ describe("extension", () => {
|
|
|
19
19
|
assert.equal(match("file.md", ".txt"), null);
|
|
20
20
|
assert.equal(match("file.md/", ".md"), "file/");
|
|
21
21
|
assert.equal(match("file", ""), "file");
|
|
22
|
+
assert.equal(match("file.md", ""), "file.md");
|
|
22
23
|
assert.equal(match("file", "/"), null);
|
|
23
24
|
assert.equal(match("file/", "/"), "file");
|
|
24
25
|
});
|
|
@@ -2,6 +2,7 @@ import assert from "node:assert";
|
|
|
2
2
|
import { describe, test } from "node:test";
|
|
3
3
|
import { DeepObjectTree, ObjectTree } from "../../src/internal.js";
|
|
4
4
|
import cachedKeyFunctions from "../../src/operations/cachedKeyFunctions.js";
|
|
5
|
+
import * as trailingSlash from "../../src/trailingSlash.js";
|
|
5
6
|
|
|
6
7
|
describe("cachedKeyFunctions", () => {
|
|
7
8
|
test("maps keys with caching", async () => {
|
|
@@ -74,7 +75,7 @@ describe("cachedKeyFunctions", () => {
|
|
|
74
75
|
assert.equal(callCount, 1);
|
|
75
76
|
});
|
|
76
77
|
|
|
77
|
-
test("preserves trailing slashes", async () => {
|
|
78
|
+
test("preserves trailing slashes if key function does so", async () => {
|
|
78
79
|
const tree = new ObjectTree({
|
|
79
80
|
a: "letter a",
|
|
80
81
|
});
|
|
@@ -87,4 +88,19 @@ describe("cachedKeyFunctions", () => {
|
|
|
87
88
|
assert.equal(await inverseKey("_a/", tree), "a/");
|
|
88
89
|
assert.equal(await inverseKey("_a", tree), "a");
|
|
89
90
|
});
|
|
91
|
+
|
|
92
|
+
test("if key function toggles slash, defers to key function slash handling", async () => {
|
|
93
|
+
const tree = new ObjectTree({
|
|
94
|
+
a: "letter a",
|
|
95
|
+
});
|
|
96
|
+
const addUnderscoreAndSlash = async (sourceKey) =>
|
|
97
|
+
`_${trailingSlash.remove(sourceKey)}/`;
|
|
98
|
+
const { inverseKey, key } = cachedKeyFunctions(addUnderscoreAndSlash);
|
|
99
|
+
|
|
100
|
+
assert.equal(await inverseKey("_a/", tree), "a");
|
|
101
|
+
assert.equal(await inverseKey("_a", tree), "a");
|
|
102
|
+
|
|
103
|
+
assert.equal(await key("a", tree), "_a/");
|
|
104
|
+
assert.equal(await key("a/", tree), "_a/");
|
|
105
|
+
});
|
|
90
106
|
});
|