@jsenv/filesystem 2.7.2 → 3.2.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.
Files changed (37) hide show
  1. package/README.md +1 -1
  2. package/main.js +14 -12
  3. package/package.json +3 -4
  4. package/src/assertDirectoryPresence.js +2 -2
  5. package/src/assertFilePresence.js +2 -2
  6. package/src/collectDirectoryMatchReport.js +2 -2
  7. package/src/collectFiles.js +2 -2
  8. package/src/copyDirectoryContent.js +6 -6
  9. package/src/{copyFileSystemNode.js → copyEntry.js} +15 -18
  10. package/src/ensureEmptyDirectory.js +4 -4
  11. package/src/ensureParentDirectories.js +2 -1
  12. package/src/fileSystemRootUrl.js +2 -0
  13. package/src/grantPermissionsOnEntry.js +20 -0
  14. package/src/internal/createWatcher.js +1 -1
  15. package/src/internal/guard_second_call.js +20 -0
  16. package/src/internal/read_entry_info.js +20 -0
  17. package/src/moveDirectoryContent.js +6 -6
  18. package/src/{moveFileSystemNode.js → moveEntry.js} +10 -10
  19. package/src/moveUrl.js +10 -0
  20. package/src/readEntryModificationTime.js +6 -0
  21. package/src/{readFileSystemNodePermissions.js → readEntryPermissions.js} +1 -1
  22. package/src/{readFileSystemNodeStat.js → readEntryStat.js} +3 -3
  23. package/src/readFile.js +8 -7
  24. package/src/readFileSync.js +20 -0
  25. package/src/registerDirectoryLifecycle.js +201 -151
  26. package/src/registerFileLifecycle.js +39 -6
  27. package/src/{removeFileSystemNode.js → removeEntry.js} +4 -4
  28. package/src/{testFileSystemNodePermissions.js → testEntryPermissions.js} +3 -2
  29. package/src/writeDirectory.js +4 -3
  30. package/src/{writeFileSystemNodeModificationTime.js → writeEntryModificationTime.js} +3 -2
  31. package/src/{writeFileSystemNodePermissions.js → writeEntryPermissions.js} +3 -2
  32. package/src/writeFile.js +5 -6
  33. package/src/writeFileSync.js +20 -0
  34. package/src/writeSymbolicLink.js +4 -4
  35. package/src/grantPermissionsOnFileSystemNode.js +0 -20
  36. package/src/internal/fileSystemNodeToTypeOrNull.js +0 -18
  37. package/src/readFileSystemNodeModificationTime.js +0 -6
@@ -1,17 +1,16 @@
1
- /* eslint-disable import/max-dependencies */
2
- import { readdirSync } from "fs"
1
+ import { readdirSync, statSync } from "node:fs"
3
2
  import {
4
3
  normalizeStructuredMetaMap,
5
4
  urlCanContainsMetaMatching,
6
5
  urlToMeta,
7
6
  } from "@jsenv/url-meta"
7
+
8
+ import { assertAndNormalizeDirectoryUrl } from "./assertAndNormalizeDirectoryUrl.js"
9
+ import { statsToType } from "./internal/statsToType.js"
10
+ import { guardTooFastSecondCall } from "./internal/guard_second_call.js"
8
11
  import { replaceBackSlashesWithSlashes } from "./internal/replaceBackSlashesWithSlashes.js"
9
- import { fileSystemNodeToTypeOrNull } from "./internal/fileSystemNodeToTypeOrNull.js"
10
12
  import { createWatcher } from "./internal/createWatcher.js"
11
13
  import { trackRessources } from "./internal/trackRessources.js"
12
- import { ensureUrlTrailingSlash } from "./internal/ensureUrlTrailingSlash.js"
13
- import { resolveUrl } from "./resolveUrl.js"
14
- import { assertAndNormalizeFileUrl } from "./assertAndNormalizeFileUrl.js"
15
14
  import { urlToFileSystemPath } from "./urlToFileSystemPath.js"
