@jsenv/filesystem 4.3.2 → 4.5.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 (69) hide show
  1. package/package.json +4 -3
  2. package/src/{assertDirectoryPresence.js → assert_directory_presence.js} +3 -3
  3. package/src/{assertFilePresence.js → assert_file_presence.js} +3 -3
  4. package/src/copy/copy_directory.js +9 -0
  5. package/src/{copyDirectoryContent.js → copy/copy_directory_content.js} +7 -7
  6. package/src/copy/copy_directory_content_sync.js +90 -0
  7. package/src/copy/copy_directory_sync.js +9 -0
  8. package/src/{copyEntry.js → copy/copy_entry.js} +13 -13
  9. package/src/copy/copy_entry_sync.js +212 -0
  10. package/src/copy/copy_file.js +9 -0
  11. package/src/copy/copy_file_sync.js +9 -0
  12. package/src/{registerDirectoryLifecycle.js → lifecycle/register_directory_lifecycle.js} +5 -5
  13. package/src/{registerFileLifecycle.js → lifecycle/register_file_lifecycle.js} +5 -5
  14. package/src/{collectDirectoryMatchReport.js → list/collect_directory_match_report.js} +5 -5
  15. package/src/{collectFiles.js → list/collect_files.js} +4 -4
  16. package/src/{listFilesMatching.js → list/list_files_matching.js} +1 -1
  17. package/src/main.js +81 -35
  18. package/src/{moveDirectoryContent.js → move/move_directory_content.js} +7 -7
  19. package/src/{moveEntry.js → move/move_entry.js} +8 -8
  20. package/src/{ensureParentDirectories.js → read_write/ensure_parent_directories.js} +3 -3
  21. package/src/read_write/ensure_parent_directories_sync.js +16 -0
  22. package/src/{readDirectory.js → read_write/read_directory.js} +2 -1
  23. package/src/read_write/read_directory_sync.js +10 -0
  24. package/src/{readFile.js → read_write/read_file.js} +1 -1
  25. package/src/read_write/read_file_structure_sync.js +57 -0
  26. package/src/{readFileSync.js → read_write/read_file_sync.js} +1 -1
  27. package/src/{readSymbolicLink.js → read_write/read_symbolic_link.js} +1 -1
  28. package/src/read_write/read_symbolic_link_sync.js +17 -0
  29. package/src/{grantPermissionsOnEntry.js → read_write/stat/grant_permissions_on_entry.js} +3 -3
  30. package/src/{internal → read_write/stat}/read_entry_info.js +1 -1
  31. package/src/{readEntryModificationTime.js → read_write/stat/read_entry_modification_time.js} +1 -1
  32. package/src/{readEntryPermissions.js → read_write/stat/read_entry_permissions.js} +2 -2
  33. package/src/{readEntryStat.js → read_write/stat/read_entry_stat.js} +2 -2
  34. package/src/read_write/stat/read_entry_stat_sync.js +92 -0
  35. package/src/{testEntryPermissions.js → read_write/stat/test_entry_permissions.js} +1 -1
  36. package/src/{writeEntryModificationTime.js → read_write/stat/write_entry_modification_time.js} +1 -1
  37. package/src/read_write/stat/write_entry_modification_time_sync.js +14 -0
  38. package/src/{writeEntryPermissions.js → read_write/stat/write_entry_permissions.js} +2 -2
  39. package/src/read_write/stat/write_entry_permissions_sync.js +77 -0
  40. package/src/{writeDirectory.js → read_write/write_directory.js} +3 -3
  41. package/src/read_write/write_directory_sync.js +42 -0
  42. package/src/{writeFile.js → read_write/write_file.js} +2 -2
  43. package/src/read_write/write_file_structure_sync.js +13 -0
  44. package/src/{writeFileSync.js → read_write/write_file_sync.js} +1 -1
  45. package/src/{writeSymbolicLink.js → read_write/write_symbolic_link.js} +5 -5
  46. package/src/read_write/write_symbolic_link_sync.js +115 -0
  47. package/src/remove/clear_directory_sync.js +68 -0
  48. package/src/{ensureEmptyDirectory.js → remove/ensure_empty_directory.js} +9 -7
  49. package/src/remove/ensure_empty_directory_sync.js +34 -0
  50. package/src/remove/remove_directory.js +8 -0
  51. package/src/remove/remove_directory_sync.js +8 -0
  52. package/src/{removeEntry.js → remove/remove_entry.js} +3 -3
  53. package/src/remove/remove_entry_sync.js +240 -0
  54. package/src/remove/remove_file.js +5 -0
  55. package/src/remove/remove_file_sync.js +5 -0
  56. package/src/internal/getCommandArgument.js +0 -27
  57. /package/src/{bufferToEtag.js → buffer_to_etag.js} +0 -0
  58. /package/src/{internal/createWatcher.js → lifecycle/create_watcher.js} +0 -0
  59. /package/src/{internal → lifecycle}/guard_second_call.js +0 -0
  60. /package/src/{internal → lifecycle}/track_resources.js +0 -0
  61. /package/src/{comparePathnames.js → path_and_url/compare_pathnames.js} +0 -0
  62. /package/src/{directory_url_validation.js → path_and_url/directory_url_validation.js} +0 -0
  63. /package/src/{ensureWindowsDriveLetter.js → path_and_url/ensure_windows_drive_letter.js} +0 -0
  64. /package/src/{fileSystemRootUrl.js → path_and_url/file_system_root_url.js} +0 -0
  65. /package/src/{file_url_validation.js → path_and_url/file_url_validation.js} +0 -0
  66. /package/src/{internal/urlTargetsSameFileSystemPath.js → path_and_url/url_targets_same_file_system_path.js} +0 -0
  67. /package/src/{getRealFileSystemUrlSync.js → read_write/get_real_file_system_url_sync.js} +0 -0
  68. /package/src/{internal → read_write/stat}/permissions.js +0 -0
  69. /package/src/{internal/statsToType.js → read_write/stat/stats_to_type.js} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/filesystem",
