@jsenv/filesystem 2.0.0 → 2.3.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 (35) hide show
  1. package/README.md +29 -38
  2. package/dist/commonjs/jsenv_filesystem.cjs +174 -26
  3. package/dist/commonjs/jsenv_filesystem.cjs.map +50 -36
  4. package/main.js +2 -0
  5. package/package.json +11 -10
  6. package/src/assertAndNormalizeDirectoryUrl.js +6 -2
  7. package/src/assertDirectoryPresence.js +3 -1
  8. package/src/assertFilePresence.js +5 -1
  9. package/src/collectDirectoryMatchReport.js +19 -4
  10. package/src/collectFiles.js +13 -3
  11. package/src/copyDirectoryContent.js +81 -0
  12. package/src/copyFileSystemNode.js +27 -8
  13. package/src/ensureEmptyDirectory.js +4 -1
  14. package/src/ensureParentDirectories.js +4 -1
  15. package/src/ensureWindowsDriveLetter.js +6 -2
  16. package/src/internal/getCommonPathname.js +4 -1
  17. package/src/internal/replaceBackSlashesWithSlashes.js +2 -1
  18. package/src/isFileSystemPath.js +3 -1
  19. package/src/listFilesMatching.js +34 -0
  20. package/src/moveDirectoryContent.js +15 -4
  21. package/src/moveFileSystemNode.js +11 -3
  22. package/src/readDirectory.js +8 -2
  23. package/src/readFileSystemNodeStat.js +8 -2
  24. package/src/registerDirectoryLifecycle.js +52 -27
  25. package/src/registerFileLifecycle.js +32 -10
  26. package/src/removeFileSystemNode.js +18 -7
  27. package/src/testFileSystemNodePermissions.js +6 -1
  28. package/src/urlToBasename.js +2 -1
  29. package/src/urlToFilename.js +3 -1
  30. package/src/urlToParentUrl.js +4 -1
  31. package/src/urlToPathname.js +3 -1
  32. package/src/urlToRelativeUrl.js +6 -2
  33. package/src/writeFileSystemNodeModificationTime.js +2 -1
  34. package/src/writeFileSystemNodePermissions.js +5 -1
  35. package/src/writeSymbolicLink.js +82 -26
package/main.js CHANGED
@@ -22,9 +22,11 @@ export { ensureEmptyDirectory } from "./src/ensureEmptyDirectory.js"
22
22
  export { ensureParentDirectories } from "./src/ensureParentDirectories.js"
23
23
  export { ensureWindowsDriveLetter } from "./src/ensureWindowsDriveLetter.js"
24
24
  export { copyFileSystemNode } from "./src/copyFileSystemNode.js"
25
+ export { copyDirectoryContent } from "./src/copyDirectoryContent.js"
25
26
  export { fileSystemPathToUrl } from "./src/fileSystemPathToUrl.js"
26
27
  export { grantPermissionsOnFileSystemNode } from "./src/grantPermissionsOnFileSystemNode.js"
27
28
  export { isFileSystemPath } from "./src/isFileSystemPath.js"
29
+ export { listFilesMatching } from "./src/listFilesMatching.js"
28
30
  export { memoize } from "./src/memoize.js"
29
31
  export { moveDirectoryContent } from "./src/moveDirectoryContent.js"
30
32
  export { moveFileSystemNode } from "./src/moveFileSystemNode.js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/filesystem",
3
- "version": "2.0.0",
3
+ "version": "2.3.0",
4
4
  "description": "Collection of functions to interact with filesystem in Node.js",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -16,8 +16,7 @@
16
16
  "node": ">=14.17.0"
17
17
  },
18
18
  "publishConfig": {
19
- "access": "public",
20
- "registry": "https://registry.npmjs.org"
19
+ "access": "public"
21
20
  },
22
21
  "type": "module",
23
22
  "exports": {
@@ -48,21 +47,23 @@
48
47
  },
49
48
  "dependencies": {
50
49
  "@jsenv/cancellation": "3.0.0",
51
- "@jsenv/url-meta": "6.0.0"
50
+ "@jsenv/url-meta": "6.0.1"
52
51
  },
