@jsenv/filesystem 4.2.3 → 4.2.5

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 (47) hide show
  1. package/README.md +17 -17
  2. package/package.json +4 -4
  3. package/src/assertDirectoryPresence.js +10 -10
  4. package/src/assertFilePresence.js +10 -10
  5. package/src/bufferToEtag.js +11 -11
  6. package/src/collectDirectoryMatchReport.js +38 -38
  7. package/src/collectFiles.js +35 -35
  8. package/src/comparePathnames.js +23 -23
  9. package/src/copyDirectoryContent.js +37 -37
  10. package/src/copyEntry.js +88 -88
  11. package/src/directory_url_validation.js +14 -14
  12. package/src/ensureEmptyDirectory.js +13 -13
  13. package/src/ensureParentDirectories.js +9 -9
  14. package/src/ensureWindowsDriveLetter.js +19 -19
  15. package/src/fileSystemRootUrl.js +1 -1
  16. package/src/file_url_validation.js +14 -14
  17. package/src/getRealFileSystemUrlSync.js +24 -24
  18. package/src/grantPermissionsOnEntry.js +9 -9
  19. package/src/internal/createWatcher.js +12 -12
  20. package/src/internal/getCommandArgument.js +7 -7
  21. package/src/internal/guard_second_call.js +20 -20
  22. package/src/internal/permissions.js +26 -26
  23. package/src/internal/read_entry_info.js +8 -8
  24. package/src/internal/statsToType.js +9 -9
  25. package/src/internal/track_resources.js +12 -12
  26. package/src/internal/urlTargetsSameFileSystemPath.js +4 -4
  27. package/src/listFilesMatching.js +5 -5
  28. package/src/main.js +35 -35
  29. package/src/moveDirectoryContent.js +37 -37
  30. package/src/moveEntry.js +44 -44
  31. package/src/readDirectory.js +21 -21
  32. package/src/readEntryModificationTime.js +4 -4
  33. package/src/readEntryPermissions.js +10 -10
  34. package/src/readEntryStat.js +27 -27
  35. package/src/readFile.js +12 -12
  36. package/src/readFileSync.js +9 -9
  37. package/src/readSymbolicLink.js +9 -9
  38. package/src/registerDirectoryLifecycle.js +118 -118
  39. package/src/registerFileLifecycle.js +66 -66
  40. package/src/removeEntry.js +81 -81
  41. package/src/testEntryPermissions.js +15 -15
  42. package/src/writeDirectory.js +17 -17
  43. package/src/writeEntryModificationTime.js +10 -10
  44. package/src/writeEntryPermissions.js +26 -26
  45. package/src/writeFile.js +16 -16
  46. package/src/writeFileSync.js +10 -10
  47. package/src/writeSymbolicLink.js +39 -39
@@ -1,16 +1,16 @@
1
- import { readdirSync, statSync } from "node:fs"
2
- import { URL_META } from "@jsenv/url-meta"
3
- import { urlToFileSystemPath, urlToRelativeUrl } from "@jsenv/urls"
1
+ import { readdirSync, statSync } from "node:fs";
2
+ import { URL_META } from "@jsenv/url-meta";
3
+ import { urlToFileSystemPath, urlToRelativeUrl } from "@jsenv/urls";
4
4
 
5
- import { assertAndNormalizeDirectoryUrl } from "./directory_url_validation.js"
6
- import { statsToType } from "./internal/statsToType.js"
7
- import { guardTooFastSecondCallPerFile } from "./internal/guard_second_call.js"
8
- import { createWatcher } from "./internal/createWatcher.js"
9
- import { trackResources } from "./internal/track_resources.js"
5
+ import { assertAndNormalizeDirectoryUrl } from "./directory_url_validation.js";
6
+ import { statsToType } from "./internal/statsToType.js";
7
+ import { guardTooFastSecondCallPerFile } from "./internal/guard_second_call.js";
8
+ import { createWatcher } from "./internal/createWatcher.js";
9
+ import { trackResources } from "./internal/track_resources.js";
10
10
 
11
- const isLinux = process.platform === "linux"
11
+ const isLinux = process.platform === "linux";
12
12
  // linux does not support recursive option
13
- const fsWatchSupportsRecursive = !isLinux
13
+ const fsWatchSupportsRecursive = !isLinux;
14
14
 