3
- "version": "4.3.2",
3
+ "version": "4.5.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -33,7 +33,8 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "@jsenv/urls": "2.2.1",
36
- "@jsenv/url-meta": "8.1.0",
37
- "@jsenv/abort": "4.2.4"
36
+ "@jsenv/url-meta": "8.2.0",
37
+ "@jsenv/abort": "4.2.4",
38
+ "@jsenv/utils": "2.0.1"
38
39
  }
39
40
  }
@@ -1,8 +1,8 @@
1
1
  import { urlToFileSystemPath } from "@jsenv/urls";
2
2
 
3
- import { assertAndNormalizeFileUrl } from "./file_url_validation.js";
4
- import { statsToType } from "./internal/statsToType.js";
5
- import { readEntryStat } from "./readEntryStat.js";
3
+ import { assertAndNormalizeFileUrl } from "./path_and_url/file_url_validation.js";
4
+ import { readEntryStat } from "./read_write/stat/read_entry_stat.js";
5
+ import { statsToType } from "./read_write/stat/stats_to_type.js";
6
6
 
7
7
  export const assertDirectoryPresence = async (source) => {
8
8
  const sourceUrl = assertAndNormalizeFileUrl(source);
@@ -1,8 +1,8 @@
1
1
  import { urlToFileSystemPath } from "@jsenv/urls";
2
2
 
3
- import { assertAndNormalizeFileUrl } from "./file_url_validation.js";
4
- import { statsToType } from "./internal/statsToType.js";
5
- import { readEntryStat } from "./readEntryStat.js";
3
+ import { assertAndNormalizeFileUrl } from "./path_and_url/file_url_validation.js";
4
+ import { readEntryStat } from "./read_write/stat/read_entry_stat.js";
5
+ import { statsToType } from "./read_write/stat/stats_to_type.js";
6
6
 
7
7
  export const assertFilePresence = async (source) => {
8
8
  const sourceUrl = assertAndNormalizeFileUrl(source);
@@ -0,0 +1,9 @@
1
+ import { copyEntry } from "./copy_entry.js";
2
+
3
+ export const copyDirectory = ({ from, to, ...options }) => {
4
+ copyEntry({
5
+ from,
6
+ to,
7
+ ...options,
8
+ });
9
+ };
@@ -1,13 +1,13 @@
1
1
  import { Abort } from "@jsenv/abort";
2
2
  import { urlToFileSystemPath, resolveUrl } from "@jsenv/urls";
3
3
 
4
- import { assertAndNormalizeDirectoryUrl } from "./directory_url_validation.js";
5
- import { readEntryStat } from "./readEntryStat.js";
6
- import { readSymbolicLink } from "./readSymbolicLink.js";
7
- import { readDirectory } from "./readDirectory.js";
8
- import { copyEntry } from "./copyEntry.js";
9
- import { urlTargetsSameFileSystemPath } from "./internal/urlTargetsSameFileSystemPath.js";
10
- import { statsToType } from "./internal/statsToType.js";
4
+ import { assertAndNormalizeDirectoryUrl } from "../path_and_url/directory_url_validation.js";
5
+ import { urlTargetsSameFileSystemPath } from "../path_and_url/url_targets_same_file_system_path.js";
6
+ import { statsToType } from "../read_write/stat/stats_to_type.js";
7
+ import { readEntryStat } from "../read_write/stat/read_entry_stat.js";
8
+ import { readSymbolicLink } from "../read_write/read_symbolic_link.js";
9
+ import { readDirectory } from "../read_write/read_directory.js";
10
+ import { copyEntry } from "./copy_entry.js";
11
11
 
12
12
  export const copyDirectoryContent = async ({
13
13
  signal = new AbortController().signal,
@@ -0,0 +1,90 @@
1
+ import { Abort } from "@jsenv/abort";
2
+ import { urlToFileSystemPath, resolveUrl } from "@jsenv/urls";
3
+
4
+ import { assertAndNormalizeDirectoryUrl } from "../path_and_url/directory_url_validation.js";
5
+ import { urlTargetsSameFileSystemPath } from "../path_and_url/url_targets_same_file_system_path.js";
6
+ import { statsToType } from "../read_write/stat/stats_to_type.js";
7
+ import { readEntryStatSync } from "../read_write/stat/read_entry_stat_sync.js";
8
+ import { readSymbolicLinkSync } from "../read_write/read_symbolic_link_sync.js";
9
+ import { readDirectorySync } from "../read_write/read_directory_sync.js";
10
+ import { copyEntrySync } from "./copy_entry_sync.js";
11
+
12
+ export const copyDirectoryContentSync = ({
13
+ signal = new AbortController().signal,
14
+ from,
15
+ to,
16
+ overwrite,
17
+ followLink = true,
18
+ } = {}) => {
19
+ const fromUrl = assertAndNormalizeDirectoryUrl(from);
20
+ const fromPath = urlToFileSystemPath(fromUrl);
21
+ let toUrl = assertAndNormalizeDirectoryUrl(to);
22
+ let toPath = urlToFileSystemPath(toUrl);
23
+
24
+ const sourceStats = readEntryStatSync(fromUrl, {
25
+ nullIfNotFound: true,
26
+ followLink: false,
27
+ });
28
+ if (!sourceStats) {
29
+ throw new Error(`no directory to copy content from at ${fromPath}`);
30
+ }
31
+ if (!sourceStats.isDirectory()) {
32
+ const sourceType = statsToType(sourceStats);
33
+ throw new Error(
34
+ `found a ${sourceType} instead of a directory at ${fromPath}`,
35
+ );
36
+ }
37
+
38
+ let destinationStats = readEntryStatSync(toUrl, {
39
+ nullIfNotFound: true,
40
+ // we force false here but in fact we will follow the destination link
41
+ // to know where we will actually move and detect useless move overrite etc..
42
+ followLink: false,
43
+ });
44
+ if (followLink && destinationStats && destinationStats.isSymbolicLink()) {
45
+ const linkTarget = readSymbolicLinkSync(toUrl);
46
+ toUrl = resolveUrl(linkTarget, toUrl);
47
+ toPath = urlToFileSystemPath(toUrl);
48
+ destinationStats = readEntryStatSync(toUrl, {
49
+ nullIfNotFound: true,
50
+ });
51
+ }
52
+
53
+ if (destinationStats === null) {
54
+ throw new Error(`no directory to copy content into at ${toPath}`);
55
+ }
56
+ if (!destinationStats.isDirectory()) {
57
+ const destinationType = statsToType(destinationStats);
58
+ throw new Error(
59
+ `destination leads to a ${destinationType} instead of a directory at ${toPath}`,
60
+ );
61
+ }
62
+
63
+ if (urlTargetsSameFileSystemPath(fromUrl, toUrl)) {
64
+ throw new Error(
65
+ `cannot copy directory content, source and destination are the same (${fromPath})`,
66
+ );
67
+ }
68
+
69
+ const copyOperation = Abort.startOperation();
70
+ copyOperation.addAbortSignal(signal);
71
+ try {
72
+ copyOperation.throwIfAborted();
73
+ const directoryEntries = readDirectorySync(fromUrl);
74
+ directoryEntries.forEach((directoryEntry) => {
75
+ const from = resolveUrl(directoryEntry, fromUrl);
76
+ const to = resolveUrl(directoryEntry, toUrl);
77
+ copyOperation.withSignal((signal) => {
78
+ copyEntrySync({
79
+ signal,
80
+ from,
81
+ to,
82
+ overwrite,
83
+ followLink,
84
+ });
85
+ });
86
+ });
87
+ } finally {
88
+ copyOperation.end();
89
+ }
90
+ };
@@ -0,0 +1,9 @@
1
+ import { copyEntrySync } from "./copy_entry_sync.js";
2
+
3
+ export const copyDirectorySync = ({ from, to, ...options }) => {
4
+ copyEntrySync({
5
+ from,
6
+ to,
7
+ ...options,
8
+ });
9
+ };
@@ -8,19 +8,19 @@ import {
8
8
  urlToFileSystemPath,
9
9
  } from "@jsenv/urls";
10
10
 
11
- import { urlTargetsSameFileSystemPath } from "./internal/urlTargetsSameFileSystemPath.js";
12
- import { statsToType } from "./internal/statsToType.js";
13
- import { binaryFlagsToPermissions } from "./internal/permissions.js";
14
- import { assertAndNormalizeFileUrl } from "./file_url_validation.js";
15
- import { writeDirectory } from "./writeDirectory.js";
16
- import { readEntryStat } from "./readEntryStat.js";
17
- import { ensureParentDirectories } from "./ensureParentDirectories.js";
18
- import { writeEntryPermissions } from "./writeEntryPermissions.js";
19
- import { writeEntryModificationTime } from "./writeEntryModificationTime.js";
20
- import { readDirectory } from "./readDirectory.js";
21
- import { readSymbolicLink } from "./readSymbolicLink.js";
22
- import { writeSymbolicLink } from "./writeSymbolicLink.js";
23
- import { removeEntry } from "./removeEntry.js";
11
+ import { assertAndNormalizeFileUrl } from "../path_and_url/file_url_validation.js";
12
+ import { urlTargetsSameFileSystemPath } from "../path_and_url/url_targets_same_file_system_path.js";
13
+ import { readEntryStat } from "../read_write/stat/read_entry_stat.js";
14
+ import { statsToType } from "../read_write/stat/stats_to_type.js";
15
+ import { binaryFlagsToPermissions } from "../read_write/stat/permissions.js";
16
+ import { writeEntryPermissions } from "../read_write/stat/write_entry_permissions.js";
17
+ import { writeEntryModificationTime } from "../read_write/stat/write_entry_modification_time.js";
18
+ import { writeDirectory } from "../read_write/write_directory.js";
19
+ import { ensureParentDirectories } from "../read_write/ensure_parent_directories.js";
20
+ import { readDirectory } from "../read_write/read_directory.js";
21
+ import { readSymbolicLink } from "../read_write/read_symbolic_link.js";
22
+ import { writeSymbolicLink } from "../read_write/write_symbolic_link.js";
23
+ import { removeEntry } from "../remove/remove_entry.js";
24
24
 
25
25
  export const copyEntry = async ({
26
26
  signal = new AbortController().signal,
@@ -0,0 +1,212 @@
1
+ import { copyFileSync as copyFileSyncNode } from "node:fs";
2
+ import { Abort } from "@jsenv/abort";
3
+ import {
4
+ resolveUrl,
5
+ urlToRelativeUrl,
6
+ ensurePathnameTrailingSlash,
7
+ urlIsInsideOf,
8
+ urlToFileSystemPath,
9
+ } from "@jsenv/urls";
10
+
11
+ import { assertAndNormalizeFileUrl } from "../path_and_url/file_url_validation.js";
12
+ import { urlTargetsSameFileSystemPath } from "../path_and_url/url_targets_same_file_system_path.js";
13
+ import { readEntryStatSync } from "../read_write/stat/read_entry_stat_sync.js";
14
+ import { statsToType } from "../read_write/stat/stats_to_type.js";
15
+ import { binaryFlagsToPermissions } from "../read_write/stat/permissions.js";
16
+ import { writeEntryPermissionsSync } from "../read_write/stat/write_entry_permissions_sync.js";
17
+ import { writeEntryModificationTimeSync } from "../read_write/stat/write_entry_modification_time_sync.js";
18
+ import { writeDirectorySync } from "../read_write/write_directory_sync.js";
19
+ import { ensureParentDirectoriesSync } from "../read_write/ensure_parent_directories_sync.js";
20
+ import { readDirectorySync } from "../read_write/read_directory_sync.js";
21
+ import { readSymbolicLinkSync } from "../read_write/read_symbolic_link_sync.js";
22
+ import { writeSymbolicLinkSync } from "../read_write/write_symbolic_link_sync.js";
23
+ import { removeEntrySync } from "../remove/remove_entry_sync.js";
24
+
25
+ export const copyEntrySync = ({
26
+ signal = new AbortController().signal,
27
+ from,
28
+ to,
29
+ overwrite = false,
30
+ preserveStat = true,
31
+ preserveMtime = preserveStat,
32
+ preservePermissions = preserveStat,
33
+ allowUseless = false,
34
+ followLink = true,
35
+ }) => {
36
+ const fromUrl = assertAndNormalizeFileUrl(from);
37
+ const fromPath = urlToFileSystemPath(fromUrl);
38
+ let toUrl = assertAndNormalizeFileUrl(to);
39
+ let toPath = urlToFileSystemPath(toUrl);
40
+
41
+ const sourceStats = readEntryStatSync(fromUrl, {
42
+ nullIfNotFound: true,
43
+ followLink: false,
44
+ });
45
+ if (!sourceStats) {
46
+ throw new Error(`nothing to copy at ${fromPath}`);
47
+ }
48
+
49
+ let destinationStats = readEntryStatSync(toUrl, {
50
+ nullIfNotFound: true,
51
+ // we force false here but in fact we will follow the destination link
52
+ // to know where we will actually move and detect useless move overrite etc..
53
+ followLink: false,
54
+ });
55
+
56
+ if (followLink && destinationStats && destinationStats.isSymbolicLink()) {
57
+ const linkTarget = readSymbolicLinkSync(toUrl);
58
+ toUrl = resolveUrl(linkTarget, toUrl);
59
+ toPath = urlToFileSystemPath(toUrl);
60
+ destinationStats = readEntryStatSync(toUrl, {
61
+ nullIfNotFound: true,
62
+ });
63
+ }
64
+
65
+ if (urlTargetsSameFileSystemPath(fromUrl, toUrl)) {
66
+ if (allowUseless) {
67
+ return;
68
+ }
69
+ throw new Error(
70
+ `cannot copy ${fromPath} because destination and source are the same`,
71
+ );
72
+ }
73
+
74
+ if (sourceStats.isDirectory()) {
75
+ toUrl = ensurePathnameTrailingSlash(toUrl);
76
+ }
77
+
78
+ const copyOperation = Abort.startOperation();
79
+ copyOperation.addAbortSignal(signal);
80
+
81
+ const visit = async (url, stats) => {
82
+ copyOperation.throwIfAborted();
83
+ if (stats.isFile() || stats.isCharacterDevice() || stats.isBlockDevice()) {
84
+ visitFile(url, stats);
85
+ } else if (stats.isSymbolicLink()) {
86
+ visitSymbolicLink(url, stats);
87
+ } else if (stats.isDirectory()) {
88
+ visitDirectory(ensurePathnameTrailingSlash(url), stats);
89
+ }
90
+ };
91
+
92
+ const visitFile = (fileUrl, fileStats) => {
93
+ const fileRelativeUrl = urlToRelativeUrl(fileUrl, fromUrl);
94
+ const fileCopyUrl = resolveUrl(fileRelativeUrl, toUrl);
95
+
96
+ copyFileSyncNode(
97
+ urlToFileSystemPath(fileUrl),
98
+ urlToFileSystemPath(fileCopyUrl),
99
+ );
100
+ copyStatsSync(fileCopyUrl, fileStats);
101
+ };
102
+
103
+ const visitSymbolicLink = (symbolicLinkUrl) => {
104
+ const symbolicLinkRelativeUrl = urlToRelativeUrl(symbolicLinkUrl, fromUrl);
105
+ const symbolicLinkTarget = readSymbolicLinkSync(symbolicLinkUrl);
106
+ const symbolicLinkTargetUrl = resolveUrl(
107
+ symbolicLinkTarget,
108
+ symbolicLinkUrl,
109
+ );
110
+ const linkIsRelative =
111
+ symbolicLinkTarget.startsWith("./") ||
112
+ symbolicLinkTarget.startsWith("../");
113
+
114
+ let symbolicLinkCopyTarget;
115
+ if (symbolicLinkTargetUrl === fromUrl) {
116
+ symbolicLinkCopyTarget = linkIsRelative ? symbolicLinkTarget : toUrl;
117
+ } else if (urlIsInsideOf(symbolicLinkTargetUrl, fromUrl)) {
118
+ // symbolic link targets something inside the directory we want to copy
119
+ // reflects it inside the copied directory structure
120
+ const linkCopyTargetRelative = urlToRelativeUrl(
121
+ symbolicLinkTargetUrl,
122
+ fromUrl,
123
+ );
124
+ symbolicLinkCopyTarget = linkIsRelative
125
+ ? `./${linkCopyTargetRelative}`
126
+ : resolveUrl(linkCopyTargetRelative, toUrl);
127
+ } else {
128
+ // symbolic link targets something outside the directory we want to copy
129
+ symbolicLinkCopyTarget = symbolicLinkTarget;
130
+ }
131
+
132
+ // we must guess ourself the type of the symlink
133
+ // because the destination might not exists because not yet copied
134
+ // https://nodejs.org/dist/latest-v13.x/docs/api/fs.html#fs_fs_symlink_target_path_type_callback
135
+ const targetStats = readEntryStatSync(symbolicLinkTargetUrl, {
136
+ nullIfNotFound: true,
137
+ followLink: false,
138
+ });
139
+ const linkType = targetStats && targetStats.isDirectory() ? "dir" : "file";
140
+
141
+ const symbolicLinkCopyUrl = resolveUrl(symbolicLinkRelativeUrl, toUrl);
142
+ writeSymbolicLinkSync({
143
+ from: symbolicLinkCopyUrl,
144
+ to: symbolicLinkCopyTarget,
145
+ type: linkType,
146
+ });
147
+ };
148
+
149
+ const copyStatsSync = (toUrl, stats) => {
150
+ if (preservePermissions || preserveMtime) {
151
+ const { mode, mtimeMs } = stats;
152
+ if (preservePermissions) {
153
+ writeEntryPermissionsSync(toUrl, binaryFlagsToPermissions(mode));
154
+ }
155
+ if (preserveMtime) {
156
+ writeEntryModificationTimeSync(toUrl, mtimeMs);
157
+ }
158
+ }
159
+ };
160
+
161
+ const visitDirectory = async (directoryUrl, directoryStats) => {
162
+ const directoryRelativeUrl = urlToRelativeUrl(directoryUrl, fromUrl);
163
+ const directoryCopyUrl = resolveUrl(directoryRelativeUrl, toUrl);
164
+
165
+ writeDirectorySync(directoryCopyUrl);
166
+ copyDirectoryContentSync(directoryUrl);
167
+ copyStatsSync(directoryCopyUrl, directoryStats);
168
+ };
169
+
170
+ const copyDirectoryContentSync = async (directoryUrl) => {
171
+ const names = readDirectorySync(directoryUrl);
172
+ names.forEach((name) => {
173
+ const entryUrl = resolveUrl(name, directoryUrl);
174
+ const stats = readEntryStatSync(entryUrl, {
175
+ followLink: false,
176
+ });
177
+ visit(entryUrl, stats);
178
+ });
179
+ };
180
+
181
+ try {
182
+ if (destinationStats) {
183
+ const sourceType = statsToType(sourceStats);
184
+ const destinationType = statsToType(destinationStats);
185
+
186
+ if (sourceType !== destinationType) {
187
+ throw new Error(
188
+ `cannot copy ${sourceType} from ${fromPath} to ${toPath} because destination exists and is not a ${sourceType} (it's a ${destinationType})`,
189
+ );
190
+ }
191
+ if (!overwrite) {
192
+ throw new Error(
193
+ `cannot copy ${sourceType} from ${fromPath} to ${toPath} because destination exists and overwrite option is disabled`,
194
+ );
195
+ }
196
+
197
+ // remove file, link, directory...
198
+ removeEntrySync(toUrl, {
199
+ signal: copyOperation.signal,
200
+ recursive: true,
201
+ allowUseless: true,
202
+ });
203
+ } else {
204
+ ensureParentDirectoriesSync(toUrl);
205
+ }
206
+
207
+ copyOperation.throwIfAborted();
208
+ visit(fromUrl, sourceStats);
209
+ } finally {
210
+ copyOperation.end();
211
+ }
212
+ };
@@ -0,0 +1,9 @@
1
+ import { copyEntry } from "./copy_entry.js";
2
+
3
+ export const copyFile = ({ from, to, ...options }) => {
4
+ copyEntry({
5
+ from,
6
+ to,
7
+ ...options,
8
+ });
9
+ };
@@ -0,0 +1,9 @@
1
+ import { copyEntrySync } from "./copy_entry_sync.js";
2
+
3
+ export const copyFileSync = ({ from, to, ...options }) => {
4
+ copyEntrySync({
5
+ from,
6
+ to,
7
+ ...options,
8
+ });
9
+ };
@@ -2,11 +2,11 @@ import { readdirSync, statSync } from "node:fs";
2
2
  import { URL_META } from "@jsenv/url-meta";
3
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 "../path_and_url/directory_url_validation.js";
6
+ import { statsToType } from "../read_write/stat/stats_to_type.js";
7
+ import { guardTooFastSecondCallPerFile } from "./guard_second_call.js";
8
+ import { createWatcher } from "./create_watcher.js";
9
+ import { trackResources } from "./track_resources.js";
10
10
 
11
11
  const isLinux = process.platform === "linux";
12
12
  const fsWatchSupportsRecursive = !isLinux;
@@ -2,11 +2,11 @@ import { statSync } from "node:fs";
2
2
  import { dirname, basename } from "node:path";
3
3
  import { urlToFileSystemPath } from "@jsenv/urls";
4
4
 
5
- import { assertAndNormalizeFileUrl } from "./file_url_validation.js";
6
- import { guardTooFastSecondCall } from "./internal/guard_second_call.js";
7
- import { statsToType } from "./internal/statsToType.js";
8
- import { createWatcher } from "./internal/createWatcher.js";
9
- import { trackResources } from "./internal/track_resources.js";
5
+ import { assertAndNormalizeFileUrl } from "../path_and_url/file_url_validation.js";
6
+ import { statsToType } from "../read_write/stat/stats_to_type.js";
7
+ import { trackResources } from "./track_resources.js";
8
+ import { createWatcher } from "./create_watcher.js";
9
+ import { guardTooFastSecondCall } from "./guard_second_call.js";
10
10
 
11
11
  export const registerFileLifecycle = (
12
12
  source,
@@ -1,11 +1,11 @@
1
1
  import { Abort } from "@jsenv/abort";
2
-
3
2
  import { URL_META } from "@jsenv/url-meta";
4
3
  import { urlToRelativeUrl } from "@jsenv/urls";
5
- import { assertAndNormalizeDirectoryUrl } from "./directory_url_validation.js";
6
- import { readDirectory } from "./readDirectory.js";
7
- import { readEntryStat } from "./readEntryStat.js";
8
- import { comparePathnames } from "./comparePathnames.js";
4
+
5
+ import { assertAndNormalizeDirectoryUrl } from "../path_and_url/directory_url_validation.js";
6
+ import { comparePathnames } from "../path_and_url/compare_pathnames.js";
7
+ import { readDirectory } from "../read_write/read_directory.js";
8
+ import { readEntryStat } from "../read_write/stat/read_entry_stat.js";
9
9
 
10
10
  export const collectDirectoryMatchReport = async ({
11
11
  signal = new AbortController().signal,
@@ -2,10 +2,10 @@ import { Abort } from "@jsenv/abort";
2
2
  import { URL_META } from "@jsenv/url-meta";
3
3
  import { urlToRelativeUrl } from "@jsenv/urls";
4
4
 
5
- import { assertAndNormalizeDirectoryUrl } from "./directory_url_validation.js";
6
- import { readDirectory } from "./readDirectory.js";
7
- import { readEntryStat } from "./readEntryStat.js";
8
- import { comparePathnames } from "./comparePathnames.js";
5
+ import { assertAndNormalizeDirectoryUrl } from "../path_and_url/directory_url_validation.js";
6
+ import { comparePathnames } from "../path_and_url/compare_pathnames.js";
7
+ import { readEntryStat } from "../read_write/stat/read_entry_stat.js";
8
+ import { readDirectory } from "../read_write/read_directory.js";
9
9
 
10
10
  export const collectFiles = async ({
11
11
  signal = new AbortController().signal,
@@ -1,4 +1,4 @@
1
- import { collectFiles } from "./collectFiles.js";
1
+ import { collectFiles } from "./collect_files.js";
2
2
 
3
3
  export const listFilesMatching = async ({
4
4
  directoryUrl = process.cwd(),
package/src/main.js CHANGED
@@ -1,41 +1,87 @@
1
+ // we might wanna expose the sync versions as follows:
2
+ // readDirectory.sync()
3
+ // +1: very easy to switch between sync/async versions of a given function
4
+ // -1: code splitting
5
+ // -1: unusual
6
+
7
+ // path_and_url
1
8
  export {
2
9
  validateDirectoryUrl,
3
10
  assertAndNormalizeDirectoryUrl,
4
- } from "./directory_url_validation.js";
11
+ } from "./path_and_url/directory_url_validation.js";
5
12
  export {
6
13
  validateFileUrl,
7
14
  assertAndNormalizeFileUrl,
8
- } from "./file_url_validation.js";
9
- export { assertDirectoryPresence } from "./assertDirectoryPresence.js";
10
- export { assertFilePresence } from "./assertFilePresence.js";
11
- export { bufferToEtag } from "./bufferToEtag.js";
12
- export { collectDirectoryMatchReport } from "./collectDirectoryMatchReport.js";
13
- export { collectFiles } from "./collectFiles.js";
14
- export { comparePathnames } from "./comparePathnames.js";
15
- export { ensureEmptyDirectory } from "./ensureEmptyDirectory.js";
16
- export { ensureParentDirectories } from "./ensureParentDirectories.js";
17
- export { ensureWindowsDriveLetter } from "./ensureWindowsDriveLetter.js";
18
- export { copyEntry } from "./copyEntry.js";
19
- export { copyDirectoryContent } from "./copyDirectoryContent.js";
20
- export { getRealFileSystemUrlSync } from "./getRealFileSystemUrlSync.js";
21
- export { grantPermissionsOnEntry } from "./grantPermissionsOnEntry.js";
22
- export { listFilesMatching } from "./listFilesMatching.js";
23
- export { moveDirectoryContent } from "./moveDirectoryContent.js";
24
- export { moveEntry } from "./moveEntry.js";
25
- export { readDirectory } from "./readDirectory.js";
26
- export { readFile } from "./readFile.js";
27
- export { readFileSync } from "./readFileSync.js";
28
- export { readEntryModificationTime } from "./readEntryModificationTime.js";
29
- export { readEntryPermissions } from "./readEntryPermissions.js";
30
- export { readEntryStat } from "./readEntryStat.js";
31
- export { readSymbolicLink } from "./readSymbolicLink.js";
32
- export { registerDirectoryLifecycle } from "./registerDirectoryLifecycle.js";
33
- export { registerFileLifecycle } from "./registerFileLifecycle.js";
34
- export { removeEntry } from "./removeEntry.js";
35
- export { testEntryPermissions } from "./testEntryPermissions.js";
36
- export { writeDirectory } from "./writeDirectory.js";
37
- export { writeFile } from "./writeFile.js";
38
- export { writeFileSync } from "./writeFileSync.js";
39
- export { writeEntryModificationTime } from "./writeEntryModificationTime.js";
40
- export { writeEntryPermissions } from "./writeEntryPermissions.js";
41
- export { writeSymbolicLink } from "./writeSymbolicLink.js";
15
+ } from "./path_and_url/file_url_validation.js";
16
+ export { comparePathnames } from "./path_and_url/compare_pathnames.js";
17
+ export { ensureWindowsDriveLetter } from "./path_and_url/ensure_windows_drive_letter.js";
18
+
19
+ // list
20
+ export { collectDirectoryMatchReport } from "./list/collect_directory_match_report.js";
21
+ export { collectFiles } from "./list/collect_files.js";
22
+ export { listFilesMatching } from "./list/list_files_matching.js";
23
+
24
+ // read and write
25
+ export { ensureParentDirectories } from "./read_write/ensure_parent_directories.js";
26
+ export { readDirectory } from "./read_write/read_directory.js";
27
+ export { writeDirectory } from "./read_write/write_directory.js";
28
+ export { readFile } from "./read_write/read_file.js";
29
+ export { writeFile } from "./read_write/write_file.js";
30
+ export { readFileSync } from "./read_write/read_file_sync.js";
31
+ export { writeFileSync } from "./read_write/write_file_sync.js";
32
+ export { readSymbolicLink } from "./read_write/read_symbolic_link.js";
33
+ export { writeSymbolicLink } from "./read_write/write_symbolic_link.js";
34
+ // read and write sync
35
+ export { ensureParentDirectoriesSync } from "./read_write/ensure_parent_directories_sync.js";
36
+ export { readDirectorySync } from "./read_write/read_directory_sync.js";
37
+ export { getRealFileSystemUrlSync } from "./read_write/get_real_file_system_url_sync.js";
38
+ export { readSymbolicLinkSync } from "./read_write/read_symbolic_link_sync.js";
39
+ export { writeDirectorySync } from "./read_write/write_directory_sync.js";
40
+ export { readFileStructureSync } from "./read_write/read_file_structure_sync.js";
41
+ export { writeFileStructureSync } from "./read_write/write_file_structure_sync.js";
42
+
43
+ // stat
44
+ export { readEntryStat } from "./read_write/stat/read_entry_stat.js";
45
+ export { readEntryModificationTime } from "./read_write/stat/read_entry_modification_time.js";
46
+ export { writeEntryModificationTime } from "./read_write/stat/write_entry_modification_time.js";
47
+ export { readEntryPermissions } from "./read_write/stat/read_entry_permissions.js";
48
+ export { writeEntryPermissions } from "./read_write/stat/write_entry_permissions.js";
49
+ export { grantPermissionsOnEntry } from "./read_write/stat/grant_permissions_on_entry.js";
50
+ export { testEntryPermissions } from "./read_write/stat/test_entry_permissions.js";
51
+ // stat sync
52
+ export { readEntryStatSync } from "./read_write/stat/read_entry_stat_sync.js";
53
+ export { writeEntryModificationTimeSync } from "./read_write/stat/write_entry_modification_time_sync.js";
54
+
55
+ // move
56
+ export { moveDirectoryContent } from "./move/move_directory_content.js";
57
+ export { moveEntry } from "./move/move_entry.js";
58
+
59
+ // copy
60
+ export { copyEntry } from "./copy/copy_entry.js";
61
+ export { copyFile } from "./copy/copy_file.js";
62
+ export { copyDirectory } from "./copy/copy_directory.js";
63
+ export { copyDirectoryContent } from "./copy/copy_directory_content.js";
64
+ export { copyEntrySync } from "./copy/copy_entry_sync.js";
65
+ export { copyFileSync } from "./copy/copy_file_sync.js";
66
+ export { copyDirectorySync } from "./copy/copy_directory_sync.js";
67
+ export { copyDirectoryContentSync } from "./copy/copy_directory_content_sync.js";
68
+
69
+ // remove
70
+ export { ensureEmptyDirectory } from "./remove/ensure_empty_directory.js";
71
+ export { ensureEmptyDirectorySync } from "./remove/ensure_empty_directory_sync.js";
72
+ export { clearDirectorySync } from "./remove/clear_directory_sync.js";
73
+ export { removeDirectory } from "./remove/remove_directory.js";
74
+ export { removeFile } from "./remove/remove_file.js";
75
+ export { removeEntry } from "./remove/remove_entry.js";
76
+ export { removeDirectorySync } from "./remove/remove_directory_sync.js";
77
+ export { removeFileSync } from "./remove/remove_file_sync.js";
78
+ export { removeEntrySync } from "./remove/remove_entry_sync.js";
79
+
80
+ // lifecycle
81
+ export { registerDirectoryLifecycle } from "./lifecycle/register_directory_lifecycle.js";
82
+ export { registerFileLifecycle } from "./lifecycle/register_file_lifecycle.js";
83
+
84
+ // other
85
+ export { assertDirectoryPresence } from "./assert_directory_presence.js";
86
+ export { assertFilePresence } from "./assert_file_presence.js";
87
+ export { bufferToEtag } from "./buffer_to_etag.js";