53
52
  "devDependencies": {
53
+ "@babel/core": "7.15.5",
54
+ "@babel/eslint-parser": "7.15.7",
54
55
  "@jsenv/assert": "2.2.7",
55
56
  "@jsenv/codecov-upload": "3.5.0",
56
- "@jsenv/core": "19.6.2",
57
- "@jsenv/eslint-config": "15.0.2",
57
+ "@jsenv/core": "20.3.0",
58
+ "@jsenv/eslint-config": "16.0.3",
58
59
  "@jsenv/github-release-package": "1.2.3",
59
- "@jsenv/importmap-eslint-resolver": "5.1.0",
60
- "@jsenv/importmap-node-module": "1.0.1",
60
+ "@jsenv/importmap-eslint-resolver": "5.1.2",
61
+ "@jsenv/importmap-node-module": "2.2.1",
61
62
  "@jsenv/package-publish": "1.6.2",
62
63
  "@jsenv/performance-impact": "1.7.0",
63
64
  "@jsenv/prettier-check-project": "5.6.1",
64
65
  "eslint": "7.32.0",
65
- "eslint-plugin-import": "2.24.0",
66
- "prettier": "2.3.2"
66
+ "eslint-plugin-import": "2.24.2",
67
+ "prettier": "2.4.1"
67
68
  }
68
69
  }
@@ -14,11 +14,15 @@ export const assertAndNormalizeDirectoryUrl = (value) => {
14
14
  try {
15
15
  urlString = String(new URL(value))
16
16
  } catch (e) {
17
- throw new TypeError(`directoryUrl must be a valid url, received ${value}`)
17
+ throw new TypeError(
18
+ `directoryUrl must be a valid url, received ${value}`,
19
+ )
18
20
  }
19
21
  }
20
22
  } else {
21
- throw new TypeError(`directoryUrl must be a string or an url, received ${value}`)
23
+ throw new TypeError(
24
+ `directoryUrl must be a string or an url, received ${value}`,
25
+ )
22
26
  }
23
27
 
24
28
  if (!urlString.startsWith("file://")) {
@@ -15,7 +15,9 @@ export const assertDirectoryPresence = async (source) => {
15
15
  }
16
16
  if (!sourceStats.isDirectory()) {
17
17
  throw new Error(
18
- `directory expected at ${sourcePath} and found ${statsToType(sourceStats)} instead`,
18
+ `directory expected at ${sourcePath} and found ${statsToType(
19
+ sourceStats,
20
+ )} instead`,
19
21
  )
20
22
  }
21
23
  }
@@ -14,6 +14,10 @@ export const assertFilePresence = async (source) => {
14
14
  throw new Error(`file not found at ${sourcePath}`)
15
15
  }
16
16
  if (!sourceStats.isFile()) {
17
- throw new Error(`file expected at ${sourcePath} and found ${statsToType(sourceStats)} instead`)
17
+ throw new Error(
18
+ `file expected at ${sourcePath} and found ${statsToType(
19
+ sourceStats,
20
+ )} instead`,
21
+ )
18
22
  }
19
23
  }
@@ -1,5 +1,9 @@
1
1
  import { createCancellationToken, createOperation } from "@jsenv/cancellation"
2
- import { normalizeStructuredMetaMap, urlCanContainsMetaMatching, urlToMeta } from "@jsenv/url-meta"
2
+ import {
3
+ normalizeStructuredMetaMap,
4
+ urlCanContainsMetaMatching,
5
+ urlToMeta,
6
+ } from "@jsenv/url-meta"
3
7
 
4
8
  import { ensureUrlTrailingSlash } from "./internal/ensureUrlTrailingSlash.js"
5
9
  import { assertAndNormalizeDirectoryUrl } from "./assertAndNormalizeDirectoryUrl.js"