16
15
  import { urlToRelativeUrl } from "./urlToRelativeUrl.js"
17
16
 
@@ -22,18 +21,25 @@ const fsWatchSupportsRecursive = !isLinux
22
21
  export const registerDirectoryLifecycle = (
23
22
  source,
24
23
  {
24
+ debug = false,
25
25
  added,
26
26
  updated,
27
27
  removed,
28
- watchDescription = {
28
+ watchPatterns = {
29
29
  "./**/*": true,
30
30
  },
31
31
  notifyExistent = false,
32
32
  keepProcessAlive = true,
33
33
  recursive = false,
34
+ // filesystem might dispatch more events than expected
35
+ // Code can use "cooldownBetweenFileEvents" to prevent that
36
+ // BUT it is UNADVISED to rely on this as explained later (search for "is lying" in this file)
37
+ // For this reason"cooldownBetweenFileEvents" should be reserved to scenarios
38
+ // like unit tests
39
+ cooldownBetweenFileEvents = 0,
34
40
  },
35
41
  ) => {
36
- const sourceUrl = ensureUrlTrailingSlash(assertAndNormalizeFileUrl(source))
42
+ const sourceUrl = assertAndNormalizeDirectoryUrl(source)
37
43
  if (!undefinedOrFunction(added)) {
38
44
  throw new TypeError(`added must be a function or undefined, got ${added}`)
39
45
  }
@@ -47,34 +53,70 @@ export const registerDirectoryLifecycle = (
47
53
  `removed must be a function or undefined, got ${removed}`,
48
54
  )
49
55
  }
56
+ if (cooldownBetweenFileEvents) {
57
+ if (added) {
58
+ added = guardTooFastSecondCall(added, cooldownBetweenFileEvents)
59
+ }
60
+ if (updated) {
61
+ updated = guardTooFastSecondCall(updated, cooldownBetweenFileEvents)
62
+ }
63
+ if (removed) {
64
+ removed = guardTooFastSecondCall(removed, cooldownBetweenFileEvents)
65
+ }
66
+ }
50
67
 
51
68
  const structuredMetaMap = normalizeStructuredMetaMap(
52
- { watch: watchDescription },
69
+ { watch: watchPatterns },
53
70
  sourceUrl,
54
71
  )
55
- const entryShouldBeWatched = ({ relativeUrl, type }) => {
56
- const entryUrl = resolveUrl(relativeUrl, sourceUrl)
57
-
72
+ const getWatchPatternValue = ({ url, type }) => {
58
73
  if (type === "directory") {
59
- const canContainEntryToWatch = urlCanContainsMetaMatching({
60
- url: `${entryUrl}/`,
74
+ let firstMeta = false
75
+ urlCanContainsMetaMatching({
76
+ url: `${url}/`,
61
77
  structuredMetaMap,
62
- predicate: ({ watch }) => watch,
78
+ predicate: ({ watch }) => {
79
+ if (watch) {
80
+ firstMeta = watch
81
+ }
82
+ return watch
83
+ },
63
84
  })
64
- return canContainEntryToWatch
85
+ return firstMeta
65
86
  }
66
-
67
- const entryMeta = urlToMeta({
68
- url: entryUrl,
87
+ const filesystemEntryMeta = urlToMeta({
88
+ url,
69
89
  structuredMetaMap,
70
90
  })
71
-
72
- return entryMeta.watch
91
+ return filesystemEntryMeta.watch
73
92
  }
74
-
75
93
  const tracker = trackRessources()
76
-
77
- const contentMap = new Map()
94
+ const infoMap = new Map()
95
+ const readEntryInfo = (url) => {
96
+ try {
97
+ const relativeUrl = urlToRelativeUrl(url, source)
98
+ const previousInfo = infoMap.get(relativeUrl)
99
+ const stats = statSync(new URL(url))
100
+ const type = statsToType(stats)
101
+ const patternValue = previousInfo
102
+ ? previousInfo.patternValue
103
+ : getWatchPatternValue({ url, type })
104
+ return {
105
+ previousInfo,
106
+ url,
107
+ relativeUrl,
108
+ type,
109
+ atimeMs: stats.atimeMs,
110
+ mtimeMs: stats.mtimeMs,
111
+ patternValue,
112
+ }
113
+ } catch (e) {
114
+ if (e.code === "ENOENT") {
115
+ return null
116
+ }
117
+ throw e
118
+ }
119
+ }
78
120
 
79
121
  const handleDirectoryEvent = ({
80
122
  directoryRelativeUrl,
@@ -84,98 +126,103 @@ export const registerDirectoryLifecycle = (
84
126
  if (filename) {
85
127
  if (directoryRelativeUrl) {
86
128
  handleChange(`${directoryRelativeUrl}/${filename}`)
87
- } else {
88
- handleChange(`${filename}`)
129
+ return
130
+ }
131
+ handleChange(`${filename}`)
132
+ return
133
+ }
134
+ if (eventType === "rename") {
135
+ if (!removed && !added) {
136
+ return
89
137
  }
90
- } else if ((removed || added) && eventType === "rename") {
91
138
  // we might receive `rename` without filename
92
139
  // in that case we try to find ourselves which file was removed.
93
-
94
- let relativeUrlCandidateArray = Array.from(contentMap.keys())
95
-
140
+ let relativeUrlCandidateArray = Array.from(infoMap.keys())
96
141
  if (recursive && !fsWatchSupportsRecursive) {
97
142
  relativeUrlCandidateArray = relativeUrlCandidateArray.filter(
98
143
  (relativeUrlCandidate) => {
99
144
  if (!directoryRelativeUrl) {
100
145
  // ensure entry is top level
101
- if (relativeUrlCandidate.includes("/")) return false
146
+ if (relativeUrlCandidate.includes("/")) {
147
+ return false
148
+ }
102
149
  return true
103
150
  }
104
-
105
151
  // entry not inside this directory
106
- if (!relativeUrlCandidate.startsWith(directoryRelativeUrl))
152
+ if (!relativeUrlCandidate.startsWith(directoryRelativeUrl)) {
107
153
  return false
108
-
154
+ }
109
155
  const afterDirectory = relativeUrlCandidate.slice(
110
156
  directoryRelativeUrl.length + 1,
111
157
  )
112
158
  // deep inside this directory
113
- if (afterDirectory.includes("/")) return false
114
-
159
+ if (afterDirectory.includes("/")) {
160
+ return false
161
+ }
115
162
  return true
116
163
  },
117
164
  )
118
165
  }
119
-
120
166
  const removedEntryRelativeUrl = relativeUrlCandidateArray.find(
121
167
  (relativeUrlCandidate) => {
122
- const entryUrl = resolveUrl(relativeUrlCandidate, sourceUrl)
123
- const type = fileSystemNodeToTypeOrNull(entryUrl)
124
- return type === null
168
+ try {
169
+ statSync(new URL(relativeUrlCandidate, sourceUrl))
170
+ return false
171
+ } catch (e) {
172
+ if (e.code === "ENOENT") {
173
+ return true
174
+ }
175
+ throw e
176
+ }
125
177
  },
126
178
  )
127
-
128
179
  if (removedEntryRelativeUrl) {
129
- handleEntryLost({
130
- relativeUrl: removedEntryRelativeUrl,
131
- type: contentMap.get(removedEntryRelativeUrl),
132
- })
180
+ handleEntryLost(infoMap.get(removedEntryRelativeUrl))
133
181
  }
134
182
  }
135
183
  }
136
184
 
137
185
  const handleChange = (relativeUrl) => {
138
- const entryUrl = resolveUrl(relativeUrl, sourceUrl)
139
- const previousType = contentMap.get(relativeUrl)
140
- const type = fileSystemNodeToTypeOrNull(entryUrl)
141
-
142
- if (!entryShouldBeWatched({ relativeUrl, type })) {
186
+ const entryUrl = new URL(relativeUrl, sourceUrl).href
187
+ const entryInfo = readEntryInfo(entryUrl)
188
+ if (!entryInfo) {
189
+ const previousEntryInfo = infoMap.get(relativeUrl)
190
+ if (!previousEntryInfo) {
191
+ // on MacOS it's possible to receive a "rename" event for
192
+ // a file that does not exists...
193
+ return
194
+ }
195
+ if (debug) {
196
+ console.debug(`"${relativeUrl}" removed`)
197
+ }
198
+ handleEntryLost(previousEntryInfo)
143
199
  return
144
200
  }
145
-
146
- // it's something new
147
- if (!previousType) {
148
- if (type !== null) {
149
- handleEntryFound({ relativeUrl, type, existent: false })
201
+ const { previousInfo } = entryInfo
202
+ if (!previousInfo) {
203
+ if (debug) {
204
+ console.debug(`"${relativeUrl}" added`)
150
205
  }
206
+ handleEntryFound(entryInfo)
151
207
  return
152
208
  }
153
-
154
- // it existed but now it's not here anymore
155
- if (type === null) {
156
- handleEntryLost({ relativeUrl, type: previousType })
209
+ if (entryInfo.type !== previousInfo.type) {
210
+ // it existed and was replaced by something else
211
+ // we don't handle this as an update. We rather say the ressource
212
+ // is lost and something else is found (call removed() then added())
213
+ handleEntryLost(previousInfo)
214
+ handleEntryFound(entryInfo)
157
215
  return
158
216
  }
159
-
160
- // it existed and was replaced by something else
161
- // we don't handle this as an update. We rather say the ressource
162
- // is lost and something else is found (call removed() then added())
163
- if (previousType !== type) {
164
- handleEntryLost({ relativeUrl, type: previousType })
165
- handleEntryFound({ relativeUrl, type })
217
+ if (entryInfo.type === "directory") {
218
+ // a directory cannot really be updated in way that matters for us
219
+ // filesystem is trying to tell us the directory content have changed
220
+ // but we don't care about that
221
+ // we'll already be notified about what has changed
166
222
  return
167
223
  }
168
-
169
- // a directory cannot really be updated in way that matters for us
170
- // filesystem is trying to tell us the directory content have changed
171
- // but we don't care about that
172
- // we'll already be notified about what has changed
173
- if (type === "directory") {
174
- return
175
- }
176
-
177
224
  // something has changed at this relativeUrl (the file existed and was not deleted)
178
- // it's possible to get there and there is no real update
225
+ // it's possible to get there without a real update
179
226
  // (file content is the same and file mtime is the same).
180
227
  // In short filesystem is sometimes "lying"
181
228
  // Not trying to guard against that because:
@@ -183,76 +230,95 @@ export const registerDirectoryLifecycle = (
183
230
  // - it happens very rarely
184
231
  // - it's not really a concern in practice
185
232
  // - filesystem did not send an event out of nowhere:
186
- // something occured but we don't know what with the information we have.
187
- if (updated) {
188
- updated({ relativeUrl, type })
233
+ // something occured but we don't know exactly what
234
+ // maybe we should exclude some stuff as done in
235
+ // https://github.com/paulmillr/chokidar/blob/b2c4f249b6cfa98c703f0066fb4a56ccd83128b5/lib/nodefs-handler.js#L366
236
+ if (debug) {
237
+ console.debug(`"${relativeUrl}" modified`)
189
238
  }
239
+ handleEntryUpdated(entryInfo)
190
240
  }
191
-
192
- const handleEntryFound = ({ relativeUrl, type, existent }) => {
193
- if (!entryShouldBeWatched({ relativeUrl, type })) {
194
- return
195
- }
196
-
197
- contentMap.set(relativeUrl, type)
198
-
199
- const entryUrl = resolveUrl(relativeUrl, sourceUrl)
200
-
201
- if (type === "directory") {
202
- visitDirectory({
203
- directoryUrl: `${entryUrl}/`,
204
- entryFound: (entry) => {
205
- handleEntryFound({
206
- relativeUrl: `${relativeUrl}/${entry.relativeUrl}`,
207
- type: entry.type,
208
- existent,
209
- })
210
- },
211
- })
212
- }
213
-
214
- if (added) {
215
- if (existent) {
216
- if (notifyExistent) {
217
- added({ relativeUrl, type, existent: true })
241
+ const handleEntryFound = (entryInfo, { notify = true } = {}) => {
242
+ infoMap.set(entryInfo.relativeUrl, entryInfo)
243
+ if (entryInfo.type === "directory") {
244
+ const directoryUrl = `${entryInfo.url}/`
245
+ readdirSync(new URL(directoryUrl)).forEach((entryName) => {
246
+ const childEntryUrl = new URL(entryName, directoryUrl).href
247
+ const childEntryInfo = readEntryInfo(childEntryUrl)
248
+ if (childEntryInfo) {
249
+ handleEntryFound(childEntryInfo)
218
250
  }
219
- } else {
220
- added({ relativeUrl, type })
251
+ })
252
+ // we must watch manually every directory we find
253
+ if (!fsWatchSupportsRecursive) {
254
+ const watcher = createWatcher(urlToFileSystemPath(entryInfo.url), {
255
+ persistent: keepProcessAlive,
256
+ })
257
+ tracker.registerCleanupCallback(() => {
258
+ watcher.close()
259
+ })
260
+ watcher.on("change", (eventType, filename) => {
261
+ handleDirectoryEvent({
262
+ directoryRelativeUrl: entryInfo.relativeUrl,
263
+ filename: filename ? replaceBackSlashesWithSlashes(filename) : "",
264
+ eventType,
265
+ })
266
+ })
221
267
  }
222
268
  }
223
-
224
- // we must watch manually every directory we find
225
- if (!fsWatchSupportsRecursive && type === "directory") {
226
- const watcher = createWatcher(urlToFileSystemPath(entryUrl), {
227
- persistent: keepProcessAlive,
228
- })
229
- tracker.registerCleanupCallback(() => {
230
- watcher.close()
269
+ if (added && entryInfo.patternValue && notify) {
270
+ added({
271
+ relativeUrl: entryInfo.relativeUrl,
272
+ type: entryInfo.type,
273
+ patternValue: entryInfo.patternValue,
274
+ mtime: entryInfo.mtimeMs,
231
275
  })
232
- watcher.on("change", (eventType, filename) => {
233
- handleDirectoryEvent({
234
- directoryRelativeUrl: relativeUrl,
235
- filename: filename ? replaceBackSlashesWithSlashes(filename) : "",
236
- eventType,
237
- })
276
+ }
277
+ }
278
+ const handleEntryLost = (entryInfo) => {
279
+ infoMap.delete(entryInfo.relativeUrl)
280
+ if (removed && entryInfo.patternValue) {
281
+ removed({
282
+ relativeUrl: entryInfo.relativeUrl,
283
+ type: entryInfo.type,
284
+ patternValue: entryInfo.patternValue,
285
+ mtime: entryInfo.mtimeMs,
238
286
  })
239
287
  }
240
288
  }
241
-
242
- const handleEntryLost = ({ relativeUrl, type }) => {
243
- contentMap.delete(relativeUrl)
244
- if (removed) {
245
- removed({ relativeUrl, type })
289
+ const handleEntryUpdated = (entryInfo) => {
290
+ infoMap.set(entryInfo.relativeUrl, entryInfo)
291
+ if (updated && entryInfo.patternValue) {
292
+ updated({
293
+ relativeUrl: entryInfo.relativeUrl,
294
+ type: entryInfo.type,
295
+ patternValue: entryInfo.patternValue,
296
+ mtime: entryInfo.mtimeMs,
297
+ previousMtime: entryInfo.previousInfo.mtimeMs,
298
+ })
246
299
  }
247
300
  }
248
301
 
249
- visitDirectory({
250
- directoryUrl: sourceUrl,
251
- entryFound: ({ relativeUrl, type }) => {
252
- handleEntryFound({ relativeUrl, type, existent: true })
253
- },
302
+ readdirSync(new URL(sourceUrl)).forEach((entry) => {
303
+ const entryUrl = new URL(entry, sourceUrl).href
304
+ const entryInfo = readEntryInfo(entryUrl)
305
+ if (entryInfo) {
306
+ handleEntryFound(entryInfo, {
307
+ notify: notifyExistent,
308
+ })
309
+ }
254
310
  })
255
-
311
+ if (debug) {
312
+ const relativeUrls = Array.from(infoMap.keys())
313
+ if (relativeUrls.length === 0) {
314
+ console.debug(`No file found`)
315
+ } else {
316
+ console.debug(
317
+ `${relativeUrls.length} file found:
318
+ ${relativeUrls.join("\n")}`,
319
+ )
320
+ }
321
+ }
256
322
  const watcher = createWatcher(urlToFileSystemPath(sourceUrl), {
257
323
  recursive: recursive && fsWatchSupportsRecursive,
258
324
  persistent: keepProcessAlive,
@@ -270,24 +336,8 @@ export const registerDirectoryLifecycle = (
270
336
  return tracker.cleanup
271
337
  }
272
338
 
273
- const undefinedOrFunction = (value) =>
274
- typeof value === "undefined" || typeof value === "function"
275
-
276
- const visitDirectory = ({ directoryUrl, entryFound }) => {
277
- const directoryPath = urlToFileSystemPath(directoryUrl)
278
- readdirSync(directoryPath).forEach((entry) => {
279
- const entryUrl = resolveUrl(entry, directoryUrl)
280
- const type = fileSystemNodeToTypeOrNull(entryUrl)
281
- if (type === null) {
282
- return
283
- }
284
-
285
- const relativeUrl = urlToRelativeUrl(entryUrl, directoryUrl)
286
- entryFound({
287
- relativeUrl,
288
- type,
289
- })
290
- })
339
+ const undefinedOrFunction = (value) => {
340
+ return typeof value === "undefined" || typeof value === "function"
291
341
  }
292
342
 
293
343
  const fileSystemPathToDirectoryRelativeUrlAndFilename = (path) => {
@@ -1,5 +1,8 @@
1
- import { dirname, basename } from "path"
2
- import { fileSystemNodeToTypeOrNull } from "./internal/fileSystemNodeToTypeOrNull.js"
1
+ import { statSync } from "node:fs"
2
+ import { dirname, basename } from "node:path"
3
+
4
+ import { guardTooFastSecondCall } from "./internal/guard_second_call.js"
5
+ import { statsToType } from "./internal/statsToType.js"
3
6
  import { createWatcher } from "./internal/createWatcher.js"
4
7
  import { trackRessources } from "./internal/trackRessources.js"
5
8
  import { assertAndNormalizeFileUrl } from "./assertAndNormalizeFileUrl.js"
@@ -7,7 +10,14 @@ import { urlToFileSystemPath } from "./urlToFileSystemPath.js"
7
10
 
8
11
  export const registerFileLifecycle = (
9
12
  source,
10
- { added, updated, removed, notifyExistent = false, keepProcessAlive = true },
13
+ {
14
+ added,
15
+ updated,
16
+ removed,
17
+ notifyExistent = false,
18
+ keepProcessAlive = true,
19
+ cooldownBetweenFileEvents = 0,
20
+ },
11
21
  ) => {
12
22
  const sourceUrl = assertAndNormalizeFileUrl(source)
13
23
  if (!undefinedOrFunction(added)) {
@@ -23,6 +33,17 @@ export const registerFileLifecycle = (
23
33
  `removed must be a function or undefined, got ${removed}`,
24
34
  )
25
35
  }
36
+ if (cooldownBetweenFileEvents) {
37
+ if (added) {
38
+ added = guardTooFastSecondCall(added, cooldownBetweenFileEvents)
39
+ }
40
+ if (updated) {
41
+ updated = guardTooFastSecondCall(updated, cooldownBetweenFileEvents)
42
+ }
43
+ if (removed) {
44
+ removed = guardTooFastSecondCall(removed, cooldownBetweenFileEvents)
45
+ }
46
+ }
26
47
 
27
48
  const tracker = trackRessources()
28
49
 
@@ -67,7 +88,7 @@ export const registerFileLifecycle = (
67
88
  )
68
89
  }
69
90
 
70
- const sourceType = fileSystemNodeToTypeOrNull(sourceUrl)
91
+ const sourceType = entryToTypeOrNull(sourceUrl)
71
92
  if (sourceType === null) {
72
93
  if (added) {
73
94
  watchFileAdded()
@@ -89,6 +110,18 @@ export const registerFileLifecycle = (
89
110
  return tracker.cleanup
90
111
  }
91
112
 
113
+ const entryToTypeOrNull = (url) => {
114
+ try {
115
+ const stats = statSync(new URL(url))
116
+ return statsToType(stats)
117
+ } catch (e) {
118
+ if (e.code === "ENOENT") {
119
+ return null
120
+ }
121
+ throw e
122
+ }
123
+ }
124
+
92
125
  const undefinedOrFunction = (value) =>
93
126
  typeof value === "undefined" || typeof value === "function"
94
127
 
@@ -102,7 +135,7 @@ const watchFileCreation = (source, callback, keepProcessAlive) => {
102
135
  directoryWatcher.on("change", (eventType, filename) => {
103
136
  if (filename && filename !== sourceFilename) return
104
137
 
105
- const type = fileSystemNodeToTypeOrNull(source)
138
+ const type = entryToTypeOrNull(source)
106
139
  // ignore if something else with that name gets created
107
140
  // we are only interested into files
108
141
  if (type !== "file") return
@@ -128,7 +161,7 @@ const watchFileMutation = (
128
161
  })
129
162
 
130
163
  watcher.on("change", () => {
131
- const sourceType = fileSystemNodeToTypeOrNull(sourceUrl)
164
+ const sourceType = entryToTypeOrNull(sourceUrl)
132
165
 
133
166
  if (sourceType === null) {
134
167
  watcher.close()
@@ -4,11 +4,11 @@ import { Abort } from "@jsenv/abort"
4
4
  import { ensureUrlTrailingSlash } from "./internal/ensureUrlTrailingSlash.js"
5
5
  import { assertAndNormalizeFileUrl } from "./assertAndNormalizeFileUrl.js"
6
6
  import { urlToFileSystemPath } from "./urlToFileSystemPath.js"
7
- import { readFileSystemNodeStat } from "./readFileSystemNodeStat.js"
7
+ import { readEntryStat } from "./readEntryStat.js"
8
8
  import { readDirectory } from "./readDirectory.js"
9
9
  import { resolveUrl } from "./resolveUrl.js"
10
10
 
11
- export const removeFileSystemNode = async (
11
+ export const removeEntry = async (
12
12
  source,
13
13
  {
14
14
  signal = new AbortController().signal,
@@ -26,7 +26,7 @@ export const removeFileSystemNode = async (
26
26
 
27
27
  try {
28
28
  removeOperation.throwIfAborted()
29
- const sourceStats = await readFileSystemNodeStat(sourceUrl, {
29
+ const sourceStats = await readEntryStat(sourceUrl, {
30
30
  nullIfNotFound: true,
31
31
  followLink: false,
32
32
  })
@@ -123,7 +123,7 @@ const removeDirectory = async (
123
123
 
124
124
  const visit = async (sourceUrl) => {
125
125
  removeDirectoryOperation.throwIfAborted()
126
- const sourceStats = await readFileSystemNodeStat(sourceUrl, {
126
+ const sourceStats = await readEntryStat(sourceUrl, {
127
127
  nullIfNotFound: true,
128
128
  followLink: false,
129
129
  })
@@ -1,4 +1,5 @@
1
- import { promises, constants } from "fs"
1
+ import { promises, constants } from "node:fs"
2
+
2
3
  import { assertAndNormalizeFileUrl } from "./assertAndNormalizeFileUrl.js"
3
4
  import { urlToFileSystemPath } from "./urlToFileSystemPath.js"
4
5
 
@@ -10,7 +11,7 @@ const {
10
11
  X_OK,
11
12
  } = constants
12
13
 
13
- export const testFileSystemNodePermissions = async (
14
+ export const testEntryPermissions = async (
14
15
  source,
15
16
  {
16
17
  read = false,
@@ -1,8 +1,9 @@
1
- import { promises } from "fs"
1
+ import { promises } from "node:fs"
2
+
2
3
  import { statsToType } from "./internal/statsToType.js"
3
4
  import { assertAndNormalizeDirectoryUrl } from "./assertAndNormalizeDirectoryUrl.js"
4
5
  import { urlToFileSystemPath } from "./urlToFileSystemPath.js"
5
- import { readFileSystemNodeStat } from "./readFileSystemNodeStat.js"
6
+ import { readEntryStat } from "./readEntryStat.js"
6
7
 
7
8
  // https://nodejs.org/dist/latest-v13.x/docs/api/fs.html#fs_fspromises_mkdir_path_options
8
9
  const { mkdir } = promises
@@ -14,7 +15,7 @@ export const writeDirectory = async (
14
15
  const destinationUrl = assertAndNormalizeDirectoryUrl(destination)
15
16
  const destinationPath = urlToFileSystemPath(destinationUrl)
16
17
 
17
- const destinationStats = await readFileSystemNodeStat(destinationUrl, {
18
+ const destinationStats = await readEntryStat(destinationUrl, {
18
19
  nullIfNotFound: true,
19
20
  followLink: false,
20
21
  })
@@ -1,8 +1,9 @@
1
- import { utimes } from "fs"
1
+ import { utimes } from "node:fs"
2
+
2
3
  import { assertAndNormalizeFileUrl } from "./assertAndNormalizeFileUrl.js"
3
4
  import { urlToFileSystemPath } from "./urlToFileSystemPath.js"
4
5
 
5
- export const writeFileSystemNodeModificationTime = (source, mtime) => {
6
+ export const writeEntryModificationTime = (source, mtime) => {
6
7
  const sourceUrl = assertAndNormalizeFileUrl(source)
7
8
  const sourcePath = urlToFileSystemPath(sourceUrl)
8
9
  const mtimeValue =
@@ -1,9 +1,10 @@
1
- import { chmod } from "fs"
1
+ import { chmod } from "node:fs"
2
+
2
3
  import { permissionsToBinaryFlags } from "./internal/permissions.js"
3
4
  import { assertAndNormalizeFileUrl } from "./assertAndNormalizeFileUrl.js"
4
5
  import { urlToFileSystemPath } from "./urlToFileSystemPath.js"
5
6
 
6
- export const writeFileSystemNodePermissions = async (source, permissions) => {
7
+ export const writeEntryPermissions = async (source, permissions) => {
7
8
  const sourceUrl = assertAndNormalizeFileUrl(source)
8
9
  const sourcePath = urlToFileSystemPath(sourceUrl)
9
10