@jsenv/filesystem 2.3.1 → 2.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.
@@ -1,4 +1,5 @@
1
1
  import { unlink, rmdir, openSync, closeSync } from "node:fs"
2
+ import { Abort } from "@jsenv/abort"
2
3
 
3
4
  import { ensureUrlTrailingSlash } from "./internal/ensureUrlTrailingSlash.js"
4
5
  import { assertAndNormalizeFileUrl } from "./assertAndNormalizeFileUrl.js"
@@ -10,6 +11,7 @@ import { resolveUrl } from "./resolveUrl.js"
10
11
  export const removeFileSystemNode = async (
11
12
  source,
12
13
  {
14
+ signal = new AbortController().signal,
13
15
  allowUseless = false,
14
16
  recursive = false,
15
17
  maxRetries = 3,
@@ -19,40 +21,49 @@ export const removeFileSystemNode = async (
19
21
  ) => {
20
22
  const sourceUrl = assertAndNormalizeFileUrl(source)
21
23
 
22
- const sourceStats = await readFileSystemNodeStat(sourceUrl, {
23
- nullIfNotFound: true,
24
- followLink: false,
25
- })
26
- if (!sourceStats) {
27
- if (allowUseless) {
28
- return
24
+ const removeOperation = Abort.startOperation()
25
+ removeOperation.addAbortSignal(signal)
26
+
27
+ try {
28
+ removeOperation.throwIfAborted()
29
+ const sourceStats = await readFileSystemNodeStat(sourceUrl, {
30
+ nullIfNotFound: true,
31
+ followLink: false,
32
+ })
33
+ if (!sourceStats) {
34
+ if (allowUseless) {
35
+ return
36
+ }
37
+ throw new Error(`nothing to remove at ${urlToFileSystemPath(sourceUrl)}`)
29
38
  }
30
- throw new Error(`nothing to remove at ${urlToFileSystemPath(sourceUrl)}`)
31
- }
32
39
 
33
- // https://nodejs.org/dist/latest-v13.x/docs/api/fs.html#fs_class_fs_stats
34
- // FIFO and socket are ignored, not sure what they are exactly and what to do with them
35
- // other libraries ignore them, let's do the same.
36
- if (
37
- sourceStats.isFile() ||
38
- sourceStats.isSymbolicLink() ||
39
- sourceStats.isCharacterDevice() ||
40
- sourceStats.isBlockDevice()
41
- ) {
42
- await removeNonDirectory(
43
- sourceUrl.endsWith("/") ? sourceUrl.slice(0, -1) : sourceUrl,
44
- {
40
+ // https://nodejs.org/dist/latest-v13.x/docs/api/fs.html#fs_class_fs_stats
41
+ // FIFO and socket are ignored, not sure what they are exactly and what to do with them
42
+ // other libraries ignore them, let's do the same.
43
+ if (
44
+ sourceStats.isFile() ||
45
+ sourceStats.isSymbolicLink() ||
46
+ sourceStats.isCharacterDevice() ||
47
+ sourceStats.isBlockDevice()
48
+ ) {
49
+ await removeNonDirectory(
50
+ sourceUrl.endsWith("/") ? sourceUrl.slice(0, -1) : sourceUrl,
51
+ {
52
+ maxRetries,
53
+ retryDelay,
54
+ },
55
+ )
56
+ } else if (sourceStats.isDirectory()) {
57
+ await removeDirectory(ensureUrlTrailingSlash(sourceUrl), {
58
+ signal: removeOperation.signal,
59
+ recursive,
45
60
  maxRetries,
46
61
  retryDelay,
47
- },
48
- )
49
- } else if (sourceStats.isDirectory()) {
50
- await removeDirectory(ensureUrlTrailingSlash(sourceUrl), {
51
- recursive,
52
- maxRetries,
53
- retryDelay,
54
- onlyContent,
55
- })
62
+ onlyContent,
63
+ })
64
+ }
65
+ } finally {
66
+ await removeOperation.end()
56
67
  }
57
68
  }
58
69
 
@@ -105,9 +116,13 @@ const unlinkNaive = (sourcePath, { handleTemporaryError = null } = {}) => {
105
116
 
106
117
  const removeDirectory = async (
107
118
  rootDirectoryUrl,
108
- { maxRetries, retryDelay, recursive, onlyContent },
119
+ { signal, maxRetries, retryDelay, recursive, onlyContent },
109
120
  ) => {
121
+ const removeDirectoryOperation = Abort.startOperation()
122
+ removeDirectoryOperation.addAbortSignal(signal)
123
+
110
124
  const visit = async (sourceUrl) => {
125
+ removeDirectoryOperation.throwIfAborted()
111
126
  const sourceStats = await readFileSystemNodeStat(sourceUrl, {
112
127
  nullIfNotFound: true,
113
128
  followLink: false,
@@ -141,6 +156,7 @@ const removeDirectory = async (
141
156
  },
142
157
  }
143
158
  : {}
159
+ removeDirectoryOperation.throwIfAborted()
144
160
  await removeDirectoryNaive(directoryPath, {
145
161
  ...optionsFromRecursive,
146
162
  // Workaround for https://github.com/joyent/node/issues/4337
@@ -179,6 +195,7 @@ const removeDirectory = async (
179
195
  }
180
196
 
181
197
  const removeDirectoryContent = async (directoryUrl) => {
198
+ removeDirectoryOperation.throwIfAborted()
182
199
  const names = await readDirectory(directoryUrl)
183
200
  await Promise.all(
184
201
  names.map(async (name) => {
@@ -196,10 +213,14 @@ const removeDirectory = async (
196
213
  await removeNonDirectory(symbolicLinkUrl, { maxRetries, retryDelay })
197
214
  }
198
215
 
199
- if (onlyContent) {
200
- await removeDirectoryContent(rootDirectoryUrl)
201
- } else {
202
- await visitDirectory(rootDirectoryUrl)
216
+ try {
217
+ if (onlyContent) {
218
+ await removeDirectoryContent(rootDirectoryUrl)
219
+ } else {
220
+ await visitDirectory(rootDirectoryUrl)
221
+ }
222
+ } finally {
223
+ await removeDirectoryOperation.end()
203
224
  }
204
225
  }
205
226