@@ -35,7 +39,10 @@ export const collectDirectoryMatchReport = async ({
35
39
  await Promise.all(
36
40
  directoryItems.map(async (directoryItem) => {
37
41
  const directoryChildNodeUrl = `${directoryUrl}${directoryItem}`
38
- const relativeUrl = urlToRelativeUrl(directoryChildNodeUrl, rootDirectoryUrl)
42
+ const relativeUrl = urlToRelativeUrl(
43
+ directoryChildNodeUrl,
44
+ rootDirectoryUrl,
45
+ )
39
46
 
40
47
  const directoryChildNodeStats = await createOperation({
41
48
  cancellationToken,
@@ -79,11 +86,19 @@ export const collectDirectoryMatchReport = async ({
79
86
  structuredMetaMap: structuredMetaMapNormalized,
80
87
  })
81
88
  if (!predicate(meta)) {
82
- ignoredArray.push({ relativeUrl, meta, fileStats: directoryChildNodeStats })
89
+ ignoredArray.push({
90
+ relativeUrl,
91
+ meta,
92
+ fileStats: directoryChildNodeStats,
93
+ })
83
94
  return
84
95
  }
85
96
 
86
- matchingArray.push({ relativeUrl, meta, fileStats: directoryChildNodeStats })
97
+ matchingArray.push({
98
+ relativeUrl,
99
+ meta,
100
+ fileStats: directoryChildNodeStats,
101
+ })
87
102
  return
88
103
  }
89
104
  }),
@@ -1,5 +1,9 @@
1
1
  import { createCancellationToken, createOperation } from "@jsenv/cancellation"
2
- import { normalizeStructuredMetaMap, urlCanContainsMetaMatching, urlToMeta } from "@jsenv/url-meta"
2
+ import {
3
+ normalizeStructuredMetaMap,
4
+ urlCanContainsMetaMatching,
5
+ urlToMeta,
6
+ } from "@jsenv/url-meta"
3
7
 
4
8
  import { assertAndNormalizeDirectoryUrl } from "./assertAndNormalizeDirectoryUrl.js"
5
9
  import { readDirectory } from "./readDirectory.js"
@@ -19,7 +23,9 @@ export const collectFiles = async ({
19
23
  throw new TypeError(`predicate must be a function, got ${predicate}`)
20
24
  }
21
25
  if (typeof matchingFileOperation !== "function") {
22
- throw new TypeError(`matchingFileOperation must be a function, got ${matchingFileOperation}`)
26
+ throw new TypeError(
27
+ `matchingFileOperation must be a function, got ${matchingFileOperation}`,
28
+ )
23
29
  }
24
30
  const structuredMetaMapNormalized = normalizeStructuredMetaMap(
25
31
  structuredMetaMap,
@@ -75,7 +81,10 @@ export const collectFiles = async ({
75
81
  })
76
82
  if (!predicate(meta)) return
77
83
 
78
- const relativeUrl = urlToRelativeUrl(directoryChildNodeUrl, rootDirectoryUrl)
84
+ const relativeUrl = urlToRelativeUrl(
85
+ directoryChildNodeUrl,
86
+ rootDirectoryUrl,
87
+ )
79
88
  const operationResult = await createOperation({
80
89
  cancellationToken,
81
90
  start: () =>
@@ -87,6 +96,7 @@ export const collectFiles = async ({
87
96
  }),
88
97
  })
89
98
  matchingFileResultArray.push({
99
+ url: new URL(relativeUrl, directoryUrl).href,
90
100
  relativeUrl,
91
101
  meta,
92
102
  fileStats: directoryChildNodeStats,
@@ -0,0 +1,81 @@
1
+ import { assertAndNormalizeDirectoryUrl } from "./assertAndNormalizeDirectoryUrl.js"
2
+ import { readFileSystemNodeStat } from "./readFileSystemNodeStat.js"
3
+ import { urlToFileSystemPath } from "./urlToFileSystemPath.js"
4
+ import { readSymbolicLink } from "./readSymbolicLink.js"
5
+ import { resolveUrl } from "./resolveUrl.js"
6
+ import { readDirectory } from "./readDirectory.js"
7
+ import { copyFileSystemNode } from "./copyFileSystemNode.js"
8
+
9
+ import { urlTargetsSameFileSystemPath } from "./internal/urlTargetsSameFileSystemPath.js"
10
+ import { statsToType } from "./internal/statsToType.js"
11
+
12
+ export const copyDirectoryContent = async ({
13
+ from,
14
+ to,
15
+ overwrite,
16
+ followLink = true,
17
+ } = {}) => {
18
+ const fromUrl = assertAndNormalizeDirectoryUrl(from)
19
+ const fromPath = urlToFileSystemPath(fromUrl)
20
+ let toUrl = assertAndNormalizeDirectoryUrl(to)
21
+ let toPath = urlToFileSystemPath(toUrl)
22
+
23
+ const sourceStats = await readFileSystemNodeStat(fromUrl, {
24
+ nullIfNotFound: true,
25
+ followLink: false,
26
+ })
27
+ if (!sourceStats) {
28
+ throw new Error(`no directory to copy content from at ${fromPath}`)
29
+ }
30
+ if (!sourceStats.isDirectory()) {
31
+ const sourceType = statsToType(sourceStats)
32
+ throw new Error(
33
+ `found a ${sourceType} instead of a directory at ${fromPath}`,
34
+ )
35
+ }
36
+
37
+ let destinationStats = await readFileSystemNodeStat(toUrl, {
38
+ nullIfNotFound: true,
39
+ // we force false here but in fact we will follow the destination link
40
+ // to know where we will actually move and detect useless move overrite etc..
41
+ followLink: false,
42
+ })
43
+ if (followLink && destinationStats && destinationStats.isSymbolicLink()) {
44
+ const linkTarget = await readSymbolicLink(toUrl)
45
+ toUrl = resolveUrl(linkTarget, toUrl)
46
+ toPath = urlToFileSystemPath(toUrl)
47
+ destinationStats = await readFileSystemNodeStat(toUrl, {
48
+ nullIfNotFound: true,
49
+ })
50
+ }
51
+
52
+ if (destinationStats === null) {
53
+ throw new Error(`no directory to copy content into at ${toPath}`)
54
+ }
55
+ if (!destinationStats.isDirectory()) {
56
+ const destinationType = statsToType(destinationStats)
57
+ throw new Error(
58
+ `destination leads to a ${destinationType} instead of a directory at ${toPath}`,
59
+ )
60
+ }
61
+
62
+ if (urlTargetsSameFileSystemPath(fromUrl, toUrl)) {
63
+ throw new Error(
64
+ `cannot copy directory content, source and destination are the same (${fromPath})`,
65
+ )
66
+ }
67
+
68
+ const directoryEntries = await readDirectory(fromUrl)
69
+ await Promise.all(
70
+ directoryEntries.map(async (directoryEntry) => {
71
+ const from = resolveUrl(directoryEntry, fromUrl)
72
+ const to = resolveUrl(directoryEntry, toUrl)
73
+ await copyFileSystemNode({
74
+ from,
75
+ to,
76
+ overwrite,
77
+ followLink,
78
+ })
79
+ }),
80
+ )
81
+ }
@@ -54,14 +54,18 @@ export const copyFileSystemNode = async ({
54
54
  const linkTarget = await readSymbolicLink(toUrl)
55
55
  toUrl = resolveUrl(linkTarget, toUrl)
56
56
  toPath = urlToFileSystemPath(toUrl)
57
- destinationStats = await readFileSystemNodeStat(toUrl, { nullIfNotFound: true })
57
+ destinationStats = await readFileSystemNodeStat(toUrl, {
58
+ nullIfNotFound: true,
59
+ })
58
60
  }
59
61
 
60
62
  if (urlTargetsSameFileSystemPath(fromUrl, toUrl)) {
61
63
  if (allowUseless) {
62
64
  return
63
65
  }
64
- throw new Error(`cannot copy ${fromPath} because destination and source are the same`)
66
+ throw new Error(
67
+ `cannot copy ${fromPath} because destination and source are the same`,
68
+ )
65
69
  }
66
70
 
67
71
  if (destinationStats) {
@@ -103,16 +107,23 @@ export const copyFileSystemNode = async ({
103
107
  const fileRelativeUrl = urlToRelativeUrl(fileUrl, fromUrl)
104
108
  const fileCopyUrl = resolveUrl(fileRelativeUrl, toUrl)
105
109
 
106
- await copyFileContentNaive(urlToFileSystemPath(fileUrl), urlToFileSystemPath(fileCopyUrl))
110
+ await copyFileContentNaive(
111
+ urlToFileSystemPath(fileUrl),
112
+ urlToFileSystemPath(fileCopyUrl),
113
+ )
107
114
  await copyStats(fileCopyUrl, fileStats)
108
115
  }
109
116
 
110
117
  const visitSymbolicLink = async (symbolicLinkUrl) => {
111
118
  const symbolicLinkRelativeUrl = urlToRelativeUrl(symbolicLinkUrl, fromUrl)
112
119
  const symbolicLinkTarget = await readSymbolicLink(symbolicLinkUrl)
113
- const symbolicLinkTargetUrl = resolveUrl(symbolicLinkTarget, symbolicLinkUrl)
120
+ const symbolicLinkTargetUrl = resolveUrl(
121
+ symbolicLinkTarget,
122
+ symbolicLinkUrl,
123
+ )
114
124
  const linkIsRelative =
115
- symbolicLinkTarget.startsWith("./") || symbolicLinkTarget.startsWith("../")
125
+ symbolicLinkTarget.startsWith("./") ||
126
+ symbolicLinkTarget.startsWith("../")
116
127
 
117
128
  let symbolicLinkCopyTarget
118
129
  if (symbolicLinkTargetUrl === fromUrl) {
@@ -120,7 +131,10 @@ export const copyFileSystemNode = async ({
120
131
  } else if (urlIsInsideOf(symbolicLinkTargetUrl, fromUrl)) {
121
132
  // symbolic link targets something inside the directory we want to copy
122
133
  // reflects it inside the copied directory structure
123
- const linkCopyTargetRelative = urlToRelativeUrl(symbolicLinkTargetUrl, fromUrl)
134
+ const linkCopyTargetRelative = urlToRelativeUrl(
135
+ symbolicLinkTargetUrl,
136
+ fromUrl,
137
+ )
124
138
  symbolicLinkCopyTarget = linkIsRelative
125
139
  ? `./${linkCopyTargetRelative}`
126
140
  : resolveUrl(linkCopyTargetRelative, toUrl)
@@ -150,7 +164,10 @@ export const copyFileSystemNode = async ({
150
164
  if (preservePermissions || preserveMtime) {
151
165
  const { mode, mtimeMs } = stats
152
166
  if (preservePermissions) {
153
- await writeFileSystemNodePermissions(toUrl, binaryFlagsToPermissions(mode))
167
+ await writeFileSystemNodePermissions(
168
+ toUrl,
169
+ binaryFlagsToPermissions(mode),
170
+ )
154
171
  }
155
172
  if (preserveMtime) {
156
173
  await writeFileSystemNodeModificationTime(toUrl, mtimeMs)
@@ -172,7 +189,9 @@ export const copyFileSystemNode = async ({
172
189
  await Promise.all(
173
190
  names.map(async (name) => {
174
191
  const fileSystemNodeUrl = resolveUrl(name, directoryUrl)
175
- const stats = await readFileSystemNodeStat(fileSystemNodeUrl, { followLink: false })
192
+ const stats = await readFileSystemNodeStat(fileSystemNodeUrl, {
193
+ followLink: false,
194
+ })
176
195
  await visit(fileSystemNodeUrl, stats)
177
196
  }),
178
197
  )
@@ -6,7 +6,10 @@ import { readFileSystemNodeStat } from "./readFileSystemNodeStat.js"
6
6
  import { removeFileSystemNode } from "./removeFileSystemNode.js"
7
7
 
8
8
  export const ensureEmptyDirectory = async (source) => {
9
- const stats = await readFileSystemNodeStat(source, { nullIfNotFound: true, followLink: false })
9
+ const stats = await readFileSystemNodeStat(source, {
10
+ nullIfNotFound: true,
11
+ followLink: false,
12
+ })
10
13
  if (stats === null) {
11
14
  // if there is nothing, create a directory
12
15
  return writeDirectory(source, { allowUseless: true })
@@ -8,5 +8,8 @@ export const ensureParentDirectories = async (destination) => {
8
8
  const destinationPath = urlToFileSystemPath(destinationUrl)
9
9
  const destinationParentPath = dirname(destinationPath)
10
10
 
11
- return writeDirectory(destinationParentPath, { recursive: true, allowUseless: true })
11
+ return writeDirectory(destinationParentPath, {
12
+ recursive: true,
13
+ allowUseless: true,
14
+ })
12
15
  }
@@ -45,8 +45,12 @@ export const ensureWindowsDriveLetter = (url, baseUrl) => {
45
45
  }
46
46
 
47
47
  // drive letter was lost, restore it
48
- const baseUrlOrFallback = baseUrl.startsWith("file://") ? baseUrl : baseUrlFallback
49
- const driveLetter = extractDriveLetter(baseUrlOrFallback.slice("file://".length))
48
+ const baseUrlOrFallback = baseUrl.startsWith("file://")
49
+ ? baseUrl
50
+ : baseUrlFallback
51
+ const driveLetter = extractDriveLetter(
52
+ baseUrlOrFallback.slice("file://".length),
53
+ )
50
54
  if (!driveLetter) {
51
55
  throw new Error(
52
56
  `drive letter expected on baseUrl but got ${baseUrl} to ensure windows drive letter on ${url}`,
@@ -1,5 +1,8 @@
1
1
  export const getCommonPathname = (pathname, otherPathname) => {
2
- const firstDifferentCharacterIndex = findFirstDifferentCharacterIndex(pathname, otherPathname)
2
+ const firstDifferentCharacterIndex = findFirstDifferentCharacterIndex(
3
+ pathname,
4
+ otherPathname,
5
+ )
3
6
 
4
7
  // pathname and otherpathname are exactly the same
5
8
  if (firstDifferentCharacterIndex === -1) {
@@ -1 +1,2 @@
1
- export const replaceBackSlashesWithSlashes = (string) => string.replace(/\\/g, "/")
1
+ export const replaceBackSlashesWithSlashes = (string) =>
2
+ string.replace(/\\/g, "/")
@@ -1,6 +1,8 @@
1
1
  export const isFileSystemPath = (value) => {
2
2
  if (typeof value !== "string") {
3
- throw new TypeError(`isFileSystemPath first arg must be a string, got ${value}`)
3
+ throw new TypeError(
4
+ `isFileSystemPath first arg must be a string, got ${value}`,
5
+ )
4
6
  }
5
7
 
6
8
  if (value[0] === "/") {
@@ -0,0 +1,34 @@
1
+ import { collectFiles } from "./collectFiles.js"
2
+
3
+ export const listFilesMatching = async (
4
+ patterns,
5
+ directoryUrl = process.cwd(),
6
+ ) => {
7
+ if (typeof patterns === "string") {
8
+ patterns = [patterns]
9
+ } else if (Array.isArray(patterns)) {
10
+ throw new TypeError(
11
+ `patterns must be a string or an array of strings, got ${patterns}`,
12
+ )
13
+ }
14
+
15
+ const patternMap = {}
16
+ patterns.forEach((pattern, index) => {
17
+ if (typeof pattern !== "string") {
18
+ throw new TypeError(
19
+ `every pattern must be a string, found ${pattern} at index ${index}`,
20
+ )
21
+ }
22
+ patternMap[pattern] = true
23
+ })
24
+
25
+ const fileDatas = await collectFiles({
26
+ directoryUrl,
27
+ structuredMetaMap: {
28
+ matches: patternMap,
29
+ },
30
+ predicate: ({ matches }) => matches,
31
+ })
32
+
33
+ return fileDatas.map(({ url }) => url)
34
+ }
@@ -9,7 +9,12 @@ import { moveFileSystemNode } from "./moveFileSystemNode.js"
9
9
  import { urlTargetsSameFileSystemPath } from "./internal/urlTargetsSameFileSystemPath.js"
10
10
  import { statsToType } from "./internal/statsToType.js"
11
11
 
12
- export const moveDirectoryContent = async ({ from, to, overwrite, followLink = true } = {}) => {
12
+ export const moveDirectoryContent = async ({
13
+ from,
14
+ to,
15
+ overwrite,
16
+ followLink = true,
17
+ } = {}) => {
13
18
  const fromUrl = assertAndNormalizeDirectoryUrl(from)
14
19
  const fromPath = urlToFileSystemPath(fromUrl)
15
20
  let toUrl = assertAndNormalizeDirectoryUrl(to)
@@ -24,7 +29,9 @@ export const moveDirectoryContent = async ({ from, to, overwrite, followLink = t
24
29
  }
25
30
  if (!sourceStats.isDirectory()) {
26
31
  const sourceType = statsToType(sourceStats)
27
- throw new Error(`found a ${sourceType} instead of a directory at ${fromPath}`)
32
+ throw new Error(
33
+ `found a ${sourceType} instead of a directory at ${fromPath}`,
34
+ )
28
35
  }
29
36
 
30
37
  let destinationStats = await readFileSystemNodeStat(toUrl, {
@@ -37,7 +44,9 @@ export const moveDirectoryContent = async ({ from, to, overwrite, followLink = t
37
44
  const linkTarget = await readSymbolicLink(toUrl)
38
45
  toUrl = resolveUrl(linkTarget, toUrl)
39
46
  toPath = urlToFileSystemPath(toUrl)
40
- destinationStats = await readFileSystemNodeStat(toUrl, { nullIfNotFound: true })
47
+ destinationStats = await readFileSystemNodeStat(toUrl, {
48
+ nullIfNotFound: true,
49
+ })
41
50
  }
42
51
 
43
52
  if (destinationStats === null) {
@@ -45,7 +54,9 @@ export const moveDirectoryContent = async ({ from, to, overwrite, followLink = t
45
54
  }
46
55
  if (!destinationStats.isDirectory()) {
47
56
  const destinationType = statsToType(destinationStats)
48
- throw new Error(`destination leads to a ${destinationType} instead of a directory at ${toPath}`)
57
+ throw new Error(
58
+ `destination leads to a ${destinationType} instead of a directory at ${toPath}`,
59
+ )
49
60
  }
50
61
 
51
62
  if (urlTargetsSameFileSystemPath(fromUrl, toUrl)) {
@@ -43,14 +43,18 @@ export const moveFileSystemNode = async ({
43
43
  const linkTarget = await readSymbolicLink(toUrl)
44
44
  toUrl = resolveUrl(linkTarget, toUrl)
45
45
  toPath = urlToFileSystemPath(toUrl)
46
- destinationStats = await readFileSystemNodeStat(toUrl, { nullIfNotFound: true })
46
+ destinationStats = await readFileSystemNodeStat(toUrl, {
47
+ nullIfNotFound: true,
48
+ })
47
49
  }
48
50
 
49
51
  if (urlTargetsSameFileSystemPath(fromUrl, toUrl)) {
50
52
  if (allowUseless) {
51
53
  return
52
54
  }
53
- throw new Error(`no move needed for ${fromPath} because destination and source are the same`)
55
+ throw new Error(
56
+ `no move needed for ${fromPath} because destination and source are the same`,
57
+ )
54
58
  }
55
59
 
56
60
  if (destinationStats) {
@@ -86,7 +90,11 @@ export const moveFileSystemNode = async ({
86
90
  })
87
91
  }
88
92
 
89
- const moveNaive = (fromPath, destinationPath, { handleCrossDeviceError = null } = {}) => {
93
+ const moveNaive = (
94
+ fromPath,
95
+ destinationPath,
96
+ { handleCrossDeviceError = null } = {},
97
+ ) => {
90
98
  return new Promise((resolve, reject) => {
91
99
  rename(fromPath, destinationPath, (error) => {
92
100
  if (error) {
@@ -30,12 +30,18 @@ export const readDirectory = async (url, { emfileMaxWait = 1000 } = {}) => {
30
30
  return attempt()
31
31
  }
32
32
 
33
- const readdirNaive = (directoryPath, { handleTooManyFilesOpenedError = null } = {}) => {
33
+ const readdirNaive = (
34
+ directoryPath,
35
+ { handleTooManyFilesOpenedError = null } = {},
36
+ ) => {
34
37
  return new Promise((resolve, reject) => {
35
38
  readdir(directoryPath, (error, names) => {
36
39
  if (error) {
37
40
  // https://nodejs.org/dist/latest-v13.x/docs/api/errors.html#errors_common_system_errors
38
- if (handleTooManyFilesOpenedError && (error.code === "EMFILE" || error.code === "ENFILE")) {
41
+ if (
42
+ handleTooManyFilesOpenedError &&
43
+ (error.code === "EMFILE" || error.code === "ENFILE")
44
+ ) {
39
45
  resolve(handleTooManyFilesOpenedError(error))
40
46
  } else {
41
47
  reject(error)
@@ -33,7 +33,9 @@ export const readFileSystemNodeStat = async (
33
33
  ? {
34
34
  // Windows can EPERM on stat
35
35
  handlePermissionDeniedError: async (error) => {
36
- console.error(`trying to fix windows EPERM after stats on ${sourcePath}`)
36
+ console.error(
37
+ `trying to fix windows EPERM after stats on ${sourcePath}`,
38
+ )
37
39
 
38
40
  try {
39
41
  // unfortunately it means we mutate the permissions
@@ -64,7 +66,11 @@ export const readFileSystemNodeStat = async (
64
66
 
65
67
  const readStat = (
66
68
  sourcePath,
67
- { followLink, handleNotFoundError = null, handlePermissionDeniedError = null } = {},
69
+ {
70
+ followLink,
71
+ handleNotFoundError = null,
72
+ handlePermissionDeniedError = null,
73
+ } = {},
68
74
  ) => {
69
75
  const nodeMethod = followLink ? stat : lstat
70
76