@jsenv/filesystem 2.7.0 → 3.0.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/main.js +13 -12
  2. package/package.json +1 -1
  3. package/src/assertDirectoryPresence.js +2 -2
  4. package/src/assertFilePresence.js +2 -2
  5. package/src/collectDirectoryMatchReport.js +2 -2
  6. package/src/collectFiles.js +2 -2
  7. package/src/copyDirectoryContent.js +6 -6
  8. package/src/{copyFileSystemNode.js → copyEntry.js} +15 -18
  9. package/src/ensureEmptyDirectory.js +4 -4
  10. package/src/ensureParentDirectories.js +2 -1
  11. package/src/fileSystemRootUrl.js +2 -0
  12. package/src/getRealFileSystemUrlSync.js +17 -6
  13. package/src/grantPermissionsOnEntry.js +20 -0
  14. package/src/internal/{fileSystemNodeToTypeOrNull.js → entryToTypeOrNull.js} +1 -1
  15. package/src/internal/getCommonPathname.js +0 -1
  16. package/src/moveDirectoryContent.js +6 -6
  17. package/src/{moveFileSystemNode.js → moveEntry.js} +10 -10
  18. package/src/moveUrl.js +10 -0
  19. package/src/readEntryModificationTime.js +6 -0
  20. package/src/{readFileSystemNodePermissions.js → readEntryPermissions.js} +1 -1
  21. package/src/{readFileSystemNodeStat.js → readEntryStat.js} +3 -3
  22. package/src/registerDirectoryLifecycle.js +4 -4
  23. package/src/registerFileLifecycle.js +4 -4
  24. package/src/{removeFileSystemNode.js → removeEntry.js} +4 -4
  25. package/src/{testFileSystemNodePermissions.js → testEntryPermissions.js} +3 -2
  26. package/src/urlToPathname.js +8 -3
  27. package/src/urlToRelativeUrl.js +0 -1
  28. package/src/writeDirectory.js +4 -3
  29. package/src/{writeFileSystemNodeModificationTime.js → writeEntryModificationTime.js} +3 -2
  30. package/src/{writeFileSystemNodePermissions.js → writeEntryPermissions.js} +3 -2
  31. package/src/writeFile.js +2 -1
  32. package/src/writeFileSync.js +20 -0
  33. package/src/writeSymbolicLink.js +4 -4
  34. package/src/grantPermissionsOnFileSystemNode.js +0 -20
  35. package/src/readFileSystemNodeModificationTime.js +0 -6
package/main.js CHANGED
@@ -1,5 +1,3 @@
1
- /* eslint-disable import/max-dependencies */
2
-
3
1
  // we won't internalize @jsenv/url-meta
4
2
  // so that @jsenv/url-meta does not becomes nodejs specific
5
3
  // but these functions could be inside this repository
@@ -21,28 +19,30 @@ export { comparePathnames } from "./src/comparePathnames.js"
21
19
  export { ensureEmptyDirectory } from "./src/ensureEmptyDirectory.js"
22
20
  export { ensureParentDirectories } from "./src/ensureParentDirectories.js"
23
21
  export { ensureWindowsDriveLetter } from "./src/ensureWindowsDriveLetter.js"
24
- export { copyFileSystemNode } from "./src/copyFileSystemNode.js"
22
+ export { copyEntry } from "./src/copyEntry.js"
25
23
  export { copyDirectoryContent } from "./src/copyDirectoryContent.js"
26
24
  export { fileSystemPathToUrl } from "./src/fileSystemPathToUrl.js"
25
+ export { fileSystemRootUrl } from "./src/fileSystemRootUrl.js"
27
26
  export { getRealFileSystemUrlSync } from "./src/getRealFileSystemUrlSync.js"
28
- export { grantPermissionsOnFileSystemNode } from "./src/grantPermissionsOnFileSystemNode.js"
27
+ export { grantPermissionsOnEntry } from "./src/grantPermissionsOnEntry.js"
29
28
  export { isFileSystemPath } from "./src/isFileSystemPath.js"
30
29
  export { listFilesMatching } from "./src/listFilesMatching.js"
31
30
  export { memoize } from "./src/memoize.js"
32
31
  export { moveDirectoryContent } from "./src/moveDirectoryContent.js"
33
- export { moveFileSystemNode } from "./src/moveFileSystemNode.js"
32
+ export { moveEntry } from "./src/moveEntry.js"
33
+ export { moveUrl } from "./src/moveUrl.js"
34
34
  export { readDirectory } from "./src/readDirectory.js"
35
35
  export { readFile } from "./src/readFile.js"
36
- export { readFileSystemNodeModificationTime } from "./src/readFileSystemNodeModificationTime.js"
37
- export { readFileSystemNodePermissions } from "./src/readFileSystemNodePermissions.js"
38
- export { readFileSystemNodeStat } from "./src/readFileSystemNodeStat.js"
36
+ export { readEntryModificationTime } from "./src/readEntryModificationTime.js"
37
+ export { readEntryPermissions } from "./src/readEntryPermissions.js"
38
+ export { readEntryStat } from "./src/readEntryStat.js"
39
39
  export { readSymbolicLink } from "./src/readSymbolicLink.js"
40
40
  export { registerDirectoryLifecycle } from "./src/registerDirectoryLifecycle.js"
41
41
  export { registerFileLifecycle } from "./src/registerFileLifecycle.js"