15
15
  export const registerDirectoryLifecycle = (
16
16
  source,
@@ -33,71 +33,71 @@ export const registerDirectoryLifecycle = (
33
33
  cooldownBetweenFileEvents = 0,
34
34
  },
35
35
  ) => {
36
- const sourceUrl = assertAndNormalizeDirectoryUrl(source)
36
+ const sourceUrl = assertAndNormalizeDirectoryUrl(source);
37
37
  if (!undefinedOrFunction(added)) {
38
- throw new TypeError(`added must be a function or undefined, got ${added}`)
38
+ throw new TypeError(`added must be a function or undefined, got ${added}`);
39
39
  }
40
40
  if (!undefinedOrFunction(updated)) {
41
41
  throw new TypeError(
42
42
  `updated must be a function or undefined, got ${updated}`,
43
- )
43
+ );
44
44
  }
45
45
  if (!undefinedOrFunction(removed)) {
46
46
  throw new TypeError(
47
47
  `removed must be a function or undefined, got ${removed}`,
48
- )
48
+ );
49
49
  }
50
50
  if (cooldownBetweenFileEvents) {
51
51
  if (added) {
52
- added = guardTooFastSecondCallPerFile(added, cooldownBetweenFileEvents)
52
+ added = guardTooFastSecondCallPerFile(added, cooldownBetweenFileEvents);
53
53
  }
54
54
  if (updated) {
55
55
  updated = guardTooFastSecondCallPerFile(
56
56
  updated,
57
57
  cooldownBetweenFileEvents,
58
- )
58
+ );
59
59
  }
60
60
  if (removed) {
61
61
  removed = guardTooFastSecondCallPerFile(
62
62
  removed,
63
63
  cooldownBetweenFileEvents,
64
- )
64
+ );
65
65
  }
66
66
  }
67
67
 
68
68
  const associations = URL_META.resolveAssociations(
69
69
  { watch: watchPatterns },
70
70
  sourceUrl,
71
- )
71
+ );
72
72
  const getWatchPatternValue = ({ url, type }) => {
73
73
  if (type === "directory") {
74
- let firstMeta = false
74
+ let firstMeta = false;
75
75
  URL_META.urlChildMayMatch({
76
76
  url: `${url}/`,
77
77
  associations,
78
78
  predicate: ({ watch }) => {
79
79
  if (watch) {
80
- firstMeta = watch
80
+ firstMeta = watch;
81
81
  }
82
- return watch
82
+ return watch;
83
83
  },
84
- })
85
- return firstMeta
84
+ });
85
+ return firstMeta;
86
86
  }
87
- const { watch } = URL_META.applyAssociations({ url, associations })
88
- return watch
89
- }
90
- const tracker = trackResources()
91
- const infoMap = new Map()
87
+ const { watch } = URL_META.applyAssociations({ url, associations });
88
+ return watch;
89
+ };
90
+ const tracker = trackResources();
91
+ const infoMap = new Map();
92
92
  const readEntryInfo = (url) => {
93
93
  try {
94
- const relativeUrl = urlToRelativeUrl(url, source)
95
- const previousInfo = infoMap.get(relativeUrl)
96
- const stats = statSync(new URL(url))
97
- const type = statsToType(stats)
94
+ const relativeUrl = urlToRelativeUrl(url, source);
95
+ const previousInfo = infoMap.get(relativeUrl);
96
+ const stats = statSync(new URL(url));
97
+ const type = statsToType(stats);
98
98
  const patternValue = previousInfo
99
99
  ? previousInfo.patternValue
100
- : getWatchPatternValue({ url, type })
100
+ : getWatchPatternValue({ url, type });
101
101
  return {
102
102
  previousInfo,
103
103
  url,
@@ -106,14 +106,14 @@ export const registerDirectoryLifecycle = (
106
106
  atimeMs: stats.atimeMs,
107
107
  mtimeMs: stats.mtimeMs,
108
108
  patternValue,
109
- }
109
+ };
110
110
  } catch (e) {
111
111
  if (e.code === "ENOENT") {
112
- return null
112
+ return null;
113
113
  }
114
- throw e
114
+ throw e;
115
115
  }
116
- }
116
+ };
117
117
 
