@jsenv/filesystem 4.2.3 → 4.2.4
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/README.md +17 -17
- package/package.json +4 -4
- package/src/assertDirectoryPresence.js +10 -10
- package/src/assertFilePresence.js +10 -10
- package/src/bufferToEtag.js +11 -11
- package/src/collectDirectoryMatchReport.js +38 -38
- package/src/collectFiles.js +35 -35
- package/src/comparePathnames.js +23 -23
- package/src/copyDirectoryContent.js +37 -37
- package/src/copyEntry.js +88 -88
- package/src/directory_url_validation.js +14 -14
- package/src/ensureEmptyDirectory.js +13 -13
- package/src/ensureParentDirectories.js +9 -9
- package/src/ensureWindowsDriveLetter.js +19 -19
- package/src/fileSystemRootUrl.js +1 -1
- package/src/file_url_validation.js +14 -14
- package/src/getRealFileSystemUrlSync.js +24 -24
- package/src/grantPermissionsOnEntry.js +9 -9
- package/src/internal/createWatcher.js +12 -12
- package/src/internal/getCommandArgument.js +7 -7
- package/src/internal/guard_second_call.js +20 -20
- package/src/internal/permissions.js +26 -26
- package/src/internal/read_entry_info.js +8 -8
- package/src/internal/statsToType.js +9 -9
- package/src/internal/track_resources.js +12 -12
- package/src/internal/urlTargetsSameFileSystemPath.js +4 -4
- package/src/listFilesMatching.js +5 -5
- package/src/main.js +35 -35
- package/src/moveDirectoryContent.js +37 -37
- package/src/moveEntry.js +44 -44
- package/src/readDirectory.js +21 -21
- package/src/readEntryModificationTime.js +4 -4
- package/src/readEntryPermissions.js +10 -10
- package/src/readEntryStat.js +27 -27
- package/src/readFile.js +12 -12
- package/src/readFileSync.js +9 -9
- package/src/readSymbolicLink.js +9 -9
- package/src/registerDirectoryLifecycle.js +118 -118
- package/src/registerFileLifecycle.js +66 -66
- package/src/removeEntry.js +81 -81
- package/src/testEntryPermissions.js +15 -15
- package/src/writeDirectory.js +17 -17
- package/src/writeEntryModificationTime.js +10 -10
- package/src/writeEntryPermissions.js +26 -26
- package/src/writeFile.js +16 -16
- package/src/writeFileSync.js +10 -10
- package/src/writeSymbolicLink.js +39 -39
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { Abort } from "@jsenv/abort"
|
|
2
|
-
import { urlToFileSystemPath, resolveUrl } from "@jsenv/urls"
|
|
1
|
+
import { Abort } from "@jsenv/abort";
|
|
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 "./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";
|
|
11
11
|
|
|
12
12
|
export const copyDirectoryContent = async ({
|
|
13
13
|
signal = new AbortController().signal,
|
|
@@ -16,23 +16,23 @@ export const copyDirectoryContent = async ({
|
|
|
16
16
|
overwrite,
|
|
17
17
|
followLink = true,
|
|
18
18
|
} = {}) => {
|
|
19
|
-
const fromUrl = assertAndNormalizeDirectoryUrl(from)
|
|
20
|
-
const fromPath = urlToFileSystemPath(fromUrl)
|
|
21
|
-
let toUrl = assertAndNormalizeDirectoryUrl(to)
|
|
22
|
-
let toPath = urlToFileSystemPath(toUrl)
|
|
19
|
+
const fromUrl = assertAndNormalizeDirectoryUrl(from);
|
|
20
|
+
const fromPath = urlToFileSystemPath(fromUrl);
|
|
21
|
+
let toUrl = assertAndNormalizeDirectoryUrl(to);
|
|
22
|
+
let toPath = urlToFileSystemPath(toUrl);
|
|
23
23
|
|
|
24
24
|
const sourceStats = await readEntryStat(fromUrl, {
|
|
25
25
|
nullIfNotFound: true,
|
|
26
26
|
followLink: false,
|
|
27
|
-
})
|
|
27
|
+
});
|
|
28
28
|
if (!sourceStats) {
|
|
29
|
-
throw new Error(`no directory to copy content from at ${fromPath}`)
|
|
29
|
+
throw new Error(`no directory to copy content from at ${fromPath}`);
|
|
30
30
|
}
|
|
31
31
|
if (!sourceStats.isDirectory()) {
|
|
32
|
-
const sourceType = statsToType(sourceStats)
|
|
32
|
+
const sourceType = statsToType(sourceStats);
|
|
33
33
|
throw new Error(
|
|
34
34
|
`found a ${sourceType} instead of a directory at ${fromPath}`,
|
|
35
|
-
)
|
|
35
|
+
);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
let destinationStats = await readEntryStat(toUrl, {
|
|
@@ -40,41 +40,41 @@ export const copyDirectoryContent = async ({
|
|
|
40
40
|
// we force false here but in fact we will follow the destination link
|
|
41
41
|
// to know where we will actually move and detect useless move overrite etc..
|
|
42
42
|
followLink: false,
|
|
43
|
-
})
|
|
43
|
+
});
|
|
44
44
|
if (followLink && destinationStats && destinationStats.isSymbolicLink()) {
|
|
45
|
-
const linkTarget = await readSymbolicLink(toUrl)
|
|
46
|
-
toUrl = resolveUrl(linkTarget, toUrl)
|
|
47
|
-
toPath = urlToFileSystemPath(toUrl)
|
|
45
|
+
const linkTarget = await readSymbolicLink(toUrl);
|
|
46
|
+
toUrl = resolveUrl(linkTarget, toUrl);
|
|
47
|
+
toPath = urlToFileSystemPath(toUrl);
|
|
48
48
|
destinationStats = await readEntryStat(toUrl, {
|
|
49
49
|
nullIfNotFound: true,
|
|
50
|
-
})
|
|
50
|
+
});
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
if (destinationStats === null) {
|
|
54
|
-
throw new Error(`no directory to copy content into at ${toPath}`)
|
|
54
|
+
throw new Error(`no directory to copy content into at ${toPath}`);
|
|
55
55
|
}
|
|
56
56
|
if (!destinationStats.isDirectory()) {
|
|
57
|
-
const destinationType = statsToType(destinationStats)
|
|
57
|
+
const destinationType = statsToType(destinationStats);
|
|
58
58
|
throw new Error(
|
|
59
59
|
`destination leads to a ${destinationType} instead of a directory at ${toPath}`,
|
|
60
|
-
)
|
|
60
|
+
);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
if (urlTargetsSameFileSystemPath(fromUrl, toUrl)) {
|
|
64
64
|
throw new Error(
|
|
65
65
|
`cannot copy directory content, source and destination are the same (${fromPath})`,
|
|
66
|
-
)
|
|
66
|
+
);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
const copyOperation = Abort.startOperation()
|
|
70
|
-
copyOperation.addAbortSignal(signal)
|
|
69
|
+
const copyOperation = Abort.startOperation();
|
|
70
|
+
copyOperation.addAbortSignal(signal);
|
|
71
71
|
try {
|
|
72
|
-
copyOperation.throwIfAborted()
|
|
73
|
-
const directoryEntries = await readDirectory(fromUrl)
|
|
72
|
+
copyOperation.throwIfAborted();
|
|
73
|
+
const directoryEntries = await readDirectory(fromUrl);
|
|
74
74
|
await Promise.all(
|
|
75
75
|
directoryEntries.map(async (directoryEntry) => {
|
|
76
|
-
const from = resolveUrl(directoryEntry, fromUrl)
|
|
77
|
-
const to = resolveUrl(directoryEntry, toUrl)
|
|
76
|
+
const from = resolveUrl(directoryEntry, fromUrl);
|
|
77
|
+
const to = resolveUrl(directoryEntry, toUrl);
|
|
78
78
|
await copyOperation.withSignal(async (signal) => {
|
|
79
79
|
await copyEntry({
|
|
80
80
|
signal,
|
|
@@ -82,11 +82,11 @@ export const copyDirectoryContent = async ({
|
|
|
82
82
|
to,
|
|
83
83
|
overwrite,
|
|
84
84
|
followLink,
|
|
85
|
-
})
|
|
86
|
-
})
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
87
|
}),
|
|
88
|
-
)
|
|
88
|
+
);
|
|
89
89
|
} finally {
|
|
90
|
-
await copyOperation.end()
|
|
90
|
+
await copyOperation.end();
|
|
91
91
|
}
|
|
92
|
-
}
|
|
92
|
+
};
|
package/src/copyEntry.js
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import { copyFile as copyFileNode } from "node:fs"
|
|
2
|
-
import { Abort } from "@jsenv/abort"
|
|
1
|
+
import { copyFile as copyFileNode } from "node:fs";
|
|
2
|
+
import { Abort } from "@jsenv/abort";
|
|
3
3
|
import {
|
|
4
4
|
resolveUrl,
|
|
5
5
|
urlToRelativeUrl,
|
|
6
6
|
ensurePathnameTrailingSlash,
|
|
7
7
|
urlIsInsideOf,
|
|
8
8
|
urlToFileSystemPath,
|
|
9
|
-
} from "@jsenv/urls"
|
|
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"
|
|
9
|
+
} from "@jsenv/urls";
|
|
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";
|
|
24
24
|
|
|
25
25
|
export const copyEntry = async ({
|
|
26
26
|
signal = new AbortController().signal,
|
|
@@ -33,17 +33,17 @@ export const copyEntry = async ({
|
|
|
33
33
|
allowUseless = false,
|
|
34
34
|
followLink = true,
|
|
35
35
|
}) => {
|
|
36
|
-
const fromUrl = assertAndNormalizeFileUrl(from)
|
|
37
|
-
const fromPath = urlToFileSystemPath(fromUrl)
|
|
38
|
-
let toUrl = assertAndNormalizeFileUrl(to)
|
|
39
|
-
let toPath = urlToFileSystemPath(toUrl)
|
|
36
|
+
const fromUrl = assertAndNormalizeFileUrl(from);
|
|
37
|
+
const fromPath = urlToFileSystemPath(fromUrl);
|
|
38
|
+
let toUrl = assertAndNormalizeFileUrl(to);
|
|
39
|
+
let toPath = urlToFileSystemPath(toUrl);
|
|
40
40
|
|
|
41
41
|
const sourceStats = await readEntryStat(fromUrl, {
|
|
42
42
|
nullIfNotFound: true,
|
|
43
43
|
followLink: false,
|
|
44
|
-
})
|
|
44
|
+
});
|
|
45
45
|
if (!sourceStats) {
|
|
46
|
-
throw new Error(`nothing to copy at ${fromPath}`)
|
|
46
|
+
throw new Error(`nothing to copy at ${fromPath}`);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
let destinationStats = await readEntryStat(toUrl, {
|
|
@@ -51,82 +51,82 @@ export const copyEntry = async ({
|
|
|
51
51
|
// we force false here but in fact we will follow the destination link
|
|
52
52
|
// to know where we will actually move and detect useless move overrite etc..
|
|
53
53
|
followLink: false,
|
|
54
|
-
})
|
|
54
|
+
});
|
|
55
55
|
|
|
56
56
|
if (followLink && destinationStats && destinationStats.isSymbolicLink()) {
|
|
57
|
-
const linkTarget = await readSymbolicLink(toUrl)
|
|
58
|
-
toUrl = resolveUrl(linkTarget, toUrl)
|
|
59
|
-
toPath = urlToFileSystemPath(toUrl)
|
|
57
|
+
const linkTarget = await readSymbolicLink(toUrl);
|
|
58
|
+
toUrl = resolveUrl(linkTarget, toUrl);
|
|
59
|
+
toPath = urlToFileSystemPath(toUrl);
|
|
60
60
|
destinationStats = await readEntryStat(toUrl, {
|
|
61
61
|
nullIfNotFound: true,
|
|
62
|
-
})
|
|
62
|
+
});
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
if (urlTargetsSameFileSystemPath(fromUrl, toUrl)) {
|
|
66
66
|
if (allowUseless) {
|
|
67
|
-
return
|
|
67
|
+
return;
|
|
68
68
|
}
|
|
69
69
|
throw new Error(
|
|
70
70
|
`cannot copy ${fromPath} because destination and source are the same`,
|
|
71
|
-
)
|
|
71
|
+
);
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
if (sourceStats.isDirectory()) {
|
|
75
|
-
toUrl = ensurePathnameTrailingSlash(toUrl)
|
|
75
|
+
toUrl = ensurePathnameTrailingSlash(toUrl);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
const copyOperation = Abort.startOperation()
|
|
79
|
-
copyOperation.addAbortSignal(signal)
|
|
78
|
+
const copyOperation = Abort.startOperation();
|
|
79
|
+
copyOperation.addAbortSignal(signal);
|
|
80
80
|
|
|
81
81
|
const visit = async (url, stats) => {
|
|
82
|
-
copyOperation.throwIfAborted()
|
|
82
|
+
copyOperation.throwIfAborted();
|
|
83
83
|
if (stats.isFile() || stats.isCharacterDevice() || stats.isBlockDevice()) {
|
|
84
|
-
await visitFile(url, stats)
|
|
84
|
+
await visitFile(url, stats);
|
|
85
85
|
} else if (stats.isSymbolicLink()) {
|
|
86
|
-
await visitSymbolicLink(url, stats)
|
|
86
|
+
await visitSymbolicLink(url, stats);
|
|
87
87
|
} else if (stats.isDirectory()) {
|
|
88
|
-
await visitDirectory(ensurePathnameTrailingSlash(url), stats)
|
|
88
|
+
await visitDirectory(ensurePathnameTrailingSlash(url), stats);
|
|
89
89
|
}
|
|
90
|
-
}
|
|
90
|
+
};
|
|
91
91
|
|
|
92
92
|
const visitFile = async (fileUrl, fileStats) => {
|
|
93
|
-
const fileRelativeUrl = urlToRelativeUrl(fileUrl, fromUrl)
|
|
94
|
-
const fileCopyUrl = resolveUrl(fileRelativeUrl, toUrl)
|
|
93
|
+
const fileRelativeUrl = urlToRelativeUrl(fileUrl, fromUrl);
|
|
94
|
+
const fileCopyUrl = resolveUrl(fileRelativeUrl, toUrl);
|
|
95
95
|
|
|
96
96
|
await copyFileContentNaive(
|
|
97
97
|
urlToFileSystemPath(fileUrl),
|
|
98
98
|
urlToFileSystemPath(fileCopyUrl),
|
|
99
|
-
)
|
|
100
|
-
await copyStats(fileCopyUrl, fileStats)
|
|
101
|
-
}
|
|
99
|
+
);
|
|
100
|
+
await copyStats(fileCopyUrl, fileStats);
|
|
101
|
+
};
|
|
102
102
|
|
|
103
103
|
const visitSymbolicLink = async (symbolicLinkUrl) => {
|
|
104
|
-
const symbolicLinkRelativeUrl = urlToRelativeUrl(symbolicLinkUrl, fromUrl)
|
|
105
|
-
const symbolicLinkTarget = await readSymbolicLink(symbolicLinkUrl)
|
|
104
|
+
const symbolicLinkRelativeUrl = urlToRelativeUrl(symbolicLinkUrl, fromUrl);
|
|
105
|
+
const symbolicLinkTarget = await readSymbolicLink(symbolicLinkUrl);
|
|
106
106
|
const symbolicLinkTargetUrl = resolveUrl(
|
|
107
107
|
symbolicLinkTarget,
|
|
108
108
|
symbolicLinkUrl,
|
|
109
|
-
)
|
|
109
|
+
);
|
|
110
110
|
const linkIsRelative =
|
|
111
111
|
symbolicLinkTarget.startsWith("./") ||
|
|
112
|
-
symbolicLinkTarget.startsWith("../")
|
|
112
|
+
symbolicLinkTarget.startsWith("../");
|
|
113
113
|
|
|
114
|
-
let symbolicLinkCopyTarget
|
|
114
|
+
let symbolicLinkCopyTarget;
|
|
115
115
|
if (symbolicLinkTargetUrl === fromUrl) {
|
|
116
|
-
symbolicLinkCopyTarget = linkIsRelative ? symbolicLinkTarget : toUrl
|
|
116
|
+
symbolicLinkCopyTarget = linkIsRelative ? symbolicLinkTarget : toUrl;
|
|
117
117
|
} else if (urlIsInsideOf(symbolicLinkTargetUrl, fromUrl)) {
|
|
118
118
|
// symbolic link targets something inside the directory we want to copy
|
|
119
119
|
// reflects it inside the copied directory structure
|
|
120
120
|
const linkCopyTargetRelative = urlToRelativeUrl(
|
|
121
121
|
symbolicLinkTargetUrl,
|
|
122
122
|
fromUrl,
|
|
123
|
-
)
|
|
123
|
+
);
|
|
124
124
|
symbolicLinkCopyTarget = linkIsRelative
|
|
125
125
|
? `./${linkCopyTargetRelative}`
|
|
126
|
-
: resolveUrl(linkCopyTargetRelative, toUrl)
|
|
126
|
+
: resolveUrl(linkCopyTargetRelative, toUrl);
|
|
127
127
|
} else {
|
|
128
128
|
// symbolic link targets something outside the directory we want to copy
|
|
129
|
-
symbolicLinkCopyTarget = symbolicLinkTarget
|
|
129
|
+
symbolicLinkCopyTarget = symbolicLinkTarget;
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
// we must guess ourself the type of the symlink
|
|
@@ -135,65 +135,65 @@ export const copyEntry = async ({
|
|
|
135
135
|
const targetStats = await readEntryStat(symbolicLinkTargetUrl, {
|
|
136
136
|
nullIfNotFound: true,
|
|
137
137
|
followLink: false,
|
|
138
|
-
})
|
|
139
|
-
const linkType = targetStats && targetStats.isDirectory() ? "dir" : "file"
|
|
138
|
+
});
|
|
139
|
+
const linkType = targetStats && targetStats.isDirectory() ? "dir" : "file";
|
|
140
140
|
|
|
141
|
-
const symbolicLinkCopyUrl = resolveUrl(symbolicLinkRelativeUrl, toUrl)
|
|
141
|
+
const symbolicLinkCopyUrl = resolveUrl(symbolicLinkRelativeUrl, toUrl);
|
|
142
142
|
await writeSymbolicLink({
|
|
143
143
|
from: symbolicLinkCopyUrl,
|
|
144
144
|
to: symbolicLinkCopyTarget,
|
|
145
145
|
type: linkType,
|
|
146
|
-
})
|
|
147
|
-
}
|
|
146
|
+
});
|
|
147
|
+
};
|
|
148
148
|
|
|
149
149
|
const copyStats = async (toUrl, stats) => {
|
|
150
150
|
if (preservePermissions || preserveMtime) {
|
|
151
|
-
const { mode, mtimeMs } = stats
|
|
151
|
+
const { mode, mtimeMs } = stats;
|
|
152
152
|
if (preservePermissions) {
|
|
153
|
-
await writeEntryPermissions(toUrl, binaryFlagsToPermissions(mode))
|
|
153
|
+
await writeEntryPermissions(toUrl, binaryFlagsToPermissions(mode));
|
|
154
154
|
}
|
|
155
155
|
if (preserveMtime) {
|
|
156
|
-
await writeEntryModificationTime(toUrl, mtimeMs)
|
|
156
|
+
await writeEntryModificationTime(toUrl, mtimeMs);
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
|
-
}
|
|
159
|
+
};
|
|
160
160
|
|
|
161
161
|
const visitDirectory = async (directoryUrl, directoryStats) => {
|
|
162
|
-
const directoryRelativeUrl = urlToRelativeUrl(directoryUrl, fromUrl)
|
|
163
|
-
const directoryCopyUrl = resolveUrl(directoryRelativeUrl, toUrl)
|
|
162
|
+
const directoryRelativeUrl = urlToRelativeUrl(directoryUrl, fromUrl);
|
|
163
|
+
const directoryCopyUrl = resolveUrl(directoryRelativeUrl, toUrl);
|
|
164
164
|
|
|
165
|
-
await writeDirectory(directoryCopyUrl)
|
|
166
|
-
await copyDirectoryContent(directoryUrl)
|
|
167
|
-
await copyStats(directoryCopyUrl, directoryStats)
|
|
168
|
-
}
|
|
165
|
+
await writeDirectory(directoryCopyUrl);
|
|
166
|
+
await copyDirectoryContent(directoryUrl);
|
|
167
|
+
await copyStats(directoryCopyUrl, directoryStats);
|
|
168
|
+
};
|
|
169
169
|
|
|
170
170
|
const copyDirectoryContent = async (directoryUrl) => {
|
|
171
|
-
const names = await readDirectory(directoryUrl)
|
|
171
|
+
const names = await readDirectory(directoryUrl);
|
|
172
172
|
await Promise.all(
|
|
173
173
|
names.map(async (name) => {
|
|
174
|
-
const entryUrl = resolveUrl(name, directoryUrl)
|
|
174
|
+
const entryUrl = resolveUrl(name, directoryUrl);
|
|
175
175
|
const stats = await readEntryStat(entryUrl, {
|
|
176
176
|
followLink: false,
|
|
177
|
-
})
|
|
178
|
-
await visit(entryUrl, stats)
|
|
177
|
+
});
|
|
178
|
+
await visit(entryUrl, stats);
|
|
179
179
|
}),
|
|
180
|
-
)
|
|
181
|
-
}
|
|
180
|
+
);
|
|
181
|
+
};
|
|
182
182
|
|
|
183
183
|
try {
|
|
184
184
|
if (destinationStats) {
|
|
185
|
-
const sourceType = statsToType(sourceStats)
|
|
186
|
-
const destinationType = statsToType(destinationStats)
|
|
185
|
+
const sourceType = statsToType(sourceStats);
|
|
186
|
+
const destinationType = statsToType(destinationStats);
|
|
187
187
|
|
|
188
188
|
if (sourceType !== destinationType) {
|
|
189
189
|
throw new Error(
|
|
190
190
|
`cannot copy ${sourceType} from ${fromPath} to ${toPath} because destination exists and is not a ${sourceType} (it's a ${destinationType})`,
|
|
191
|
-
)
|
|
191
|
+
);
|
|
192
192
|
}
|
|
193
193
|
if (!overwrite) {
|
|
194
194
|
throw new Error(
|
|
195
195
|
`cannot copy ${sourceType} from ${fromPath} to ${toPath} because destination exists and overwrite option is disabled`,
|
|
196
|
-
)
|
|
196
|
+
);
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
// remove file, link, directory...
|
|
@@ -201,26 +201,26 @@ export const copyEntry = async ({
|
|
|
201
201
|
signal: copyOperation.signal,
|
|
202
202
|
recursive: true,
|
|
203
203
|
allowUseless: true,
|
|
204
|
-
})
|
|
204
|
+
});
|
|
205
205
|
} else {
|
|
206
|
-
await ensureParentDirectories(toUrl)
|
|
206
|
+
await ensureParentDirectories(toUrl);
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
-
copyOperation.throwIfAborted()
|
|
210
|
-
await visit(fromUrl, sourceStats)
|
|
209
|
+
copyOperation.throwIfAborted();
|
|
210
|
+
await visit(fromUrl, sourceStats);
|
|
211
211
|
} finally {
|
|
212
|
-
await copyOperation.end()
|
|
212
|
+
await copyOperation.end();
|
|
213
213
|
}
|
|
214
|
-
}
|
|
214
|
+
};
|
|
215
215
|
|
|
216
216
|
const copyFileContentNaive = (filePath, fileDestinationPath) => {
|
|
217
217
|
return new Promise((resolve, reject) => {
|
|
218
218
|
copyFileNode(filePath, fileDestinationPath, (error) => {
|
|
219
219
|
if (error) {
|
|
220
|
-
reject(error)
|
|
220
|
+
reject(error);
|
|
221
221
|
} else {
|
|
222
|
-
resolve()
|
|
222
|
+
resolve();
|
|
223
223
|
}
|
|
224
|
-
})
|
|
225
|
-
})
|
|
226
|
-
}
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
};
|
|
@@ -2,25 +2,25 @@ import {
|
|
|
2
2
|
fileSystemPathToUrl,
|
|
3
3
|
isFileSystemPath,
|
|
4
4
|
ensurePathnameTrailingSlash,
|
|
5
|
-
} from "@jsenv/urls"
|
|
5
|
+
} from "@jsenv/urls";
|
|
6
6
|
|
|
7
7
|
export const validateDirectoryUrl = (value) => {
|
|
8
|
-
let urlString
|
|
8
|
+
let urlString;
|
|
9
9
|
|
|
10
10
|
if (value instanceof URL) {
|
|
11
|
-
urlString = value.href
|
|
11
|
+
urlString = value.href;
|
|
12
12
|
} else if (typeof value === "string") {
|
|
13
13
|
if (isFileSystemPath(value)) {
|
|
14
|
-
urlString = fileSystemPathToUrl(value)
|
|
14
|
+
urlString = fileSystemPathToUrl(value);
|
|
15
15
|
} else {
|
|
16
16
|
try {
|
|
17
|
-
urlString = String(new URL(value))
|
|
17
|
+
urlString = String(new URL(value));
|
|
18
18
|
} catch (e) {
|
|
19
19
|
return {
|
|
20
20
|
valid: false,
|
|
21
21
|
value,
|
|
22
22
|
message: `must be a valid url`,
|
|
23
|
-
}
|
|
23
|
+
};
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
} else {
|
|
@@ -28,28 +28,28 @@ export const validateDirectoryUrl = (value) => {
|
|
|
28
28
|
valid: false,
|
|
29
29
|
value,
|
|
30
30
|
message: `must be a string or an url`,
|
|
31
|
-
}
|
|
31
|
+
};
|
|
32
32
|
}
|
|
33
33
|
if (!urlString.startsWith("file://")) {
|
|
34
34
|
return {
|
|
35
35
|
valid: false,
|
|
36
36
|
value,
|
|
37
37
|
message: 'must start with "file://"',
|
|
38
|
-
}
|
|
38
|
+
};
|
|
39
39
|
}
|
|
40
40
|
return {
|
|
41
41
|
valid: true,
|
|
42
42
|
value: ensurePathnameTrailingSlash(urlString),
|
|
43
|
-
}
|
|
44
|
-
}
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
45
|
|
|
46
46
|
export const assertAndNormalizeDirectoryUrl = (
|
|
47
47
|
directoryUrl,
|
|
48
48
|
name = "directoryUrl",
|
|
49
49
|
) => {
|
|
50
|
-
const { valid, message, value } = validateDirectoryUrl(directoryUrl)
|
|
50
|
+
const { valid, message, value } = validateDirectoryUrl(directoryUrl);
|
|
51
51
|
if (!valid) {
|
|
52
|
-
throw new TypeError(`${name} ${message}, got ${value}`)
|
|
52
|
+
throw new TypeError(`${name} ${message}, got ${value}`);
|
|
53
53
|
}
|
|
54
|
-
return value
|
|
55
|
-
}
|
|
54
|
+
return value;
|
|
55
|
+
};
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { urlToFileSystemPath } from "@jsenv/urls"
|
|
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 { writeDirectory } from "./writeDirectory.js"
|
|
6
|
-
import { readEntryStat } from "./readEntryStat.js"
|
|
7
|
-
import { removeEntry } from "./removeEntry.js"
|
|
3
|
+
import { assertAndNormalizeFileUrl } from "./file_url_validation.js";
|
|
4
|
+
import { statsToType } from "./internal/statsToType.js";
|
|
5
|
+
import { writeDirectory } from "./writeDirectory.js";
|
|
6
|
+
import { readEntryStat } from "./readEntryStat.js";
|
|
7
|
+
import { removeEntry } from "./removeEntry.js";
|
|
8
8
|
|
|
9
9
|
export const ensureEmptyDirectory = async (source) => {
|
|
10
10
|
const stats = await readEntryStat(source, {
|
|
11
11
|
nullIfNotFound: true,
|
|
12
12
|
followLink: false,
|
|
13
|
-
})
|
|
13
|
+
});
|
|
14
14
|
if (stats === null) {
|
|
15
15
|
// if there is nothing, create a directory
|
|
16
|
-
return writeDirectory(source, { allowUseless: true })
|
|
16
|
+
return writeDirectory(source, { allowUseless: true });
|
|
17
17
|
}
|
|
18
18
|
if (stats.isDirectory()) {
|
|
19
19
|
// if there is a directory remove its content and done
|
|
@@ -21,12 +21,12 @@ export const ensureEmptyDirectory = async (source) => {
|
|
|
21
21
|
allowUseless: true,
|
|
22
22
|
recursive: true,
|
|
23
23
|
onlyContent: true,
|
|
24
|
-
})
|
|
24
|
+
});
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
const sourceType = statsToType(stats)
|
|
28
|
-
const sourcePath = urlToFileSystemPath(assertAndNormalizeFileUrl(source))
|
|
27
|
+
const sourceType = statsToType(stats);
|
|
28
|
+
const sourcePath = urlToFileSystemPath(assertAndNormalizeFileUrl(source));
|
|
29
29
|
throw new Error(
|
|
30
30
|
`ensureEmptyDirectory expect directory at ${sourcePath}, found ${sourceType} instead`,
|
|
31
|
-
)
|
|
32
|
-
}
|
|
31
|
+
);
|
|
32
|
+
};
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { dirname } from "node:path"
|
|
2
|
-
import { urlToFileSystemPath } from "@jsenv/urls"
|
|
1
|
+
import { dirname } from "node:path";
|
|
2
|
+
import { urlToFileSystemPath } from "@jsenv/urls";
|
|
3
3
|
|
|
4
|
-
import { assertAndNormalizeFileUrl } from "./file_url_validation.js"
|
|
5
|
-
import { writeDirectory } from "./writeDirectory.js"
|
|
4
|
+
import { assertAndNormalizeFileUrl } from "./file_url_validation.js";
|
|
5
|
+
import { writeDirectory } from "./writeDirectory.js";
|
|
6
6
|
|
|
7
7
|
export const ensureParentDirectories = async (destination) => {
|
|
8
|
-
const destinationUrl = assertAndNormalizeFileUrl(destination)
|
|
9
|
-
const destinationPath = urlToFileSystemPath(destinationUrl)
|
|
10
|
-
const destinationParentPath = dirname(destinationPath)
|
|
8
|
+
const destinationUrl = assertAndNormalizeFileUrl(destination);
|
|
9
|
+
const destinationPath = urlToFileSystemPath(destinationUrl);
|
|
10
|
+
const destinationParentPath = dirname(destinationPath);
|
|
11
11
|
|
|
12
12
|
return writeDirectory(destinationParentPath, {
|
|
13
13
|
recursive: true,
|
|
14
14
|
allowUseless: true,
|
|
15
|
-
})
|
|
16
|
-
}
|
|
15
|
+
});
|
|
16
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { fileSystemPathToUrl } from "@jsenv/urls"
|
|
1
|
+
import { fileSystemPathToUrl } from "@jsenv/urls";
|
|
2
2
|
|
|
3
|
-
const isWindows = process.platform === "win32"
|
|
4
|
-
const baseUrlFallback = fileSystemPathToUrl(process.cwd())
|
|
3
|
+
const isWindows = process.platform === "win32";
|
|
4
|
+
const baseUrlFallback = fileSystemPathToUrl(process.cwd());
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Some url might be resolved or remapped to url without the windows drive letter.
|
|
@@ -18,51 +18,51 @@ const baseUrlFallback = fileSystemPathToUrl(process.cwd())
|
|
|
18
18
|
|
|
19
19
|
export const ensureWindowsDriveLetter = (url, baseUrl) => {
|
|
20
20
|
try {
|
|
21
|
-
url = String(new URL(url))
|
|
21
|
+
url = String(new URL(url));
|
|
22
22
|
} catch (e) {
|
|
23
|
-
throw new Error(`absolute url expected but got ${url}`)
|
|
23
|
+
throw new Error(`absolute url expected but got ${url}`);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
if (!isWindows) {
|
|
27
|
-
return url
|
|
27
|
+
return url;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
try {
|
|
31
|
-
baseUrl = String(new URL(baseUrl))
|
|
31
|
+
baseUrl = String(new URL(baseUrl));
|
|
32
32
|
} catch (e) {
|
|
33
33
|
throw new Error(
|
|
34
34
|
`absolute baseUrl expected but got ${baseUrl} to ensure windows drive letter on ${url}`,
|
|
35
|
-
)
|
|
35
|
+
);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
if (!url.startsWith("file://")) {
|
|
39
|
-
return url
|
|
39
|
+
return url;
|
|
40
40
|
}
|
|
41
|
-
const afterProtocol = url.slice("file://".length)
|
|
41
|
+
const afterProtocol = url.slice("file://".length);
|
|
42
42
|
// we still have the windows drive letter
|
|
43
43
|
if (extractDriveLetter(afterProtocol)) {
|
|
44
|
-
return url
|
|
44
|
+
return url;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
// drive letter was lost, restore it
|
|
48
48
|
const baseUrlOrFallback = baseUrl.startsWith("file://")
|
|
49
49
|
? baseUrl
|
|
50
|
-
: baseUrlFallback
|
|
50
|
+
: baseUrlFallback;
|
|
51
51
|
const driveLetter = extractDriveLetter(
|
|
52
52
|
baseUrlOrFallback.slice("file://".length),
|
|
53
|
-
)
|
|
53
|
+
);
|
|
54
54
|
if (!driveLetter) {
|
|
55
55
|
throw new Error(
|
|
56
56
|
`drive letter expected on baseUrl but got ${baseUrl} to ensure windows drive letter on ${url}`,
|
|
57
|
-
)
|
|
57
|
+
);
|
|
58
58
|
}
|
|
59
|
-
return `file:///${driveLetter}:${afterProtocol}
|
|
60
|
-
}
|
|
59
|
+
return `file:///${driveLetter}:${afterProtocol}`;
|
|
60
|
+
};
|
|
61
61
|
|
|
62
62
|
const extractDriveLetter = (resource) => {
|
|
63
63
|
// we still have the windows drive letter
|
|
64
64
|
if (/[a-zA-Z]/.test(resource[1]) && resource[2] === ":") {
|
|
65
|
-
return resource[1]
|
|
65
|
+
return resource[1];
|
|
66
66
|
}
|
|
67
|
-
return null
|
|
68
|
-
}
|
|
67
|
+
return null;
|
|
68
|
+
};
|
package/src/fileSystemRootUrl.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export const fileSystemRootUrl =
|
|
2
|
-
process.platform === "win32" ? `file:///${process.cwd()[0]}:/` : "file:///"
|
|
2
|
+
process.platform === "win32" ? `file:///${process.cwd()[0]}:/` : "file:///";
|