42
- export { removeFileSystemNode } from "./src/removeFileSystemNode.js"
42
+ export { removeEntry } from "./src/removeEntry.js"
43
43
  export { resolveDirectoryUrl } from "./src/resolveDirectoryUrl.js"
44
44
  export { resolveUrl } from "./src/resolveUrl.js"
45
- export { testFileSystemNodePermissions } from "./src/testFileSystemNodePermissions.js"
45
+ export { testEntryPermissions } from "./src/testEntryPermissions.js"
46
46
  export { urlIsInsideOf } from "./src/urlIsInsideOf.js"
47
47
  export { urlToBasename } from "./src/urlToBasename.js"
48
48
  export { urlToExtension } from "./src/urlToExtension.js"
@@ -56,6 +56,7 @@ export { urlToRessource } from "./src/urlToRessource.js"
56
56
  export { urlToScheme } from "./src/urlToScheme.js"
57
57
  export { writeDirectory } from "./src/writeDirectory.js"
58
58
  export { writeFile } from "./src/writeFile.js"
59
- export { writeFileSystemNodeModificationTime } from "./src/writeFileSystemNodeModificationTime.js"
60
- export { writeFileSystemNodePermissions } from "./src/writeFileSystemNodePermissions.js"
59
+ export { writeFileSync } from "./src/writeFileSync.js"
60
+ export { writeEntryModificationTime } from "./src/writeEntryModificationTime.js"
61
+ export { writeEntryPermissions } from "./src/writeEntryPermissions.js"
61
62
  export { writeSymbolicLink } from "./src/writeSymbolicLink.js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/filesystem",
3
- "version": "2.7.0",
3
+ "version": "3.0.0",
4
4
  "description": "Collection of functions to interact with filesystem in Node.js",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -1,13 +1,13 @@
1
1
  import { statsToType } from "./internal/statsToType.js"
2
2
  import { assertAndNormalizeFileUrl } from "./assertAndNormalizeFileUrl.js"
3
3
  import { urlToFileSystemPath } from "./urlToFileSystemPath.js"
4
- import { readFileSystemNodeStat } from "./readFileSystemNodeStat.js"
4
+ import { readEntryStat } from "./readEntryStat.js"
5
5
 
