@jsenv/filesystem 4.2.3 → 4.2.4
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/README.md +17 -17
- package/package.json +4 -4
- package/src/assertDirectoryPresence.js +10 -10
- package/src/assertFilePresence.js +10 -10
- package/src/bufferToEtag.js +11 -11
- package/src/collectDirectoryMatchReport.js +38 -38
- package/src/collectFiles.js +35 -35
- package/src/comparePathnames.js +23 -23
- package/src/copyDirectoryContent.js +37 -37
- package/src/copyEntry.js +88 -88
- package/src/directory_url_validation.js +14 -14
- package/src/ensureEmptyDirectory.js +13 -13
- package/src/ensureParentDirectories.js +9 -9
- package/src/ensureWindowsDriveLetter.js +19 -19
- package/src/fileSystemRootUrl.js +1 -1
- package/src/file_url_validation.js +14 -14
- package/src/getRealFileSystemUrlSync.js +24 -24
- package/src/grantPermissionsOnEntry.js +9 -9
- package/src/internal/createWatcher.js +12 -12
- package/src/internal/getCommandArgument.js +7 -7
- package/src/internal/guard_second_call.js +20 -20
- package/src/internal/permissions.js +26 -26
- package/src/internal/read_entry_info.js +8 -8
- package/src/internal/statsToType.js +9 -9
- package/src/internal/track_resources.js +12 -12
- package/src/internal/urlTargetsSameFileSystemPath.js +4 -4
- package/src/listFilesMatching.js +5 -5
- package/src/main.js +35 -35
- package/src/moveDirectoryContent.js +37 -37
- package/src/moveEntry.js +44 -44
- package/src/readDirectory.js +21 -21
- package/src/readEntryModificationTime.js +4 -4
- package/src/readEntryPermissions.js +10 -10
- package/src/readEntryStat.js +27 -27
- package/src/readFile.js +12 -12
- package/src/readFileSync.js +9 -9
- package/src/readSymbolicLink.js +9 -9
- package/src/registerDirectoryLifecycle.js +118 -118
- package/src/registerFileLifecycle.js +66 -66
- package/src/removeEntry.js +81 -81
- package/src/testEntryPermissions.js +15 -15
- package/src/writeDirectory.js +17 -17
- package/src/writeEntryModificationTime.js +10 -10
- package/src/writeEntryPermissions.js +26 -26
- package/src/writeFile.js +16 -16
- package/src/writeFileSync.js +10 -10
- package/src/writeSymbolicLink.js +39 -39
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ Collection of functions to interact with filesystem in Node.js
|
|
|
5
5
|
## List files using pattern matching
|
|
6
6
|
|
|
7
7
|
```js
|
|
8
|
-
import { listFilesMatching } from "@jsenv/filesystem"
|
|
8
|
+
import { listFilesMatching } from "@jsenv/filesystem";
|
|
9
9
|
|
|
10
10
|
const jsFiles = await listFilesMatching({
|
|
11
11
|
directoryUrl: new URL("./", import.meta.url),
|
|
@@ -13,7 +13,7 @@ const jsFiles = await listFilesMatching({
|
|
|
13
13
|
"./**/*.js": true,
|
|
14
14
|
"./**/*.test.js": false,
|
|
15
15
|
},
|
|
16
|
-
})
|
|
16
|
+
});
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
```console
|
|
@@ -26,45 +26,45 @@ const jsFiles = await listFilesMatching({
|
|
|
26
26
|
## Watch a specific file changes
|
|
27
27
|
|
|
28
28
|
```js
|
|
29
|
-
import { readFileSync } from "node:fs"
|
|
30
|
-
import { registerFileLifecycle } from "@jsenv/filesystem"
|
|
29
|
+
import { readFileSync } from "node:fs";
|
|
30
|
+
import { registerFileLifecycle } from "@jsenv/filesystem";
|
|
31
31
|
|
|
32
|
-
const packageJSONFileUrl = new URL("./package.json", import.meta.url)
|
|
33
|
-
let packageJSON = null
|
|
32
|
+
const packageJSONFileUrl = new URL("./package.json", import.meta.url);
|
|
33
|
+
let packageJSON = null;
|
|
34
34
|
const unregister = registerFileLifecycle(packageJSONFileUrl, {
|
|
35
35
|
added: () => {
|
|
36
|
-
packageJSON = JSON.parse(String(readFileSync(packageJSONFileUrl)))
|
|
36
|
+
packageJSON = JSON.parse(String(readFileSync(packageJSONFileUrl)));
|
|
37
37
|
},
|
|
38
38
|
updated: () => {
|
|
39
|
-
packageJSON = JSON.parse(String(readFileSync(packageJSONFileUrl)))
|
|
39
|
+
packageJSON = JSON.parse(String(readFileSync(packageJSONFileUrl)));
|
|
40
40
|
},
|
|
41
41
|
removed: () => {
|
|
42
|
-
packageJSON = null
|
|
42
|
+
packageJSON = null;
|
|
43
43
|
},
|
|
44
44
|
notifyExistent: true,
|
|
45
|
-
})
|
|
46
|
-
unregister() // stop watching the file changes
|
|
45
|
+
});
|
|
46
|
+
unregister(); // stop watching the file changes
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
## Watch many files changes
|
|
50
50
|
|
|
51
51
|
```js
|
|
52
|
-
import { registerDirectoryLifecycle } from "@jsenv/filesystem"
|
|
52
|
+
import { registerDirectoryLifecycle } from "@jsenv/filesystem";
|
|
53
53
|
|
|
54
|
-
const directoryContentDescription = {}
|
|
54
|
+
const directoryContentDescription = {};
|
|
55
55
|
const unregister = registerDirectoryLifecycle("file:///directory/", {
|
|
56
56
|
watchPatterns: {
|
|
57
57
|
"./**/*": true,
|
|
58
58
|
"./node_modules/": false,
|
|
59
59
|
},
|
|
60
60
|
added: ({ relativeUrl, type }) => {
|
|
61
|
-
directoryContentDescription[relativeUrl] = type
|
|
61
|
+
directoryContentDescription[relativeUrl] = type;
|
|
62
62
|
},
|
|
63
63
|
removed: ({ relativeUrl }) => {
|
|
64
|
-
delete directoryContentDescription[relativeUrl]
|
|
64
|
+
delete directoryContentDescription[relativeUrl];
|
|
65
65
|
},
|
|
66
|
-
})
|
|
67
|
-
unregister() // stop watching the directory changes
|
|
66
|
+
});
|
|
67
|
+
unregister(); // stop watching the directory changes
|
|
68
68
|
```
|
|
69
69
|
|
|
70
70
|
# API
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/filesystem",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
|
-
"url": "https://github.com/jsenv/
|
|
8
|
-
"directory": "packages/filesystem"
|
|
7
|
+
"url": "https://github.com/jsenv/core",
|
|
8
|
+
"directory": "packages/independent/filesystem"
|
|
9
9
|
},
|
|
10
10
|
"publishConfig": {
|
|
11
11
|
"access": "public"
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"test": "node --conditions=development ./scripts/test.mjs"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@jsenv/urls": "2.
|
|
32
|
+
"@jsenv/urls": "2.1.0",
|
|
33
33
|
"@jsenv/url-meta": "8.1.0",
|
|
34
34
|
"@jsenv/abort": "4.2.4"
|
|
35
35
|
}
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import { urlToFileSystemPath } from "@jsenv/urls"
|
|
1
|
+
import { urlToFileSystemPath } from "@jsenv/urls";
|
|
2
2
|
|
|
3
|
-
import { assertAndNormalizeFileUrl } from "./file_url_validation.js"
|
|
4
|
-
import { statsToType } from "./internal/statsToType.js"
|
|
5
|
-
import { readEntryStat } from "./readEntryStat.js"
|
|
3
|
+
import { assertAndNormalizeFileUrl } from "./file_url_validation.js";
|
|
4
|
+
import { statsToType } from "./internal/statsToType.js";
|
|
5
|
+
import { readEntryStat } from "./readEntryStat.js";
|
|
6
6
|
|
|
7
7
|
export const assertDirectoryPresence = async (source) => {
|
|
8
|
-
const sourceUrl = assertAndNormalizeFileUrl(source)
|
|
9
|
-
const sourcePath = urlToFileSystemPath(sourceUrl)
|
|
8
|
+
const sourceUrl = assertAndNormalizeFileUrl(source);
|
|
9
|
+
const sourcePath = urlToFileSystemPath(sourceUrl);
|
|
10
10
|
|
|
11
11
|
const sourceStats = await readEntryStat(sourceUrl, {
|
|
12
12
|
nullIfNotFound: true,
|
|
13
|
-
})
|
|
13
|
+
});
|
|
14
14
|
if (!sourceStats) {
|
|
15
|
-
throw new Error(`directory not found at ${sourcePath}`)
|
|
15
|
+
throw new Error(`directory not found at ${sourcePath}`);
|
|
16
16
|
}
|
|
17
17
|
if (!sourceStats.isDirectory()) {
|
|
18
18
|
throw new Error(
|
|
19
19
|
`directory expected at ${sourcePath} and found ${statsToType(
|
|
20
20
|
sourceStats,
|
|
21
21
|
)} instead`,
|
|
22
|
-
)
|
|
22
|
+
);
|
|
23
23
|
}
|
|
24
|
-
}
|
|
24
|
+
};
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import { urlToFileSystemPath } from "@jsenv/urls"
|
|
1
|
+
import { urlToFileSystemPath } from "@jsenv/urls";
|
|
2
2
|
|
|
3
|
-
import { assertAndNormalizeFileUrl } from "./file_url_validation.js"
|
|
4
|
-
import { statsToType } from "./internal/statsToType.js"
|
|
5
|
-
import { readEntryStat } from "./readEntryStat.js"
|
|
3
|
+
import { assertAndNormalizeFileUrl } from "./file_url_validation.js";
|
|
4
|
+
import { statsToType } from "./internal/statsToType.js";
|
|
5
|
+
import { readEntryStat } from "./readEntryStat.js";
|
|
6
6
|
|
|
7
7
|
export const assertFilePresence = async (source) => {
|
|
8
|
-
const sourceUrl = assertAndNormalizeFileUrl(source)
|
|
9
|
-
const sourcePath = urlToFileSystemPath(sourceUrl)
|
|
8
|
+
const sourceUrl = assertAndNormalizeFileUrl(source);
|
|
9
|
+
const sourcePath = urlToFileSystemPath(sourceUrl);
|
|
10
10
|
|
|
11
11
|
const sourceStats = await readEntryStat(sourceUrl, {
|
|
12
12
|
nullIfNotFound: true,
|
|
13
|
-
})
|
|
13
|
+
});
|
|
14
14
|
if (!sourceStats) {
|
|
15
|
-
throw new Error(`file not found at ${sourcePath}`)
|
|
15
|
+
throw new Error(`file not found at ${sourcePath}`);
|
|
16
16
|
}
|
|
17
17
|
if (!sourceStats.isFile()) {
|
|
18
18
|
throw new Error(
|
|
19
19
|
`file expected at ${sourcePath} and found ${statsToType(
|
|
20
20
|
sourceStats,
|
|
21
21
|
)} instead`,
|
|
22
|
-
)
|
|
22
|
+
);
|
|
23
23
|
}
|
|
24
|
-
}
|
|
24
|
+
};
|
package/src/bufferToEtag.js
CHANGED
|
@@ -5,25 +5,25 @@
|
|
|
5
5
|
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { createHash } from "node:crypto"
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
9
|
|
|
10
|
-
const ETAG_FOR_EMPTY_CONTENT = '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"'
|
|
10
|
+
const ETAG_FOR_EMPTY_CONTENT = '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"';
|
|
11
11
|
|
|
12
12
|
export const bufferToEtag = (buffer) => {
|
|
13
13
|
if (!Buffer.isBuffer(buffer)) {
|
|
14
|
-
throw new TypeError(`buffer expected, got ${buffer}`)
|
|
14
|
+
throw new TypeError(`buffer expected, got ${buffer}`);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
if (buffer.length === 0) {
|
|
18
|
-
return ETAG_FOR_EMPTY_CONTENT
|
|
18
|
+
return ETAG_FOR_EMPTY_CONTENT;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
const hash = createHash("sha1")
|
|
22
|
-
hash.update(buffer, "utf8")
|
|
21
|
+
const hash = createHash("sha1");
|
|
22
|
+
hash.update(buffer, "utf8");
|
|
23
23
|
|
|
24
|
-
const hashBase64String = hash.digest("base64")
|
|
25
|
-
const hashBase64StringSubset = hashBase64String.slice(0, 27)
|
|
26
|
-
const length = buffer.length
|
|
24
|
+
const hashBase64String = hash.digest("base64");
|
|
25
|
+
const hashBase64StringSubset = hashBase64String.slice(0, 27);
|
|
26
|
+
const length = buffer.length;
|
|
27
27
|
|
|
28
|
-
return `"${length.toString(16)}-${hashBase64StringSubset}"
|
|
29
|
-
}
|
|
28
|
+
return `"${length.toString(16)}-${hashBase64StringSubset}"`;
|
|
29
|
+
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { Abort } from "@jsenv/abort"
|
|
1
|
+
import { Abort } from "@jsenv/abort";
|
|
2
2
|
|
|
3
|
-
import { URL_META } from "@jsenv/url-meta"
|
|
4
|
-
import { urlToRelativeUrl } from "@jsenv/urls"
|
|
5
|
-
import { assertAndNormalizeDirectoryUrl } from "./directory_url_validation.js"
|
|
6
|
-
import { readDirectory } from "./readDirectory.js"
|
|
7
|
-
import { readEntryStat } from "./readEntryStat.js"
|
|
8
|
-
import { comparePathnames } from "./comparePathnames.js"
|
|
3
|
+
import { URL_META } from "@jsenv/url-meta";
|
|
4
|
+
import { urlToRelativeUrl } from "@jsenv/urls";
|
|
5
|
+
import { assertAndNormalizeDirectoryUrl } from "./directory_url_validation.js";
|
|
6
|
+
import { readDirectory } from "./readDirectory.js";
|
|
7
|
+
import { readEntryStat } from "./readEntryStat.js";
|
|
8
|
+
import { comparePathnames } from "./comparePathnames.js";
|
|
9
9
|
|
|
10
10
|
export const collectDirectoryMatchReport = async ({
|
|
11
11
|
signal = new AbortController().signal,
|
|
@@ -13,31 +13,31 @@ export const collectDirectoryMatchReport = async ({
|
|
|
13
13
|
associations,
|
|
14
14
|
predicate,
|
|
15
15
|
}) => {
|
|
16
|
-
const matchingArray = []
|
|
17
|
-
const ignoredArray = []
|
|
16
|
+
const matchingArray = [];
|
|
17
|
+
const ignoredArray = [];
|
|
18
18
|
|
|
19
|
-
const rootDirectoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl)
|
|
19
|
+
const rootDirectoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl);
|
|
20
20
|
if (typeof predicate !== "function") {
|
|
21
|
-
throw new TypeError(`predicate must be a function, got ${predicate}`)
|
|
21
|
+
throw new TypeError(`predicate must be a function, got ${predicate}`);
|
|
22
22
|
}
|
|
23
|
-
associations = URL_META.resolveAssociations(associations, rootDirectoryUrl)
|
|
23
|
+
associations = URL_META.resolveAssociations(associations, rootDirectoryUrl);
|
|
24
24
|
|
|
25
|
-
const collectOperation = Abort.startOperation()
|
|
26
|
-
collectOperation.addAbortSignal(signal)
|
|
25
|
+
const collectOperation = Abort.startOperation();
|
|
26
|
+
collectOperation.addAbortSignal(signal);
|
|
27
27
|
|
|
28
28
|
const visitDirectory = async (directoryUrl) => {
|
|
29
|
-
collectOperation.throwIfAborted()
|
|
30
|
-
const directoryItems = await readDirectory(directoryUrl)
|
|
29
|
+
collectOperation.throwIfAborted();
|
|
30
|
+
const directoryItems = await readDirectory(directoryUrl);
|
|
31
31
|
|
|
32
32
|
await Promise.all(
|
|
33
33
|
directoryItems.map(async (directoryItem) => {
|
|
34
|
-
const directoryChildNodeUrl = `${directoryUrl}${directoryItem}
|
|
34
|
+
const directoryChildNodeUrl = `${directoryUrl}${directoryItem}`;
|
|
35
35
|
const relativeUrl = urlToRelativeUrl(
|
|
36
36
|
directoryChildNodeUrl,
|
|
37
37
|
rootDirectoryUrl,
|
|
38
|
-
)
|
|
38
|
+
);
|
|
39
39
|
|
|
40
|
-
collectOperation.throwIfAborted()
|
|
40
|
+
collectOperation.throwIfAborted();
|
|
41
41
|
const directoryChildNodeStats = await readEntryStat(
|
|
42
42
|
directoryChildNodeUrl,
|
|
43
43
|
{
|
|
@@ -49,10 +49,10 @@ export const collectDirectoryMatchReport = async ({
|
|
|
49
49
|
// because directoryPath is recursively traversed
|
|
50
50
|
followLink: false,
|
|
51
51
|
},
|
|
52
|
-
)
|
|
52
|
+
);
|
|
53
53
|
|
|
54
54
|
if (directoryChildNodeStats.isDirectory()) {
|
|
55
|
-
const subDirectoryUrl = `${directoryChildNodeUrl}
|
|
55
|
+
const subDirectoryUrl = `${directoryChildNodeUrl}/`;
|
|
56
56
|
|
|
57
57
|
if (
|
|
58
58
|
!URL_META.urlChildMayMatch({
|
|
@@ -66,53 +66,53 @@ export const collectDirectoryMatchReport = async ({
|
|
|
66
66
|
? relativeUrl
|
|
67
67
|
: `${relativeUrl}/`,
|
|
68
68
|
fileStats: directoryChildNodeStats,
|
|
69
|
-
})
|
|
69
|
+
});
|
|
70
70
|
|
|
71
|
-
return
|
|
71
|
+
return;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
await visitDirectory(subDirectoryUrl)
|
|
75
|
-
return
|
|
74
|
+
await visitDirectory(subDirectoryUrl);
|
|
75
|
+
return;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
if (directoryChildNodeStats.isFile()) {
|
|
79
79
|
const meta = URL_META.applyAssociations({
|
|
80
80
|
url: directoryChildNodeUrl,
|
|
81
81
|
associations,
|
|
82
|
-
})
|
|
82
|
+
});
|
|
83
83
|
if (!predicate(meta)) {
|
|
84
84
|
ignoredArray.push({
|
|
85
85
|
relativeUrl,
|
|
86
86
|
meta,
|
|
87
87
|
fileStats: directoryChildNodeStats,
|
|
88
|
-
})
|
|
89
|
-
return
|
|
88
|
+
});
|
|
89
|
+
return;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
matchingArray.push({
|
|
93
93
|
relativeUrl,
|
|
94
94
|
meta,
|
|
95
95
|
fileStats: directoryChildNodeStats,
|
|
96
|
-
})
|
|
97
|
-
return
|
|
96
|
+
});
|
|
97
|
+
return;
|
|
98
98
|
}
|
|
99
99
|
}),
|
|
100
|
-
)
|
|
101
|
-
}
|
|
100
|
+
);
|
|
101
|
+
};
|
|
102
102
|
|
|
103
103
|
try {
|
|
104
|
-
await visitDirectory(rootDirectoryUrl)
|
|
104
|
+
await visitDirectory(rootDirectoryUrl);
|
|
105
105
|
|
|
106
106
|
return {
|
|
107
107
|
matchingArray: sortByRelativeUrl(matchingArray),
|
|
108
108
|
ignoredArray: sortByRelativeUrl(ignoredArray),
|
|
109
|
-
}
|
|
109
|
+
};
|
|
110
110
|
} finally {
|
|
111
|
-
await collectOperation.end()
|
|
111
|
+
await collectOperation.end();
|
|
112
112
|
}
|
|
113
|
-
}
|
|
113
|
+
};
|
|
114
114
|
|
|
115
115
|
const sortByRelativeUrl = (array) =>
|
|
116
116
|
array.sort((left, right) => {
|
|
117
|
-
return comparePathnames(left.relativeUrl, right.relativeUrl)
|
|
118
|
-
})
|
|
117
|
+
return comparePathnames(left.relativeUrl, right.relativeUrl);
|
|
118
|
+
});
|
package/src/collectFiles.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { Abort } from "@jsenv/abort"
|
|
2
|
-
import { URL_META } from "@jsenv/url-meta"
|
|
3
|
-
import { urlToRelativeUrl } from "@jsenv/urls"
|
|
1
|
+
import { Abort } from "@jsenv/abort";
|
|
2
|
+
import { URL_META } from "@jsenv/url-meta";
|
|
3
|
+
import { urlToRelativeUrl } from "@jsenv/urls";
|
|
4
4
|
|
|
5
|
-
import { assertAndNormalizeDirectoryUrl } from "./directory_url_validation.js"
|
|
6
|
-
import { readDirectory } from "./readDirectory.js"
|
|
7
|
-
import { readEntryStat } from "./readEntryStat.js"
|
|
8
|
-
import { comparePathnames } from "./comparePathnames.js"
|
|
5
|
+
import { assertAndNormalizeDirectoryUrl } from "./directory_url_validation.js";
|
|
6
|
+
import { readDirectory } from "./readDirectory.js";
|
|
7
|
+
import { readEntryStat } from "./readEntryStat.js";
|
|
8
|
+
import { comparePathnames } from "./comparePathnames.js";
|
|
9
9
|
|
|
10
10
|
export const collectFiles = async ({
|
|
11
11
|
signal = new AbortController().signal,
|
|
@@ -13,24 +13,24 @@ export const collectFiles = async ({
|
|
|
13
13
|
associations,
|
|
14
14
|
predicate,
|
|
15
15
|
}) => {
|
|
16
|
-
const rootDirectoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl)
|
|
16
|
+
const rootDirectoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl);
|
|
17
17
|
if (typeof predicate !== "function") {
|
|
18
|
-
throw new TypeError(`predicate must be a function, got ${predicate}`)
|
|
18
|
+
throw new TypeError(`predicate must be a function, got ${predicate}`);
|
|
19
19
|
}
|
|
20
|
-
associations = URL_META.resolveAssociations(associations, rootDirectoryUrl)
|
|
20
|
+
associations = URL_META.resolveAssociations(associations, rootDirectoryUrl);
|
|
21
21
|
|
|
22
|
-
const collectOperation = Abort.startOperation()
|
|
23
|
-
collectOperation.addAbortSignal(signal)
|
|
22
|
+
const collectOperation = Abort.startOperation();
|
|
23
|
+
collectOperation.addAbortSignal(signal);
|
|
24
24
|
|
|
25
|
-
const matchingFileResultArray = []
|
|
25
|
+
const matchingFileResultArray = [];
|
|
26
26
|
const visitDirectory = async (directoryUrl) => {
|
|
27
|
-
collectOperation.throwIfAborted()
|
|
28
|
-
const directoryItems = await readDirectory(directoryUrl)
|
|
27
|
+
collectOperation.throwIfAborted();
|
|
28
|
+
const directoryItems = await readDirectory(directoryUrl);
|
|
29
29
|
|
|
30
30
|
await Promise.all(
|
|
31
31
|
directoryItems.map(async (directoryItem) => {
|
|
32
|
-
const directoryChildNodeUrl = `${directoryUrl}${directoryItem}
|
|
33
|
-
collectOperation.throwIfAborted()
|
|
32
|
+
const directoryChildNodeUrl = `${directoryUrl}${directoryItem}`;
|
|
33
|
+
collectOperation.throwIfAborted();
|
|
34
34
|
const directoryChildNodeStats = await readEntryStat(
|
|
35
35
|
directoryChildNodeUrl,
|
|
36
36
|
{
|
|
@@ -42,10 +42,10 @@ export const collectFiles = async ({
|
|
|
42
42
|
// because directoryPath is recursively traversed
|
|
43
43
|
followLink: false,
|
|
44
44
|
},
|
|
45
|
-
)
|
|
45
|
+
);
|
|
46
46
|
|
|
47
47
|
if (directoryChildNodeStats.isDirectory()) {
|
|
48
|
-
const subDirectoryUrl = `${directoryChildNodeUrl}
|
|
48
|
+
const subDirectoryUrl = `${directoryChildNodeUrl}/`;
|
|
49
49
|
if (
|
|
50
50
|
!URL_META.urlChildMayMatch({
|
|
51
51
|
url: subDirectoryUrl,
|
|
@@ -53,47 +53,47 @@ export const collectFiles = async ({
|
|
|
53
53
|
predicate,
|
|
54
54
|
})
|
|
55
55
|
) {
|
|
56
|
-
return
|
|
56
|
+
return;
|
|
57
57
|
}
|
|
58
|
-
await visitDirectory(subDirectoryUrl)
|
|
59
|
-
return
|
|
58
|
+
await visitDirectory(subDirectoryUrl);
|
|
59
|
+
return;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
if (directoryChildNodeStats.isFile()) {
|
|
63
63
|
const meta = URL_META.applyAssociations({
|
|
64
64
|
url: directoryChildNodeUrl,
|
|
65
65
|
associations,
|
|
66
|
-
})
|
|
67
|
-
if (!predicate(meta)) return
|
|
66
|
+
});
|
|
67
|
+
if (!predicate(meta)) return;
|
|
68
68
|
|
|
69
69
|
const relativeUrl = urlToRelativeUrl(
|
|
70
70
|
directoryChildNodeUrl,
|
|
71
71
|
rootDirectoryUrl,
|
|
72
|
-
)
|
|
72
|
+
);
|
|
73
73
|
matchingFileResultArray.push({
|
|
74
74
|
url: new URL(relativeUrl, rootDirectoryUrl).href,
|
|
75
75
|
relativeUrl: decodeURIComponent(relativeUrl),
|
|
76
76
|
meta,
|
|
77
77
|
fileStats: directoryChildNodeStats,
|
|
78
|
-
})
|
|
79
|
-
return
|
|
78
|
+
});
|
|
79
|
+
return;
|
|
80
80
|
}
|
|
81
81
|
}),
|
|
82
|
-
)
|
|
83
|
-
}
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
84
|
|
|
85
85
|
try {
|
|
86
|
-
await visitDirectory(rootDirectoryUrl)
|
|
86
|
+
await visitDirectory(rootDirectoryUrl);
|
|
87
87
|
|
|
88
88
|
// When we operate on thoose files later it feels more natural
|
|
89
89
|
// to perform operation in the same order they appear in the filesystem.
|
|
90
90
|
// It also allow to get a predictable return value.
|
|
91
91
|
// For that reason we sort matchingFileResultArray
|
|
92
92
|
matchingFileResultArray.sort((leftFile, rightFile) => {
|
|
93
|
-
return comparePathnames(leftFile.relativeUrl, rightFile.relativeUrl)
|
|
94
|
-
})
|
|
95
|
-
return matchingFileResultArray
|
|
93
|
+
return comparePathnames(leftFile.relativeUrl, rightFile.relativeUrl);
|
|
94
|
+
});
|
|
95
|
+
return matchingFileResultArray;
|
|
96
96
|
} finally {
|
|
97
|
-
await collectOperation.end()
|
|
97
|
+
await collectOperation.end();
|
|
98
98
|
}
|
|
99
|
-
}
|
|
99
|
+
};
|
package/src/comparePathnames.js
CHANGED
|
@@ -1,49 +1,49 @@
|
|
|
1
1
|
export const comparePathnames = (leftPathame, rightPathname) => {
|
|
2
|
-
const leftPartArray = leftPathame.split("/")
|
|
3
|
-
const rightPartArray = rightPathname.split("/")
|
|
2
|
+
const leftPartArray = leftPathame.split("/");
|
|
3
|
+
const rightPartArray = rightPathname.split("/");
|
|
4
4
|
|
|
5
|
-
const leftLength = leftPartArray.length
|
|
6
|
-
const rightLength = rightPartArray.length
|
|
5
|
+
const leftLength = leftPartArray.length;
|
|
6
|
+
const rightLength = rightPartArray.length;
|
|
7
7
|
|
|
8
|
-
const maxLength = Math.max(leftLength, rightLength)
|
|
9
|
-
let i = 0
|
|
8
|
+
const maxLength = Math.max(leftLength, rightLength);
|
|
9
|
+
let i = 0;
|
|
10
10
|
while (i < maxLength) {
|
|
11
|
-
const leftPartExists = i in leftPartArray
|
|
12
|
-
const rightPartExists = i in rightPartArray
|
|
11
|
+
const leftPartExists = i in leftPartArray;
|
|
12
|
+
const rightPartExists = i in rightPartArray;
|
|
13
13
|
|
|
14
14
|
// longer comes first
|
|
15
15
|
if (!leftPartExists) {
|
|
16
|
-
return +1
|
|
16
|
+
return +1;
|
|
17
17
|
}
|
|
18
18
|
if (!rightPartExists) {
|
|
19
|
-
return -1
|
|
19
|
+
return -1;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
const leftPartIsLast = i === leftPartArray.length - 1
|
|
23
|
-
const rightPartIsLast = i === rightPartArray.length - 1
|
|
22
|
+
const leftPartIsLast = i === leftPartArray.length - 1;
|
|
23
|
+
const rightPartIsLast = i === rightPartArray.length - 1;
|
|
24
24
|
// folder comes first
|
|
25
25
|
if (leftPartIsLast && !rightPartIsLast) {
|
|
26
|
-
return +1
|
|
26
|
+
return +1;
|
|
27
27
|
}
|
|
28
28
|
if (!leftPartIsLast && rightPartIsLast) {
|
|
29
|
-
return -1
|
|
29
|
+
return -1;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
const leftPart = leftPartArray[i]
|
|
33
|
-
const rightPart = rightPartArray[i]
|
|
34
|
-
i
|
|
32
|
+
const leftPart = leftPartArray[i];
|
|
33
|
+
const rightPart = rightPartArray[i];
|
|
34
|
+
i++;
|
|
35
35
|
// local comparison comes first
|
|
36
|
-
const comparison = leftPart.localeCompare(rightPart)
|
|
36
|
+
const comparison = leftPart.localeCompare(rightPart);
|
|
37
37
|
if (comparison !== 0) {
|
|
38
|
-
return comparison
|
|
38
|
+
return comparison;
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
if (leftLength < rightLength) {
|
|
43
|
-
return +1
|
|
43
|
+
return +1;
|
|
44
44
|
}
|
|
45
45
|
if (leftLength > rightLength) {
|
|
46
|
-
return -1
|
|
46
|
+
return -1;
|
|
47
47
|
}
|
|
48
|
-
return 0
|
|
49
|
-
}
|
|
48
|
+
return 0;
|
|
49
|
+
};
|