@jsenv/filesystem 4.8.2 → 4.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/filesystem",
3
- "version": "4.8.2",
3
+ "version": "4.9.1",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
package/src/main.js CHANGED
@@ -59,7 +59,10 @@ export { writeEntryModificationTimeSync } from "./read_write/stat/write_entry_mo
59
59
 
60
60
  // move
61
61
  export { moveDirectoryContent } from "./move/move_directory_content.js";
62
+ export { moveFile } from "./move/move_file.js";
62
63
  export { moveEntry } from "./move/move_entry.js";
64
+ export { moveFileSync } from "./move/move_file_sync.js";
65
+ export { moveEntrySync } from "./move/move_entry_sync.js";
63
66
 
64
67
  // copy
65
68
  export { copyEntry } from "./copy/copy_entry.js";
@@ -0,0 +1,115 @@
1
+ import { resolveUrl, urlToFileSystemPath } from "@jsenv/urls";
2
+ import { renameSync } from "node:fs";
3
+
4
+ import { copyEntry } from "../copy/copy_entry.js";
5
+ import { assertAndNormalizeFileUrl } from "../path_and_url/file_url_validation.js";
6
+ import { urlTargetsSameFileSystemPath } from "../path_and_url/url_targets_same_file_system_path.js";
7
+ import { ensureParentDirectoriesSync } from "../read_write/ensure_parent_directories_sync.js";
8
+ import { readSymbolicLinkSync } from "../read_write/read_symbolic_link_sync.js";
9
+ import { readEntryStatSync } from "../read_write/stat/read_entry_stat_sync.js";
10
+ import { statsToType } from "../read_write/stat/stats_to_type.js";
11
+ import { removeEntrySync } from "../remove/remove_entry_sync.js";
12
+
13
+ export const moveEntrySync = ({
14
+ from,
15
+ to,
16
+ overwrite = false,
17
+ allowUseless = false,
18
+ followLink = true,
19
+ noEntryEffect = "throw",
20
+ }) => {
21
+ const fromUrl = assertAndNormalizeFileUrl(from);
22
+ const fromPath = urlToFileSystemPath(fromUrl);
23
+ let toUrl = assertAndNormalizeFileUrl(to);
24
+ let toPath = urlToFileSystemPath(toUrl);
25
+
26
+ const sourceStats = readEntryStatSync(fromUrl, {
27
+ nullIfNotFound: true,
28
+ followLink: false,
29
+ });
30
+ if (!sourceStats) {
31
+ if (noEntryEffect === "throw") {
32
+ throw new Error(`nothing to move from ${fromPath}`);
33
+ }
34
+ return;
35
+ }
36
+
37
+ let destinationStats = readEntryStatSync(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
+
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 (urlTargetsSameFileSystemPath(fromUrl, toUrl)) {
54
+ if (allowUseless) {
55
+ return;
56
+ }
57
+ throw new Error(
58
+ `no move needed for ${fromPath} because destination and source are the same`,
59
+ );
60
+ }
61
+
62
+ if (destinationStats) {
63
+ const sourceType = statsToType(sourceStats);
64
+ const destinationType = statsToType(destinationStats);
65
+
66
+ if (sourceType !== destinationType) {
67
+ throw new Error(
68
+ `cannot move ${sourceType} from ${fromPath} to ${toPath} because destination exists and is not a ${sourceType} (it's a ${destinationType})`,
69
+ );
70
+ }
71
+ if (!overwrite) {
72
+ throw new Error(
73
+ `cannot move ${sourceType} from ${fromPath} to ${toPath} because destination exists and overwrite option is disabled`,
74
+ );
75
+ }
76
+
77
+ // remove file, link, directory...
78
+ removeEntrySync(toUrl, {
79
+ recursive: true,
80
+ });
81
+ } else {
82
+ ensureParentDirectoriesSync(toUrl);
83
+ }
84
+
85
+ moveNaiveSync(fromPath, toPath, {
86
+ handleCrossDeviceError: () => {
87
+ copyEntry({
88
+ from: fromUrl,
89
+ to: toUrl,
90
+ preserveStat: true,
91
+ });
92
+ removeEntrySync(fromUrl, {
93
+ recursive: true,
94
+ });
95
+ },
96
+ });
97
+ };
98
+
99
+ const moveNaiveSync = (
100
+ fromPath,
101
+ destinationPath,
102
+ { handleCrossDeviceError = null } = {},
103
+ ) => {
104
+ try {
105
+ renameSync(fromPath, destinationPath);
106
+ } catch (error) {
107
+ if (error) {
108
+ if (handleCrossDeviceError && error.code === "EXDEV") {
109
+ handleCrossDeviceError(error);
110
+ } else {
111
+ throw error;
112
+ }
113
+ }
114
+ }
115
+ };
@@ -0,0 +1,5 @@
1
+ import { moveEntry } from "./move_entry.js";
2
+
3
+ export const moveFile = async (options) => {
4
+ await moveEntry(options);
5
+ };
@@ -0,0 +1,5 @@
1
+ import { moveEntrySync } from "./move_entry_sync.js";
2
+
3
+ export const moveFileSync = (options) => {
4
+ moveEntrySync(options);
5
+ };
@@ -1,5 +1,5 @@
1
1
  import { removeEntry } from "./remove_entry.js";
2
2
 
3
- export const removeFile = (url, options) => {
4
- return removeEntry(url, options);
3
+ export const removeFile = async (url, options) => {
4
+ await removeEntry(url, options);
5
5
  };
@@ -1,5 +1,5 @@
1
1
  import { removeEntrySync } from "./remove_entry_sync.js";
2
2
 
3
3
  export const removeFileSync = (url, options) => {
4
- return removeEntrySync(url, options);
4
+ removeEntrySync(url, options);
5
5
  };