6
6
  export const assertDirectoryPresence = async (source) => {
7
7
  const sourceUrl = assertAndNormalizeFileUrl(source)
8
8
  const sourcePath = urlToFileSystemPath(sourceUrl)
9
9
 
10
- const sourceStats = await readFileSystemNodeStat(sourceUrl, {
10
+ const sourceStats = await readEntryStat(sourceUrl, {
11
11
  nullIfNotFound: true,
12
12
  })
13
13
  if (!sourceStats) {
@@ -1,13 +1,13 @@
1
1
  import { statsToType } from "./internal/statsToType.js"
2
2
  import { assertAndNormalizeFileUrl } from "./assertAndNormalizeFileUrl.js"
3
3
  import { urlToFileSystemPath } from "./urlToFileSystemPath.js"
4
- import { readFileSystemNodeStat } from "./readFileSystemNodeStat.js"
4
+ import { readEntryStat } from "./readEntryStat.js"
5
5
 
6
6
  export const assertFilePresence = async (source) => {
7
7
  const sourceUrl = assertAndNormalizeFileUrl(source)
8
8
  const sourcePath = urlToFileSystemPath(sourceUrl)
9
9
 
10
- const sourceStats = await readFileSystemNodeStat(sourceUrl, {
10
+ const sourceStats = await readEntryStat(sourceUrl, {
11
11
  nullIfNotFound: true,
12
12
  })
13
13
  if (!sourceStats) {
@@ -8,7 +8,7 @@ import {
8
8
  import { ensureUrlTrailingSlash } from "./internal/ensureUrlTrailingSlash.js"
9
9
  import { assertAndNormalizeDirectoryUrl } from "./assertAndNormalizeDirectoryUrl.js"
10
10
  import { readDirectory } from "./readDirectory.js"
11
- import { readFileSystemNodeStat } from "./readFileSystemNodeStat.js"
11
+ import { readEntryStat } from "./readEntryStat.js"
12
12
  import { urlToRelativeUrl } from "./urlToRelativeUrl.js"
13
13
  import { comparePathnames } from "./comparePathnames.js"
14
14
 
@@ -46,7 +46,7 @@ export const collectDirectoryMatchReport = async ({
46
46
  )
47
47
 
48
48
  collectOperation.throwIfAborted()
49
- const directoryChildNodeStats = await readFileSystemNodeStat(
49
+ const directoryChildNodeStats = await readEntryStat(
50
50
  directoryChildNodeUrl,
51
51
  {
52
52
  // we ignore symlink because recursively traversed
@@ -7,7 +7,7 @@ import {
7
7
 
8
8
  import { assertAndNormalizeDirectoryUrl } from "./assertAndNormalizeDirectoryUrl.js"
9
9
  import { readDirectory } from "./readDirectory.js"
10
- import { readFileSystemNodeStat } from "./readFileSystemNodeStat.js"
10
+ import { readEntryStat } from "./readEntryStat.js"
11
11
  import { urlToRelativeUrl } from "./urlToRelativeUrl.js"
12
12
  import { comparePathnames } from "./comparePathnames.js"
13
13
 
@@ -39,7 +39,7 @@ export const collectFiles = async ({
39
39
  const directoryChildNodeUrl = `${directoryUrl}${directoryItem}`
40
40
 
41
41
  collectOperation.throwIfAborted()
42
- const directoryChildNodeStats = await readFileSystemNodeStat(
42
+ const directoryChildNodeStats = await readEntryStat(
43
43
  directoryChildNodeUrl,
44
44
  {
45
45
  // we ignore symlink because recursively traversed
@@ -1,12 +1,12 @@
1
1
  import { Abort } from "@jsenv/abort"
2
2
 
3
3
  import { assertAndNormalizeDirectoryUrl } from "./assertAndNormalizeDirectoryUrl.js"
4
- import { readFileSystemNodeStat } from "./readFileSystemNodeStat.js"
4
+ import { readEntryStat } from "./readEntryStat.js"
5
5
  import { urlToFileSystemPath } from "./urlToFileSystemPath.js"
6
6
  import { readSymbolicLink } from "./readSymbolicLink.js"
7
7
  import { resolveUrl } from "./resolveUrl.js"
8
8
  import { readDirectory } from "./readDirectory.js"
9
- import { copyFileSystemNode } from "./copyFileSystemNode.js"
9
+ import { copyEntry } from "./copyEntry.js"
10
10
  import { urlTargetsSameFileSystemPath } from "./internal/urlTargetsSameFileSystemPath.js"
11
11
  import { statsToType } from "./internal/statsToType.js"
12
12
 
@@ -22,7 +22,7 @@ export const copyDirectoryContent = async ({
22
22
  let toUrl = assertAndNormalizeDirectoryUrl(to)
23
23
  let toPath = urlToFileSystemPath(toUrl)
24
24
 
25
- const sourceStats = await readFileSystemNodeStat(fromUrl, {
25
+ const sourceStats = await readEntryStat(fromUrl, {
26
26
  nullIfNotFound: true,
27
27
  followLink: false,
28
28
  })
@@ -36,7 +36,7 @@ export const copyDirectoryContent = async ({
36
36
  )
37
37
  }
38
38
 
39
- let destinationStats = await readFileSystemNodeStat(toUrl, {
39
+ let destinationStats = await readEntryStat(toUrl, {
40
40
  nullIfNotFound: true,
41
41
  // we force false here but in fact we will follow the destination link
42
42
  // to know where we will actually move and detect useless move overrite etc..
@@ -46,7 +46,7 @@ export const copyDirectoryContent = async ({
46
46
  const linkTarget = await readSymbolicLink(toUrl)
47
47
  toUrl = resolveUrl(linkTarget, toUrl)
48
48
  toPath = urlToFileSystemPath(toUrl)
49
- destinationStats = await readFileSystemNodeStat(toUrl, {
49
+ destinationStats = await readEntryStat(toUrl, {
50
50
  nullIfNotFound: true,
51
51
  })
52
52
  }
@@ -77,7 +77,7 @@ export const copyDirectoryContent = async ({
77
77
  const from = resolveUrl(directoryEntry, fromUrl)
78
78
  const to = resolveUrl(directoryEntry, toUrl)
79
79
  await copyOperation.withSignal(async (signal) => {
80
- await copyFileSystemNode({
80
+ await copyEntry({
81
81
  signal,
82
82
  from,
83
83
  to,
@@ -9,18 +9,18 @@ import { binaryFlagsToPermissions } from "./internal/permissions.js"
9
9
  import { assertAndNormalizeFileUrl } from "./assertAndNormalizeFileUrl.js"
10
10
  import { writeDirectory } from "./writeDirectory.js"
11
11
  import { urlToRelativeUrl } from "./urlToRelativeUrl.js"
12
- import { readFileSystemNodeStat } from "./readFileSystemNodeStat.js"
12
+ import { readEntryStat } from "./readEntryStat.js"
13
13
  import { ensureParentDirectories } from "./ensureParentDirectories.js"
14
- import { writeFileSystemNodePermissions } from "./writeFileSystemNodePermissions.js"
15
- import { writeFileSystemNodeModificationTime } from "./writeFileSystemNodeModificationTime.js"
14
+ import { writeEntryPermissions } from "./writeEntryPermissions.js"
15
+ import { writeEntryModificationTime } from "./writeEntryModificationTime.js"
16
16
  import { readDirectory } from "./readDirectory.js"
17
17
  import { readSymbolicLink } from "./readSymbolicLink.js"
18
18
  import { writeSymbolicLink } from "./writeSymbolicLink.js"
19
19
  import { urlIsInsideOf } from "./urlIsInsideOf.js"
20
- import { removeFileSystemNode } from "./removeFileSystemNode.js"
20
+ import { removeEntry } from "./removeEntry.js"
21
21
  import { urlToFileSystemPath } from "./urlToFileSystemPath.js"
22
22
 
23
- export const copyFileSystemNode = async ({
23
+ export const copyEntry = async ({
24
24
  signal = new AbortController().signal,
25
25
  from,
26
26
  to,
@@ -36,7 +36,7 @@ export const copyFileSystemNode = async ({
36
36
  let toUrl = assertAndNormalizeFileUrl(to)
37
37
  let toPath = urlToFileSystemPath(toUrl)
38
38
 
39
- const sourceStats = await readFileSystemNodeStat(fromUrl, {
39
+ const sourceStats = await readEntryStat(fromUrl, {
40
40
  nullIfNotFound: true,
41
41
  followLink: false,
42
42
  })
@@ -44,7 +44,7 @@ export const copyFileSystemNode = async ({
44
44
  throw new Error(`nothing to copy at ${fromPath}`)
45
45
  }
46
46
 
47
- let destinationStats = await readFileSystemNodeStat(toUrl, {
47
+ let destinationStats = await readEntryStat(toUrl, {
48
48
  nullIfNotFound: true,
49
49
  // we force false here but in fact we will follow the destination link
50
50
  // to know where we will actually move and detect useless move overrite etc..
@@ -55,7 +55,7 @@ export const copyFileSystemNode = async ({
55
55
  const linkTarget = await readSymbolicLink(toUrl)
56
56
  toUrl = resolveUrl(linkTarget, toUrl)
57
57
  toPath = urlToFileSystemPath(toUrl)
58
- destinationStats = await readFileSystemNodeStat(toUrl, {
58
+ destinationStats = await readEntryStat(toUrl, {
59
59
  nullIfNotFound: true,
60
60
  })
61
61
  }
@@ -130,7 +130,7 @@ export const copyFileSystemNode = async ({
130
130
  // we must guess ourself the type of the symlink
131
131
  // because the destination might not exists because not yet copied
132
132
  // https://nodejs.org/dist/latest-v13.x/docs/api/fs.html#fs_fs_symlink_target_path_type_callback
133
- const targetStats = await readFileSystemNodeStat(symbolicLinkTargetUrl, {
133
+ const targetStats = await readEntryStat(symbolicLinkTargetUrl, {
134
134
  nullIfNotFound: true,
135
135
  followLink: false,
136
136
  })
@@ -148,13 +148,10 @@ export const copyFileSystemNode = async ({
148
148
  if (preservePermissions || preserveMtime) {
149
149
  const { mode, mtimeMs } = stats
150
150
  if (preservePermissions) {
151
- await writeFileSystemNodePermissions(
152
- toUrl,
153
- binaryFlagsToPermissions(mode),
154
- )
151
+ await writeEntryPermissions(toUrl, binaryFlagsToPermissions(mode))
155
152
  }
156
153
  if (preserveMtime) {
157
- await writeFileSystemNodeModificationTime(toUrl, mtimeMs)
154
+ await writeEntryModificationTime(toUrl, mtimeMs)
158
155
  }
159
156
  }
160
157
  }
@@ -172,11 +169,11 @@ export const copyFileSystemNode = async ({
172
169
  const names = await readDirectory(directoryUrl)
173
170
  await Promise.all(
174
171
  names.map(async (name) => {
175
- const fileSystemNodeUrl = resolveUrl(name, directoryUrl)
176
- const stats = await readFileSystemNodeStat(fileSystemNodeUrl, {
172
+ const entryUrl = resolveUrl(name, directoryUrl)
173
+ const stats = await readEntryStat(entryUrl, {
177
174
  followLink: false,
178
175
  })
179
- await visit(fileSystemNodeUrl, stats)
176
+ await visit(entryUrl, stats)
180
177
  }),
181
178
  )
182
179
  }
@@ -198,7 +195,7 @@ export const copyFileSystemNode = async ({
198
195
  }
199
196
 
200
197
  // remove file, link, directory...
201
- await removeFileSystemNode(toUrl, {
198
+ await removeEntry(toUrl, {
202
199
  signal: copyOperation.signal,
203
200
  recursive: true,
204
201
  allowUseless: true,
@@ -2,11 +2,11 @@ import { statsToType } from "./internal/statsToType.js"
2
2
  import { assertAndNormalizeFileUrl } from "./assertAndNormalizeFileUrl.js"
3
3
  import { urlToFileSystemPath } from "./urlToFileSystemPath.js"
4
4
  import { writeDirectory } from "./writeDirectory.js"
5
- import { readFileSystemNodeStat } from "./readFileSystemNodeStat.js"
6
- import { removeFileSystemNode } from "./removeFileSystemNode.js"
5
+ import { readEntryStat } from "./readEntryStat.js"
6
+ import { removeEntry } from "./removeEntry.js"
7
7
 
8
8
  export const ensureEmptyDirectory = async (source) => {
9
- const stats = await readFileSystemNodeStat(source, {
9
+ const stats = await readEntryStat(source, {
10
10
  nullIfNotFound: true,
11
11
  followLink: false,
12
12
  })
@@ -16,7 +16,7 @@ export const ensureEmptyDirectory = async (source) => {
16
16
  }
17
17
  if (stats.isDirectory()) {
18
18
  // if there is a directory remove its content and done
19
- return removeFileSystemNode(source, {
19
+ return removeEntry(source, {
20
20
  allowUseless: true,
21
21
  recursive: true,
22
22
  onlyContent: true,
@@ -1,4 +1,5 @@
1
- import { dirname } from "path"
1
+ import { dirname } from "node:path"
2
+
2
3
  import { assertAndNormalizeFileUrl } from "./assertAndNormalizeFileUrl.js"
3
4
  import { urlToFileSystemPath } from "./urlToFileSystemPath.js"
4
5
  import { writeDirectory } from "./writeDirectory.js"
@@ -0,0 +1,2 @@
1
+ export const fileSystemRootUrl =
2
+ process.platform === "win32" ? `file///${process.cwd()[0]}:/` : "file:///"
@@ -19,12 +19,20 @@ export const getRealFileSystemUrlSync = (
19
19
  while (true) {
20
20
  const name = parts[i]
21
21
  i++
22
- const namesOnFileSystem = readdirSync(
23
- // When Node.js receives "C:/" on windows it returns
24
- // the process.cwd() directory content...
25
- // This can be fixed by passing "file:///C:/" directly but as a url object
26
- new URL(reconstructedFileUrl),
27
- )
22
+ let namesOnFileSystem
23
+ try {
24
+ namesOnFileSystem = readdirSync(
25
+ // When Node.js receives "C:/" on windows it returns
26
+ // the process.cwd() directory content...
27
+ // This can be fixed by passing "file:///C:/" directly but as a url object
28
+ new URL(reconstructedFileUrl),
29
+ )
30
+ } catch (e) {
31
+ if (e && e.code === "ENOENT") {
32
+ return null
33
+ }
34
+ throw e
35
+ }
28
36
  const foundOnFilesystem = namesOnFileSystem.includes(name)
29
37
  if (foundOnFilesystem) {
30
38
  reconstructedFileUrl += name
@@ -32,6 +40,9 @@ export const getRealFileSystemUrlSync = (
32
40
  const nameOnFileSystem = namesOnFileSystem.find(
33
41
  (nameCandidate) => nameCandidate.toLowerCase() === name.toLowerCase(),
34
42
  )
43
+ if (!nameOnFileSystem) {
44
+ return null
45
+ }
35
46
  reconstructedFileUrl += nameOnFileSystem
36
47
  }
37
48
  if (i === parts.length) {
@@ -0,0 +1,20 @@
1
+ import { assertAndNormalizeFileUrl } from "./assertAndNormalizeFileUrl.js"
2
+ import { readEntryPermissions } from "./readEntryPermissions.js"
3
+ import { writeEntryPermissions } from "./writeEntryPermissions.js"
4
+
5
+ export const grantPermissionsOnEntry = async (
6
+ source,
7
+ { read = false, write = false, execute = false },
8
+ ) => {
9
+ const sourceUrl = assertAndNormalizeFileUrl(source)
10
+
11
+ const filePermissions = await readEntryPermissions(sourceUrl)
12
+ await writeEntryPermissions(sourceUrl, {
13
+ owner: { read, write, execute },
14
+ group: { read, write, execute },
15
+ others: { read, write, execute },
16
+ })
17
+ return async () => {
18
+ await writeEntryPermissions(sourceUrl, filePermissions)
19
+ }
20
+ }
@@ -4,7 +4,7 @@ import { urlToFileSystemPath } from "../urlToFileSystemPath.js"
4
4
 
5
5
  import { statsToType } from "./statsToType.js"
6
6
 
7
- export const fileSystemNodeToTypeOrNull = (url) => {
7
+ export const entryToTypeOrNull = (url) => {
8
8
  const path = urlToFileSystemPath(url)
9
9
  try {
10
10
  const stats = statSync(path)
@@ -10,7 +10,6 @@ export const getCommonPathname = (pathname, otherPathname) => {
10
10
  }
11
11
 
12
12
  const commonString = pathname.slice(0, firstDifferentCharacterIndex + 1)
13
-
14
13
  // the first different char is at firstDifferentCharacterIndex
15
14
  if (pathname.charAt(firstDifferentCharacterIndex) === "/") {
16
15
  return commonString
@@ -1,12 +1,12 @@
1
1
  import { Abort } from "@jsenv/abort"
2
2
 
3
3
  import { assertAndNormalizeDirectoryUrl } from "./assertAndNormalizeDirectoryUrl.js"
4
- import { readFileSystemNodeStat } from "./readFileSystemNodeStat.js"
4
+ import { readEntryStat } from "./readEntryStat.js"
5
5
  import { urlToFileSystemPath } from "./urlToFileSystemPath.js"
6
6
  import { readSymbolicLink } from "./readSymbolicLink.js"
7
7
  import { resolveUrl } from "./resolveUrl.js"
8
8
  import { readDirectory } from "./readDirectory.js"
9
- import { moveFileSystemNode } from "./moveFileSystemNode.js"
9
+ import { moveEntry } from "./moveEntry.js"
10
10
  import { urlTargetsSameFileSystemPath } from "./internal/urlTargetsSameFileSystemPath.js"
11
11
  import { statsToType } from "./internal/statsToType.js"
12
12
 
@@ -22,7 +22,7 @@ export const moveDirectoryContent = async ({
22
22
  let toUrl = assertAndNormalizeDirectoryUrl(to)
23
23
  let toPath = urlToFileSystemPath(toUrl)
24
24
 
25
- const sourceStats = await readFileSystemNodeStat(fromUrl, {
25
+ const sourceStats = await readEntryStat(fromUrl, {
26
26
  nullIfNotFound: true,
27
27
  followLink: false,
28
28
  })
@@ -36,7 +36,7 @@ export const moveDirectoryContent = async ({
36
36
  )
37
37
  }
38
38
 
39
- let destinationStats = await readFileSystemNodeStat(toUrl, {
39
+ let destinationStats = await readEntryStat(toUrl, {
40
40
  nullIfNotFound: true,
41
41
  // we force false here but in fact we will follow the destination link
42
42
  // to know where we will actually move and detect useless move overrite etc..
@@ -46,7 +46,7 @@ export const moveDirectoryContent = async ({
46
46
  const linkTarget = await readSymbolicLink(toUrl)
47
47
  toUrl = resolveUrl(linkTarget, toUrl)
48
48
  toPath = urlToFileSystemPath(toUrl)
49
- destinationStats = await readFileSystemNodeStat(toUrl, {
49
+ destinationStats = await readEntryStat(toUrl, {
50
50
  nullIfNotFound: true,
51
51
  })
52
52
  }
@@ -78,7 +78,7 @@ export const moveDirectoryContent = async ({
78
78
  const to = resolveUrl(directoryEntry, toUrl)
79
79
 
80
80
  await moveOperation.withSignal(async (signal) => {
81
- await moveFileSystemNode({
81
+ await moveEntry({
82
82
  signal,
83
83
  from,
84
84
  to,
@@ -7,12 +7,12 @@ import { assertAndNormalizeFileUrl } from "./assertAndNormalizeFileUrl.js"
7
7
  import { urlToFileSystemPath } from "./urlToFileSystemPath.js"
8
8
  import { resolveUrl } from "./resolveUrl.js"
9
9
  import { ensureParentDirectories } from "./ensureParentDirectories.js"
10
- import { removeFileSystemNode } from "./removeFileSystemNode.js"
11
- import { copyFileSystemNode } from "./copyFileSystemNode.js"
12
- import { readFileSystemNodeStat } from "./readFileSystemNodeStat.js"
10
+ import { removeEntry } from "./removeEntry.js"
11
+ import { copyEntry } from "./copyEntry.js"
12
+ import { readEntryStat } from "./readEntryStat.js"
13
13
  import { readSymbolicLink } from "./readSymbolicLink.js"
14
14
 
15
- export const moveFileSystemNode = async ({
15
+ export const moveEntry = async ({
16
16
  signal = new AbortController().signal,
17
17
  from,
18
18
  to,
@@ -25,7 +25,7 @@ export const moveFileSystemNode = async ({
25
25
  let toUrl = assertAndNormalizeFileUrl(to)
26
26
  let toPath = urlToFileSystemPath(toUrl)
27
27
 
28
- const sourceStats = await readFileSystemNodeStat(fromUrl, {
28
+ const sourceStats = await readEntryStat(fromUrl, {
29
29
  nullIfNotFound: true,
30
30
  followLink: false,
31
31
  })
@@ -33,7 +33,7 @@ export const moveFileSystemNode = async ({
33
33
  throw new Error(`nothing to move from ${fromPath}`)
34
34
  }
35
35
 
36
- let destinationStats = await readFileSystemNodeStat(toUrl, {
36
+ let destinationStats = await readEntryStat(toUrl, {
37
37
  nullIfNotFound: true,
38
38
  // we force false here but in fact we will follow the destination link
39
39
  // to know where we will actually move and detect useless move overrite etc..
@@ -44,7 +44,7 @@ export const moveFileSystemNode = async ({
44
44
  const linkTarget = await readSymbolicLink(toUrl)
45
45
  toUrl = resolveUrl(linkTarget, toUrl)
46
46
  toPath = urlToFileSystemPath(toUrl)
47
- destinationStats = await readFileSystemNodeStat(toUrl, {
47
+ destinationStats = await readEntryStat(toUrl, {
48
48
  nullIfNotFound: true,
49
49
  })
50
50
  }
@@ -78,7 +78,7 @@ export const moveFileSystemNode = async ({
78
78
  }
79
79
 
80
80
  // remove file, link, directory...
81
- await removeFileSystemNode(toUrl, {
81
+ await removeEntry(toUrl, {
82
82
  signal: moveOperation.signal,
83
83
  recursive: true,
84
84
  })
@@ -89,12 +89,12 @@ export const moveFileSystemNode = async ({
89
89
  moveOperation.throwIfAborted()
90
90
  await moveNaive(fromPath, toPath, {
91
91
  handleCrossDeviceError: async () => {
92
- await copyFileSystemNode({
92
+ await copyEntry({
93
93
  from: fromUrl,
94
94
  to: toUrl,
95
95
  preserveStat: true,
96
96
  })
97
- await removeFileSystemNode(fromUrl, {
97
+ await removeEntry(fromUrl, {
98
98
  signal: moveOperation.signal,
99
99
  recursive: true,
100
100
  })
package/src/moveUrl.js ADDED
@@ -0,0 +1,10 @@
1
+ import { urlToRelativeUrl } from "./urlToRelativeUrl.js"
2
+
3
+ export const moveUrl = ({ url, from, to, preferAbsolute = false }) => {
4
+ const relativeUrl = urlToRelativeUrl(url, from)
5
+ const absoluteUrl = new URL(relativeUrl, to).href
6
+ if (preferAbsolute) {
7
+ return absoluteUrl
8
+ }
9
+ return urlToRelativeUrl(absoluteUrl, to)
10
+ }
@@ -0,0 +1,6 @@
1
+ import { readEntryStat } from "./readEntryStat.js"
2
+
3
+ export const readEntryModificationTime = async (source) => {
4
+ const stats = await readEntryStat(source)
5
+ return Math.floor(stats.mtimeMs)
6
+ }
@@ -11,7 +11,7 @@ import { urlToFileSystemPath } from "./urlToFileSystemPath.js"
11
11
 
12
12
  const { stat } = promises
13
13
 
14
- export const readFileSystemNodePermissions = async (source) => {
14
+ export const readEntryPermissions = async (source) => {
15
15
  const sourceUrl = assertAndNormalizeFileUrl(source)
16
16
  const sourcePath = urlToFileSystemPath(sourceUrl)
17
17
 
@@ -7,11 +7,11 @@ import { lstat, stat } from "node:fs"
7
7
 
8
8
  import { assertAndNormalizeFileUrl } from "./assertAndNormalizeFileUrl.js"
9
9
  import { urlToFileSystemPath } from "./urlToFileSystemPath.js"
10
- import { writeFileSystemNodePermissions } from "./writeFileSystemNodePermissions.js"
10
+ import { writeEntryPermissions } from "./writeEntryPermissions.js"
11
11
 
12
12
  const isWindows = process.platform === "win32"
13
13
 
14
- export const readFileSystemNodeStat = async (
14
+ export const readEntryStat = async (
15
15
  source,
16
16
  { nullIfNotFound = false, followLink = true } = {},
17
17
  ) => {
@@ -41,7 +41,7 @@ export const readFileSystemNodeStat = async (
41
41
  // unfortunately it means we mutate the permissions
42
42
  // without being able to restore them to the previous value
43
43
  // (because reading current permission would also throw)
44
- await writeFileSystemNodePermissions(sourceUrl, 0o666)
44
+ await writeEntryPermissions(sourceUrl, 0o666)
45
45
  const stats = await readStat(sourcePath, {
46
46
  followLink,
47
47
  ...handleNotFoundOption,
@@ -6,7 +6,7 @@ import {
6
6
  urlToMeta,
7
7
  } from "@jsenv/url-meta"
8
8
  import { replaceBackSlashesWithSlashes } from "./internal/replaceBackSlashesWithSlashes.js"
9
- import { fileSystemNodeToTypeOrNull } from "./internal/fileSystemNodeToTypeOrNull.js"
9
+ import { entryToTypeOrNull } from "./internal/entryToTypeOrNull.js"
10
10
  import { createWatcher } from "./internal/createWatcher.js"
11
11
  import { trackRessources } from "./internal/trackRessources.js"
12
12
  import { ensureUrlTrailingSlash } from "./internal/ensureUrlTrailingSlash.js"
@@ -120,7 +120,7 @@ export const registerDirectoryLifecycle = (
120
120
  const removedEntryRelativeUrl = relativeUrlCandidateArray.find(
121
121
  (relativeUrlCandidate) => {
122
122
  const entryUrl = resolveUrl(relativeUrlCandidate, sourceUrl)
123
- const type = fileSystemNodeToTypeOrNull(entryUrl)
123
+ const type = entryToTypeOrNull(entryUrl)
124
124
  return type === null
125
125
  },
126
126
  )
@@ -137,7 +137,7 @@ export const registerDirectoryLifecycle = (
137
137
  const handleChange = (relativeUrl) => {
138
138
  const entryUrl = resolveUrl(relativeUrl, sourceUrl)
139
139
  const previousType = contentMap.get(relativeUrl)
140
- const type = fileSystemNodeToTypeOrNull(entryUrl)
140
+ const type = entryToTypeOrNull(entryUrl)
141
141
 
142
142
  if (!entryShouldBeWatched({ relativeUrl, type })) {
143
143
  return
@@ -277,7 +277,7 @@ const visitDirectory = ({ directoryUrl, entryFound }) => {
277
277
  const directoryPath = urlToFileSystemPath(directoryUrl)
278
278
  readdirSync(directoryPath).forEach((entry) => {
279
279
  const entryUrl = resolveUrl(entry, directoryUrl)
280
- const type = fileSystemNodeToTypeOrNull(entryUrl)
280
+ const type = entryToTypeOrNull(entryUrl)
281
281
  if (type === null) {
282
282
  return
283
283
  }
@@ -1,5 +1,5 @@
1
1
  import { dirname, basename } from "path"
2
- import { fileSystemNodeToTypeOrNull } from "./internal/fileSystemNodeToTypeOrNull.js"
2
+ import { entryToTypeOrNull } from "./internal/entryToTypeOrNull.js"
3
3
  import { createWatcher } from "./internal/createWatcher.js"
4
4
  import { trackRessources } from "./internal/trackRessources.js"
5
5
  import { assertAndNormalizeFileUrl } from "./assertAndNormalizeFileUrl.js"
@@ -67,7 +67,7 @@ export const registerFileLifecycle = (
67
67
  )
68
68
  }
69
69
 
70
- const sourceType = fileSystemNodeToTypeOrNull(sourceUrl)
70
+ const sourceType = entryToTypeOrNull(sourceUrl)
71
71
  if (sourceType === null) {
72
72
  if (added) {
73
73
  watchFileAdded()
@@ -102,7 +102,7 @@ const watchFileCreation = (source, callback, keepProcessAlive) => {
102
102
  directoryWatcher.on("change", (eventType, filename) => {
103
103
  if (filename && filename !== sourceFilename) return
104
104
 
105
- const type = fileSystemNodeToTypeOrNull(source)
105
+ const type = entryToTypeOrNull(source)
106
106
  // ignore if something else with that name gets created
107
107
  // we are only interested into files
108
108
  if (type !== "file") return
@@ -128,7 +128,7 @@ const watchFileMutation = (
128
128
  })
129
129
 
130
130
  watcher.on("change", () => {
131
- const sourceType = fileSystemNodeToTypeOrNull(sourceUrl)
131
+ const sourceType = entryToTypeOrNull(sourceUrl)
132
132
 
133
133
  if (sourceType === null) {
134
134
  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,
@@ -8,7 +8,12 @@ export const urlToPathname = (url) => {
8
8
 
9
9
  const ressourceToPathname = (ressource) => {
10
10
  const searchSeparatorIndex = ressource.indexOf("?")
11
- return searchSeparatorIndex === -1
12
- ? ressource
13
- : ressource.slice(0, searchSeparatorIndex)
11
+ if (searchSeparatorIndex > -1) {
12
+ return ressource.slice(0, searchSeparatorIndex)
13
+ }
14
+ const hashIndex = ressource.indexOf("#")
15
+ if (hashIndex > -1) {
16
+ return ressource.slice(0, hashIndex)
17
+ }
18
+ return ressource
14
19
  }
@@ -31,7 +31,6 @@ export const urlToRelativeUrl = (url, baseUrl) => {
31
31
  const urlAsString = String(url)
32
32
  return urlAsString
33
33
  }
34
-
35
34
  const specificPathname = pathname.slice(commonPathname.length)
36
35
  const baseSpecificPathname = basePathname.slice(commonPathname.length)
37
36
  if (baseSpecificPathname.includes("/")) {
@@ -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
 
package/src/writeFile.js CHANGED
@@ -1,4 +1,5 @@
1
- import { promises } from "fs"
1
+ import { promises } from "node:fs"
2
+
2
3
  import { assertAndNormalizeFileUrl } from "./assertAndNormalizeFileUrl.js"
3
4
  import { urlToFileSystemPath } from "./urlToFileSystemPath.js"
4
5
  import { ensureParentDirectories } from "./ensureParentDirectories.js"
@@ -0,0 +1,20 @@
1
+ import { writeFileSync as writeFileSyncNode, mkdirSync } from "node:fs"
2
+
3
+ import { assertAndNormalizeFileUrl } from "./assertAndNormalizeFileUrl.js"
4
+
5
+ export const writeFileSync = (destination, content = "") => {
6
+ const destinationUrl = assertAndNormalizeFileUrl(destination)
7
+ const destinationUrlObject = new URL(destinationUrl)
8
+ try {
9
+ writeFileSyncNode(destinationUrlObject, content)
10
+ } catch (error) {
11
+ if (error.code === "ENOENT") {
12
+ mkdirSync(new URL("./", destinationUrlObject), {
13
+ recursive: true,
14
+ })
15
+ writeFileSyncNode(destinationUrlObject, content)
16
+ return
17
+ }
18
+ throw error
19
+ }
20
+ }
@@ -6,9 +6,9 @@ import { urlToFileSystemPath } from "./urlToFileSystemPath.js"
6
6
  import { resolveUrl } from "./resolveUrl.js"
7
7
  import { isFileSystemPath } from "./isFileSystemPath.js"
8
8
  import { ensureParentDirectories } from "./ensureParentDirectories.js"
9
- import { readFileSystemNodeStat } from "./readFileSystemNodeStat.js"
9
+ import { readEntryStat } from "./readEntryStat.js"
10
10
  import { readSymbolicLink } from "./readSymbolicLink.js"
11
- import { removeFileSystemNode } from "./removeFileSystemNode.js"
11
+ import { removeEntry } from "./removeEntry.js"
12
12
 
13
13
  // https://nodejs.org/dist/latest-v13.x/docs/api/fs.html#fs_fspromises_symlink_target_path_type
14
14
  const { symlink } = promises
@@ -38,7 +38,7 @@ export const writeSymbolicLink = async ({
38
38
  // In practice, if code don't specify "type" on windows, you later get EPERM errors
39
39
  // when doing operation on the symlink such as "fs.stat"
40
40
  if (isWindows && typeof type === "undefined") {
41
- const toStats = await readFileSystemNodeStat(toInfo.url, {
41
+ const toStats = await readEntryStat(toInfo.url, {
42
42
  nullIfNotFound: true,
43
43
  })
44
44
  type = toStats && toStats.isDirectory() ? "dir" : "file"
@@ -60,7 +60,7 @@ export const writeSymbolicLink = async ({
60
60
  }
61
61
  }
62
62
  if (allowOverwrite) {
63
- await removeFileSystemNode(fromUrl)
63
+ await removeEntry(fromUrl)
64
64
  await symlink(toInfo.value, symbolicLinkPath, type)
65
65
  return
66
66
  }
@@ -1,20 +0,0 @@
1
- import { assertAndNormalizeFileUrl } from "./assertAndNormalizeFileUrl.js"
2
- import { readFileSystemNodePermissions } from "./readFileSystemNodePermissions.js"
3
- import { writeFileSystemNodePermissions } from "./writeFileSystemNodePermissions.js"
4
-
5
- export const grantPermissionsOnFileSystemNode = async (
6
- source,
7
- { read = false, write = false, execute = false },
8
- ) => {
9
- const sourceUrl = assertAndNormalizeFileUrl(source)
10
-
11
- const filePermissions = await readFileSystemNodePermissions(sourceUrl)
12
- await writeFileSystemNodePermissions(sourceUrl, {
13
- owner: { read, write, execute },
14
- group: { read, write, execute },
15
- others: { read, write, execute },
16
- })
17
- return async () => {
18
- await writeFileSystemNodePermissions(sourceUrl, filePermissions)
19
- }
20
- }
@@ -1,6 +0,0 @@
1
- import { readFileSystemNodeStat } from "./readFileSystemNodeStat.js"
2
-
3
- export const readFileSystemNodeModificationTime = async (source) => {
4
- const stats = await readFileSystemNodeStat(source)
5
- return Math.floor(stats.mtimeMs)
6
- }