@jsenv/filesystem 4.0.10 → 4.1.2

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/filesystem",
3
- "version": "4.0.10",
3
+ "version": "4.1.2",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,8 +8,7 @@
8
8
  "directory": "packages/filesystem"
9
9
  },
10
10
  "publishConfig": {
11
- "access": "public",
12
- "registry": "https://registry.npmjs.org"
11
+ "access": "public"
13
12
  },
14
13
  "author": {
15
14
  "name": "dmail",
@@ -31,8 +30,8 @@
31
30
  "test": "node --conditions=development ./scripts/test.mjs"
32
31
  },
33
32
  "dependencies": {
34
- "@jsenv/urls": "1.2.6",
33
+ "@jsenv/urls": "1.2.7",
35
34
  "@jsenv/url-meta": "7.0.0",
36
35
  "@jsenv/abort": "4.2.3"
37
36
  }
38
- }
37
+ }
@@ -30,7 +30,6 @@ export const collectFiles = async ({
30
30
  await Promise.all(
31
31
  directoryItems.map(async (directoryItem) => {
32
32
  const directoryChildNodeUrl = `${directoryUrl}${directoryItem}`
33
-
34
33
  collectOperation.throwIfAborted()
35
34
  const directoryChildNodeStats = await readEntryStat(
36
35
  directoryChildNodeUrl,
@@ -59,10 +59,10 @@ export const ensureWindowsDriveLetter = (url, baseUrl) => {
59
59
  return `file:///${driveLetter}:${afterProtocol}`
60
60
  }
61
61
 
62
- const extractDriveLetter = (ressource) => {
62
+ const extractDriveLetter = (resource) => {
63
63
  // we still have the windows drive letter
64
- if (/[a-zA-Z]/.test(ressource[1]) && ressource[2] === ":") {
65
- return ressource[1]
64
+ if (/[a-zA-Z]/.test(resource[1]) && resource[2] === ":") {
65
+ return resource[1]
66
66
  }
67
67
  return null
68
68
  }
@@ -1,6 +1,25 @@
1
1
  export const guardTooFastSecondCall = (
2
2
  callback,
3
3
  cooldownBetweenFileEvents = 40,
4
+ ) => {
5
+ let previousCallMs
6
+ return (...args) => {
7
+ const nowMs = Date.now()
8
+ if (previousCallMs) {
9
+ const msEllapsed = nowMs - previousCallMs
10
+ if (msEllapsed < cooldownBetweenFileEvents) {
11
+ previousCallMs = null
12
+ return
13
+ }
14
+ }
15
+ previousCallMs = nowMs
16
+ callback(...args)
17
+ }
18
+ }
19
+
20
+ export const guardTooFastSecondCallPerFile = (
21
+ callback,
22
+ cooldownBetweenFileEvents = 40,
4
23
  ) => {
5
24
  const previousCallMsMap = new Map()
6
25
  return (fileEvent) => {
@@ -1,4 +1,4 @@
1
- export const trackRessources = () => {
1
+ export const trackResources = () => {
2
2
  const callbackArray = []
3
3
 
4
4
  const registerCleanupCallback = (callback) => {
@@ -1,54 +1,39 @@
1
1
  import { readdir } from "node:fs"
2
- import { urlToFileSystemPath } from "@jsenv/urls"
3
2
  import { assertAndNormalizeDirectoryUrl } from "./assertAndNormalizeDirectoryUrl.js"
4
3
 
5
4
  export const readDirectory = async (url, { emfileMaxWait = 1000 } = {}) => {
6
5
  const directoryUrl = assertAndNormalizeDirectoryUrl(url)
7
- const directoryPath = urlToFileSystemPath(directoryUrl)
6
+ const directoryUrlObject = new URL(directoryUrl)
8
7
  const startMs = Date.now()
9
8
  let attemptCount = 0
10
9
 
11
- const attempt = () => {
12
- return readdirNaive(directoryPath, {
13
- handleTooManyFilesOpenedError: async (error) => {
10
+ const attempt = async () => {
11
+ try {
12
+ const names = await new Promise((resolve, reject) => {
13
+ readdir(directoryUrlObject, (error, names) => {
14
+ if (error) {
15
+ reject(error)
16
+ } else {
17
+ resolve(names)
18
+ }
19
+ })
20
+ })
21
+ return names.map(encodeURIComponent)
22
+ } catch (e) {
23
+ // https://nodejs.org/dist/latest-v13.x/docs/api/errors.html#errors_common_system_errors
24
+ if (e.code === "EMFILE" || e.code === "ENFILE") {
14
25
  attemptCount++
15
26
  const nowMs = Date.now()
16
27
  const timeSpentWaiting = nowMs - startMs
17
28
  if (timeSpentWaiting > emfileMaxWait) {
18
- throw error
29
+ throw e
19
30
  }
20
-
21
- return new Promise((resolve) => {
22
- setTimeout(() => {
23
- resolve(attempt())
24
- }, attemptCount)
25
- })
26
- },
27
- })
31
+ await new Promise((resolve) => setTimeout(resolve), attemptCount)
32
+ return await attempt()
33
+ }
34
+ throw e
35
+ }
28
36
  }
29
37
 
30
38
  return attempt()
31
39
  }
32
-
33
- const readdirNaive = (
34
- directoryPath,
35
- { handleTooManyFilesOpenedError = null } = {},
36
- ) => {
37
- return new Promise((resolve, reject) => {
38
- readdir(directoryPath, (error, names) => {
39
- if (error) {
40
- // https://nodejs.org/dist/latest-v13.x/docs/api/errors.html#errors_common_system_errors
41
- if (
42
- handleTooManyFilesOpenedError &&
43
- (error.code === "EMFILE" || error.code === "ENFILE")
44
- ) {
45
- resolve(handleTooManyFilesOpenedError(error))
46
- } else {
47
- reject(error)
48
- }
49
- } else {
50
- resolve(names)
51
- }
52
- })
53
- })
54
- }
@@ -4,9 +4,9 @@ import { urlToFileSystemPath, urlToRelativeUrl } from "@jsenv/urls"
4
4
 
5
5
  import { assertAndNormalizeDirectoryUrl } from "./assertAndNormalizeDirectoryUrl.js"
6
6
  import { statsToType } from "./internal/statsToType.js"
7
- import { guardTooFastSecondCall } from "./internal/guard_second_call.js"
7
+ import { guardTooFastSecondCallPerFile } from "./internal/guard_second_call.js"
8
8
  import { createWatcher } from "./internal/createWatcher.js"
9
- import { trackRessources } from "./internal/trackRessources.js"
9
+ import { trackResources } from "./internal/track_resources.js"
10
10
 
11
11
  const isLinux = process.platform === "linux"
12
12
  // linux does not support recursive option
@@ -49,13 +49,19 @@ export const registerDirectoryLifecycle = (
49
49
  }
50
50
  if (cooldownBetweenFileEvents) {
51
51
  if (added) {
52
- added = guardTooFastSecondCall(added, cooldownBetweenFileEvents)
52
+ added = guardTooFastSecondCallPerFile(added, cooldownBetweenFileEvents)
53
53
  }
54
54
  if (updated) {
55
- updated = guardTooFastSecondCall(updated, cooldownBetweenFileEvents)
55
+ updated = guardTooFastSecondCallPerFile(
56
+ updated,
57
+ cooldownBetweenFileEvents,
58
+ )
56
59
  }
57
60
  if (removed) {
58
- removed = guardTooFastSecondCall(removed, cooldownBetweenFileEvents)
61
+ removed = guardTooFastSecondCallPerFile(
62
+ removed,
63
+ cooldownBetweenFileEvents,
64
+ )
59
65
  }
60
66
  }
61
67
 
@@ -81,7 +87,7 @@ export const registerDirectoryLifecycle = (
81
87
  const { watch } = URL_META.applyAssociations({ url, associations })
82
88
  return watch
83
89
  }
84
- const tracker = trackRessources()
90
+ const tracker = trackResources()
85
91
  const infoMap = new Map()
86
92
  const readEntryInfo = (url) => {
87
93
  try {
@@ -199,7 +205,7 @@ export const registerDirectoryLifecycle = (
199
205
  }
200
206
  if (entryInfo.type !== previousInfo.type) {
201
207
  // it existed and was replaced by something else
202
- // we don't handle this as an update. We rather say the ressource
208
+ // we don't handle this as an update. We rather say the resource
203
209
  // is lost and something else is found (call removed() then added())
204
210
  handleEntryLost(previousInfo)
205
211
  handleEntryFound(entryInfo)
@@ -6,7 +6,7 @@ import { assertAndNormalizeFileUrl } from "./assertAndNormalizeFileUrl.js"
6
6
  import { guardTooFastSecondCall } from "./internal/guard_second_call.js"
7
7
  import { statsToType } from "./internal/statsToType.js"
8
8
  import { createWatcher } from "./internal/createWatcher.js"
9
- import { trackRessources } from "./internal/trackRessources.js"
9
+ import { trackResources } from "./internal/track_resources.js"
10
10
 
11
11
  export const registerFileLifecycle = (
12
12
  source,
@@ -45,7 +45,7 @@ export const registerFileLifecycle = (
45
45
  }
46
46
  }
47
47
 
48
- const tracker = trackRessources()
48
+ const tracker = trackResources()
49
49
 
50
50
  const handleFileFound = ({ existent }) => {
51
51
  const fileMutationStopWatching = watchFileMutation(sourceUrl, {