118
118
  const handleDirectoryEvent = ({
119
119
  directoryRelativeUrl,
@@ -122,101 +122,101 @@ export const registerDirectoryLifecycle = (
122
122
  }) => {
123
123
  if (filename) {
124
124
  if (directoryRelativeUrl) {
125
- handleChange(`${directoryRelativeUrl}/${filename}`)
126
- return
125
+ handleChange(`${directoryRelativeUrl}/${filename}`);
126
+ return;
127
127
  }
128
- handleChange(`${filename}`)
129
- return
128
+ handleChange(`${filename}`);
129
+ return;
130
130
  }
131
131
  if (eventType === "rename") {
132
132
  if (!removed && !added) {
133
- return
133
+ return;
134
134
  }
135
135
  // we might receive `rename` without filename
136
136
  // in that case we try to find ourselves which file was removed.
137
- let relativeUrlCandidateArray = Array.from(infoMap.keys())
137
+ let relativeUrlCandidateArray = Array.from(infoMap.keys());
138
138
  if (recursive && !fsWatchSupportsRecursive) {
139
139
  relativeUrlCandidateArray = relativeUrlCandidateArray.filter(
140
140
  (relativeUrlCandidate) => {
141
141
  if (!directoryRelativeUrl) {
142
142
  // ensure entry is top level
143
143
  if (relativeUrlCandidate.includes("/")) {
144
- return false
144
+ return false;
145
145
  }
146
- return true
146
+ return true;
147
147
  }
148
148
  // entry not inside this directory
149
149
  if (!relativeUrlCandidate.startsWith(directoryRelativeUrl)) {
150
- return false
150
+ return false;
151
151
  }
152
152
  const afterDirectory = relativeUrlCandidate.slice(
153
153
  directoryRelativeUrl.length + 1,
154
- )
154
+ );
155
155
  // deep inside this directory
156
156
  if (afterDirectory.includes("/")) {
157
- return false
157
+ return false;
158
158
  }
159
- return true
159
+ return true;
160
160
  },
161
- )
161
+ );
162
162
  }
163
163
  const removedEntryRelativeUrl = relativeUrlCandidateArray.find(
164
164
  (relativeUrlCandidate) => {
165
165
  try {
166
- statSync(new URL(relativeUrlCandidate, sourceUrl))
167
- return false
166
+ statSync(new URL(relativeUrlCandidate, sourceUrl));
167
+ return false;
168
168
  } catch (e) {
169
169
  if (e.code === "ENOENT") {
170
- return true
170
+ return true;
171
171
  }
172
- throw e
172
+ throw e;
173
173
  }
174
174
  },
175
- )
175
+ );
176
176
  if (removedEntryRelativeUrl) {
177
- handleEntryLost(infoMap.get(removedEntryRelativeUrl))
177
+ handleEntryLost(infoMap.get(removedEntryRelativeUrl));
178
178
  }
179
179
  }
180
- }
180
+ };
181
181
 
182
182
  const handleChange = (relativeUrl) => {
183
- const entryUrl = new URL(relativeUrl, sourceUrl).href
184
- const entryInfo = readEntryInfo(entryUrl)
183
+ const entryUrl = new URL(relativeUrl, sourceUrl).href;
184
+ const entryInfo = readEntryInfo(entryUrl);
185
185
  if (!entryInfo) {
186
- const previousEntryInfo = infoMap.get(relativeUrl)
186
+ const previousEntryInfo = infoMap.get(relativeUrl);
187
187
  if (!previousEntryInfo) {
188
188
  // on MacOS it's possible to receive a "rename" event for
189
189
  // a file that does not exists...
190
- return
190
+ return;
191
191
  }
192
192
  if (debug) {
193
- console.debug(`"${relativeUrl}" removed`)
193
+ console.debug(`"${relativeUrl}" removed`);
194
194
  }
195
- handleEntryLost(previousEntryInfo)
196
- return
195
+ handleEntryLost(previousEntryInfo);
196
+ return;
197
197
  }
198
- const { previousInfo } = entryInfo
198
+ const { previousInfo } = entryInfo;
199
199
  if (!previousInfo) {
200
200
  if (debug) {
201
- console.debug(`"${relativeUrl}" added`)
201
+ console.debug(`"${relativeUrl}" added`);
202
202
  }
203
- handleEntryFound(entryInfo)
204
- return
203
+ handleEntryFound(entryInfo);
204
+ return;
205
205
  }
206
206
  if (entryInfo.type !== previousInfo.type) {
207
207
  // it existed and was replaced by something else
208
208
  // we don't handle this as an update. We rather say the resource
209
209
  // is lost and something else is found (call removed() then added())
210
- handleEntryLost(previousInfo)
211
- handleEntryFound(entryInfo)
212
- return
210
+ handleEntryLost(previousInfo);
211
+ handleEntryFound(entryInfo);
212
+ return;
213
213
  }
214
214
  if (entryInfo.type === "directory") {
215
215
  // a directory cannot really be updated in way that matters for us
216
216
  // filesystem is trying to tell us the directory content have changed
217
217
  // but we don't care about that
218
218
  // we'll already be notified about what has changed
219
- return
219
+ return;
220
220
  }
221
221
  // something has changed at this relativeUrl (the file existed and was not deleted)
222
222
  // it's possible to get there without a real update
@@ -231,29 +231,29 @@ export const registerDirectoryLifecycle = (
231
231
  // maybe we should exclude some stuff as done in
232
232
  // https://github.com/paulmillr/chokidar/blob/b2c4f249b6cfa98c703f0066fb4a56ccd83128b5/lib/nodefs-handler.js#L366
233
233
  if (debug) {
234
- console.debug(`"${relativeUrl}" modified`)
234
+ console.debug(`"${relativeUrl}" modified`);
235
235
  }
236
- handleEntryUpdated(entryInfo)
237
- }
236
+ handleEntryUpdated(entryInfo);
237
+ };
238
238
  const handleEntryFound = (entryInfo, { notify = true } = {}) => {
239
- infoMap.set(entryInfo.relativeUrl, entryInfo)
239
+ infoMap.set(entryInfo.relativeUrl, entryInfo);
240
240
  if (entryInfo.type === "directory") {
241
- const directoryUrl = `${entryInfo.url}/`
241
+ const directoryUrl = `${entryInfo.url}/`;
242
242
  readdirSync(new URL(directoryUrl)).forEach((entryName) => {
243
- const childEntryUrl = new URL(entryName, directoryUrl).href
244
- const childEntryInfo = readEntryInfo(childEntryUrl)
243
+ const childEntryUrl = new URL(entryName, directoryUrl).href;
244
+ const childEntryInfo = readEntryInfo(childEntryUrl);
245
245
  if (childEntryInfo && childEntryInfo.patternValue) {
246
- handleEntryFound(childEntryInfo, { notify })
246
+ handleEntryFound(childEntryInfo, { notify });
247
247
  }
248
- })
248
+ });
249
249
  // we must watch manually every directory we find
250
250
  if (!fsWatchSupportsRecursive) {
251
251
  const watcher = createWatcher(urlToFileSystemPath(entryInfo.url), {
252
252
  persistent: keepProcessAlive,
253
- })
253
+ });
254
254
  tracker.registerCleanupCallback(() => {
255
- watcher.close()
256
- })
255
+ watcher.close();
256
+ });
257
257
  watcher.on("change", (eventType, filename) => {
258
258
  handleDirectoryEvent({
259
259
  directoryRelativeUrl: entryInfo.relativeUrl,
@@ -262,8 +262,8 @@ export const registerDirectoryLifecycle = (
262
262
  filename.replace(/\\/g, "/")
263
263
  : "",
264
264
  eventType,
265
- })
266
- })
265
+ });
266
+ });
267
267
  }
268
268
  }
269
269
  if (added && entryInfo.patternValue && notify) {
@@ -272,22 +272,22 @@ export const registerDirectoryLifecycle = (
272
272
  type: entryInfo.type,
273
273
  patternValue: entryInfo.patternValue,
274
274
  mtime: entryInfo.mtimeMs,
275
- })
275
+ });
276
276
  }
277
- }
277
+ };
278
278
  const handleEntryLost = (entryInfo) => {
279
- infoMap.delete(entryInfo.relativeUrl)
279
+ infoMap.delete(entryInfo.relativeUrl);
280
280
  if (removed && entryInfo.patternValue) {
281
281
  removed({
282
282
  relativeUrl: entryInfo.relativeUrl,
283
283
  type: entryInfo.type,
284
284
  patternValue: entryInfo.patternValue,
285
285
  mtime: entryInfo.mtimeMs,
286
- })
286
+ });
287
287
  }
288
- }
288
+ };
289
289
  const handleEntryUpdated = (entryInfo) => {
290
- infoMap.set(entryInfo.relativeUrl, entryInfo)
290
+ infoMap.set(entryInfo.relativeUrl, entryInfo);
291
291
  if (updated && entryInfo.patternValue) {
292
292
  updated({
293
293
  relativeUrl: entryInfo.relativeUrl,
@@ -295,72 +295,72 @@ export const registerDirectoryLifecycle = (
295
295
  patternValue: entryInfo.patternValue,
296
296
  mtime: entryInfo.mtimeMs,
297
297
  previousMtime: entryInfo.previousInfo.mtimeMs,
298
- })
298
+ });
299
299
  }
300
- }
300
+ };
301
301
 
302
302
  readdirSync(new URL(sourceUrl)).forEach((entry) => {
303
- const entryUrl = new URL(entry, sourceUrl).href
304
- const entryInfo = readEntryInfo(entryUrl)
303
+ const entryUrl = new URL(entry, sourceUrl).href;
304
+ const entryInfo = readEntryInfo(entryUrl);
305
305
  if (entryInfo && entryInfo.patternValue) {
306
306
  handleEntryFound(entryInfo, {
307
307
  notify: notifyExistent,
308
- })
308
+ });
309
309
  }
310
- })
310
+ });
311
311
  if (debug) {
312
- const relativeUrls = Array.from(infoMap.keys())
312
+ const relativeUrls = Array.from(infoMap.keys());
313
313
  if (relativeUrls.length === 0) {
314
- console.debug(`No file found`)
314
+ console.debug(`No file found`);
315
315
  } else {
316
316
  console.debug(
317
317
  `${relativeUrls.length} file found:
318
318
  ${relativeUrls.join("\n")}`,
319
- )
319
+ );
320
320
  }
321
321
  }
322
322
  const watcher = createWatcher(urlToFileSystemPath(sourceUrl), {
323
323
  recursive: recursive && fsWatchSupportsRecursive,
324
324
  persistent: keepProcessAlive,
325
- })
325
+ });
326
326
  tracker.registerCleanupCallback(() => {
327
- watcher.close()
328
- })
327
+ watcher.close();
328
+ });
329
329
  watcher.on("change", (eventType, fileSystemPath) => {
330
330
  handleDirectoryEvent({
331
331
  ...fileSystemPathToDirectoryRelativeUrlAndFilename(fileSystemPath),
332
332
  eventType,
333
- })
334
- })
333
+ });
334
+ });
335
335
 
336
- return tracker.cleanup
337
- }
336
+ return tracker.cleanup;
337
+ };
338
338
 
339
339
  const undefinedOrFunction = (value) => {
340
- return typeof value === "undefined" || typeof value === "function"
341
- }
340
+ return typeof value === "undefined" || typeof value === "function";
341
+ };
342
342
 
343
343
  const fileSystemPathToDirectoryRelativeUrlAndFilename = (path) => {
344
344
  if (!path) {
345
345
  return {
346
346
  directoryRelativeUrl: "",
347
347
  filename: "",
348
- }
348
+ };
349
349
  }
350
350
 
351
- const normalizedPath = path.replace(/\\/g, "/") // replace back slashes with slashes
352
- const slashLastIndex = normalizedPath.lastIndexOf("/")
351
+ const normalizedPath = path.replace(/\\/g, "/"); // replace back slashes with slashes
352
+ const slashLastIndex = normalizedPath.lastIndexOf("/");
353
353
  if (slashLastIndex === -1) {
354
354
  return {
355
355
  directoryRelativeUrl: "",
356
356
  filename: normalizedPath,
357
- }
357
+ };
358
358
  }
359
359
 
360
- const directoryRelativeUrl = normalizedPath.slice(0, slashLastIndex)
361
- const filename = normalizedPath.slice(slashLastIndex + 1)
360
+ const directoryRelativeUrl = normalizedPath.slice(0, slashLastIndex);
361
+ const filename = normalizedPath.slice(slashLastIndex + 1);
362
362
  return {
363
363
  directoryRelativeUrl,
364
364
  filename,
365
- }
366
- }
365
+ };
366
+ };