vscode-fs 0.0.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/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # vscode-fs
2
+
3
+ VSCode like simple、serializable and cross-platform file system utilities.
package/dist/index.cjs ADDED
@@ -0,0 +1,217 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ let vscode_uri = require("vscode-uri");
3
+
4
+ //#region src/types.ts
5
+ /**
6
+ * Enumeration of file types. The types `File` and `Directory` can also be
7
+ * a symbolic links, in that case use `FileType.File | FileType.SymbolicLink` and
8
+ * `FileType.Directory | FileType.SymbolicLink`.
9
+ */
10
+ let FileType = /* @__PURE__ */ function(FileType) {
11
+ /**
12
+ * The file type is unknown.
13
+ */
14
+ FileType[FileType["Unknown"] = 0] = "Unknown";
15
+ /**
16
+ * A regular file.
17
+ */
18
+ FileType[FileType["File"] = 1] = "File";
19
+ /**
20
+ * A directory.
21
+ */
22
+ FileType[FileType["Directory"] = 2] = "Directory";
23
+ /**
24
+ * A symbolic link to a file.
25
+ */
26
+ FileType[FileType["SymbolicLink"] = 64] = "SymbolicLink";
27
+ return FileType;
28
+ }({});
29
+ let FileSystemError;
30
+ (function(_FileSystemError) {
31
+ function isFileSystemError(error) {
32
+ return error instanceof FileSystemErrorImpl;
33
+ }
34
+ _FileSystemError.isFileSystemError = isFileSystemError;
35
+ })(FileSystemError || (FileSystemError = {}));
36
+ let FileSystemProviderErrorCode = /* @__PURE__ */ function(FileSystemProviderErrorCode) {
37
+ FileSystemProviderErrorCode["FileExists"] = "EntryExists";
38
+ FileSystemProviderErrorCode["FileNotFound"] = "EntryNotFound";
39
+ FileSystemProviderErrorCode["FileNotADirectory"] = "EntryNotADirectory";
40
+ FileSystemProviderErrorCode["FileIsADirectory"] = "EntryIsADirectory";
41
+ FileSystemProviderErrorCode["FileExceedsStorageQuota"] = "EntryExceedsStorageQuota";
42
+ FileSystemProviderErrorCode["FileTooLarge"] = "EntryTooLarge";
43
+ FileSystemProviderErrorCode["FileWriteLocked"] = "EntryWriteLocked";
44
+ FileSystemProviderErrorCode["NoPermissions"] = "NoPermissions";
45
+ FileSystemProviderErrorCode["Unavailable"] = "Unavailable";
46
+ FileSystemProviderErrorCode["Unknown"] = "Unknown";
47
+ return FileSystemProviderErrorCode;
48
+ }({});
49
+
50
+ //#endregion
51
+ //#region src/error.ts
52
+ var FileSystemErrorImpl = class FileSystemErrorImpl extends Error {
53
+ static create(error, code) {
54
+ const providerError = new FileSystemErrorImpl(error.toString(), code);
55
+ this.markAsFileSystemProviderError(providerError, code);
56
+ return providerError;
57
+ }
58
+ static markAsFileSystemProviderError(error, code) {
59
+ error.name = code ? `${code} (FileSystemError)` : `FileSystemError`;
60
+ return error;
61
+ }
62
+ constructor(message, code) {
63
+ super(message);
64
+ this.code = code;
65
+ }
66
+ };
67
+ function createFileSystemError(error, code) {
68
+ return FileSystemErrorImpl.create(error, code);
69
+ }
70
+ function toFileSystemError(error) {
71
+ let resultError = error;
72
+ let code;
73
+ switch (error.code) {
74
+ case "ENOENT":
75
+ code = FileSystemProviderErrorCode.FileNotFound;
76
+ break;
77
+ case "EISDIR":
78
+ code = FileSystemProviderErrorCode.FileIsADirectory;
79
+ break;
80
+ case "ENOTDIR":
81
+ code = FileSystemProviderErrorCode.FileNotADirectory;
82
+ break;
83
+ case "EEXIST":
84
+ code = FileSystemProviderErrorCode.FileExists;
85
+ break;
86
+ case "EPERM":
87
+ case "EACCES":
88
+ code = FileSystemProviderErrorCode.NoPermissions;
89
+ break;
90
+ case "ERR_UNC_HOST_NOT_ALLOWED":
91
+ resultError = `${error.message}. Please update the 'security.allowedUNCHosts' setting if you want to allow this host.`;
92
+ code = FileSystemProviderErrorCode.Unknown;
93
+ break;
94
+ default: code = FileSystemProviderErrorCode.Unknown;
95
+ }
96
+ return createFileSystemError(resultError, code);
97
+ }
98
+
99
+ //#endregion
100
+ //#region src/node.ts
101
+ function isErrnoException(err) {
102
+ return err !== null && typeof err === "object" && "code" in err;
103
+ }
104
+ function toFileType(stats) {
105
+ if (stats.isFile()) return FileType.File;
106
+ if (stats.isDirectory()) return FileType.Directory;
107
+ if (stats.isSymbolicLink()) return FileType.SymbolicLink;
108
+ return FileType.Unknown;
109
+ }
110
+ async function wrap(fn) {
111
+ try {
112
+ return await fn();
113
+ } catch (error) {
114
+ if (FileSystemError.isFileSystemError(error)) throw error;
115
+ throw toFileSystemError(error);
116
+ }
117
+ }
118
+ function joinPath(basePath, ...segments) {
119
+ return vscode_uri.Utils.joinPath(vscode_uri.URI.file(basePath), ...segments).fsPath;
120
+ }
121
+ async function createNodeFileSystem() {
122
+ const [fs, trash] = await Promise.all([import("node:fs"), import("trash").then((m) => m.default)]);
123
+ async function resolveFileType(path) {
124
+ const lstats = await fs.promises.lstat(path);
125
+ if (!lstats.isSymbolicLink()) return {
126
+ type: toFileType(lstats),
127
+ stats: lstats
128
+ };
129
+ let targetStats = null;
130
+ try {
131
+ targetStats = await fs.promises.stat(path);
132
+ } catch {}
133
+ const baseType = targetStats ? toFileType(targetStats) : FileType.Unknown;
134
+ const stats = targetStats ?? lstats;
135
+ return {
136
+ type: baseType | FileType.SymbolicLink,
137
+ stats
138
+ };
139
+ }
140
+ async function getEntryType(dirPath, entry) {
141
+ if (!entry.isSymbolicLink()) return toFileType(entry);
142
+ try {
143
+ return toFileType(await fs.promises.stat(joinPath(dirPath, entry.name))) | FileType.SymbolicLink;
144
+ } catch {
145
+ return FileType.SymbolicLink;
146
+ }
147
+ }
148
+ async function ensureTargetNotExists(path) {
149
+ try {
150
+ await fs.promises.access(path, fs.constants.F_OK);
151
+ throw createFileSystemError(`File exists: ${path}`, FileSystemProviderErrorCode.FileExists);
152
+ } catch (err) {
153
+ if (isErrnoException(err) && err.code !== "ENOENT") throw err;
154
+ }
155
+ }
156
+ async function copyRecursive(sourcePath, targetPath, overwrite) {
157
+ const stats = await fs.promises.stat(sourcePath);
158
+ if (stats.isFile()) {
159
+ const mode = overwrite ? void 0 : fs.constants.COPYFILE_EXCL;
160
+ await fs.promises.copyFile(sourcePath, targetPath, mode);
161
+ return;
162
+ }
163
+ if (stats.isDirectory()) {
164
+ if (!overwrite) await ensureTargetNotExists(targetPath);
165
+ await fs.promises.mkdir(targetPath, { recursive: true });
166
+ const entries = await fs.promises.readdir(sourcePath, { withFileTypes: true });
167
+ for (const entry of entries) await copyRecursive(joinPath(sourcePath, entry.name), joinPath(targetPath, entry.name), overwrite);
168
+ return;
169
+ }
170
+ throw createFileSystemError(`Unsupported file type: ${sourcePath}`, FileSystemProviderErrorCode.Unknown);
171
+ }
172
+ return {
173
+ stat: (uri) => wrap(async () => {
174
+ const { type, stats } = await resolveFileType(uri.fsPath);
175
+ return {
176
+ type,
177
+ ctime: stats.birthtime.getTime(),
178
+ mtime: stats.mtime.getTime(),
179
+ size: stats.size
180
+ };
181
+ }),
182
+ readDirectory: (uri) => wrap(async () => {
183
+ const entries = await fs.promises.readdir(uri.fsPath, { withFileTypes: true });
184
+ return Promise.all(entries.map(async (entry) => [entry.name, await getEntryType(uri.fsPath, entry)]));
185
+ }),
186
+ createDirectory: (uri) => wrap(async () => {
187
+ await fs.promises.mkdir(uri.fsPath, { recursive: true });
188
+ }),
189
+ readFile: (uri) => wrap(() => fs.promises.readFile(uri.fsPath)),
190
+ writeFile: (uri, content) => wrap(() => fs.promises.writeFile(uri.fsPath, content)),
191
+ delete: (uri, options) => wrap(async () => {
192
+ if (options?.useTrash) await trash(uri.fsPath);
193
+ else await fs.promises.rm(uri.fsPath, { recursive: options?.recursive });
194
+ }),
195
+ rename: (source, target, options) => wrap(async () => {
196
+ if (options?.overwrite === false) await ensureTargetNotExists(target.fsPath);
197
+ await fs.promises.rename(source.fsPath, target.fsPath);
198
+ }),
199
+ copy: (source, target, options) => wrap(async () => {
200
+ const overwrite = options?.overwrite !== false;
201
+ await copyRecursive(source.fsPath, target.fsPath, overwrite);
202
+ })
203
+ };
204
+ }
205
+
206
+ //#endregion
207
+ Object.defineProperty(exports, 'FileSystemError', {
208
+ enumerable: true,
209
+ get: function () {
210
+ return FileSystemError;
211
+ }
212
+ });
213
+ exports.FileSystemProviderErrorCode = FileSystemProviderErrorCode;
214
+ exports.FileType = FileType;
215
+ exports.createFileSystemError = createFileSystemError;
216
+ exports.createNodeFileSystem = createNodeFileSystem;
217
+ exports.toFileSystemError = toFileSystemError;
@@ -0,0 +1,188 @@
1
+ import { URI } from "vscode-uri";
2
+
3
+ //#region src/types.d.ts
4
+ /**
5
+ * Enumeration of file types. The types `File` and `Directory` can also be
6
+ * a symbolic links, in that case use `FileType.File | FileType.SymbolicLink` and
7
+ * `FileType.Directory | FileType.SymbolicLink`.
8
+ */
9
+ declare enum FileType {
10
+ /**
11
+ * The file type is unknown.
12
+ */
13
+ Unknown = 0,
14
+ /**
15
+ * A regular file.
16
+ */
17
+ File = 1,
18
+ /**
19
+ * A directory.
20
+ */
21
+ Directory = 2,
22
+ /**
23
+ * A symbolic link to a file.
24
+ */
25
+ SymbolicLink = 64
26
+ }
27
+ /**
28
+ * The file system interface exposes the editor's built-in and contributed
29
+ * {@link FileSystemProvider file system providers}. It allows extensions to work
30
+ * with files from the local disk as well as files from remote places, like the
31
+ * remote extension host or ftp-servers.
32
+ */
33
+ interface FileSystem {
34
+ /**
35
+ * Retrieve metadata about a file.
36
+ *
37
+ * @param uri The uri of the file to retrieve metadata about.
38
+ * @returns The file metadata about the file.
39
+ */
40
+ stat(uri: URI): Promise<FileStat>;
41
+ /**
42
+ * Retrieve all entries of a {@link FileType.Directory directory}.
43
+ *
44
+ * @param uri The uri of the folder.
45
+ * @returns An array of name/type-tuples or a thenable that resolves to such.
46
+ */
47
+ readDirectory(uri: URI): Promise<[string, FileType][]>;
48
+ /**
49
+ * Create a new directory (Note, that new files are created via `write`-calls).
50
+ *
51
+ * Note* that missing directories are created automatically, e.g this call has
52
+ * `mkdirp` semantics.
53
+ *
54
+ * @param uri The uri of the new folder.
55
+ */
56
+ createDirectory(uri: URI): Promise<void>;
57
+ /**
58
+ * Read the entire contents of a file.
59
+ *
60
+ * @param uri The uri of the file.
61
+ * @returns An array of bytes or a thenable that resolves to such.
62
+ */
63
+ readFile(uri: URI): Promise<Uint8Array>;
64
+ /**
65
+ * Write data to a file, replacing its entire contents.
66
+ *
67
+ * @param uri The uri of the file.
68
+ * @param content The new content of the file.
69
+ */
70
+ writeFile(uri: URI, content: Uint8Array): Promise<void>;
71
+ /**
72
+ * Delete a file.
73
+ *
74
+ * @param uri The resource that is to be deleted.
75
+ * @param options Defines if trash can should be used and if deletion of folders is recursive
76
+ * @param options.recursive Delete the content recursively if a folder is denoted.
77
+ * @param options.useTrash Use the os's trashcan instead of permanently deleting files whenever possible.
78
+ */
79
+ delete(uri: URI, options?: {
80
+ /**
81
+ * Delete the content recursively if a folder is denoted.
82
+ */
83
+ recursive?: boolean;
84
+ /**
85
+ * Use the os's trashcan instead of permanently deleting files whenever possible.
86
+ */
87
+ useTrash?: boolean;
88
+ }): Promise<void>;
89
+ /**
90
+ * Rename a file or folder.
91
+ *
92
+ * @param source The existing file.
93
+ * @param target The new location.
94
+ * @param options Defines if existing files should be overwritten.
95
+ * @param options.overwrite Overwrite the file if it does exist.
96
+ */
97
+ rename(source: URI, target: URI, options?: {
98
+ /**
99
+ * Overwrite the file if it does exist.
100
+ */
101
+ overwrite?: boolean;
102
+ }): Promise<void>;
103
+ /**
104
+ * Copy files or folders.
105
+ *
106
+ * @param source The existing file.
107
+ * @param target The destination location.
108
+ * @param options Defines if existing files should be overwritten.
109
+ * @param options.overwrite Overwrite the file if it does exist.
110
+ */
111
+ copy(source: URI, target: URI, options?: {
112
+ /**
113
+ * Overwrite the file if it does exist.
114
+ */
115
+ overwrite?: boolean;
116
+ }): Promise<void>;
117
+ }
118
+ /**
119
+ * The `FileStat`-type represents metadata about a file
120
+ */
121
+ interface FileStat {
122
+ /**
123
+ * The type of the file, e.g. is a regular file, a directory, or symbolic link
124
+ * to a file.
125
+ *
126
+ * Note:* This value might be a bitmask, e.g. `FileType.File | FileType.SymbolicLink`.
127
+ */
128
+ type: FileType;
129
+ /**
130
+ * The creation timestamp in milliseconds elapsed since January 1, 1970 00:00:00 UTC.
131
+ */
132
+ ctime: number;
133
+ /**
134
+ * The modification timestamp in milliseconds elapsed since January 1, 1970 00:00:00 UTC.
135
+ *
136
+ * Note:* If the file changed, it is important to provide an updated `mtime` that advanced
137
+ * from the previous value. Otherwise there may be optimizations in place that will not show
138
+ * the updated file contents in an editor for example.
139
+ */
140
+ mtime: number;
141
+ /**
142
+ * The size in bytes.
143
+ *
144
+ * Note:* If the file changed, it is important to provide an updated `size`. Otherwise there
145
+ * may be optimizations in place that will not show the updated file contents in an editor for
146
+ * example.
147
+ */
148
+ size: number;
149
+ }
150
+ /**
151
+ * A type that filesystem providers should use to signal errors.
152
+ *
153
+ * This class has factory methods for common error-cases, like `FileNotFound` when
154
+ * a file or folder doesn't exist, use them like so: `throw vscode.FileSystemError.FileNotFound(someUri);`
155
+ */
156
+ interface FileSystemError extends Error {
157
+ /**
158
+ * A code that identifies this error.
159
+ *
160
+ * Possible values are names of errors, like {@linkcode FileSystemError.FileNotFound FileNotFound},
161
+ * or `Unknown` for unspecified errors.
162
+ */
163
+ readonly code: string;
164
+ }
165
+ declare namespace FileSystemError {
166
+ function isFileSystemError(error: unknown): error is FileSystemError;
167
+ }
168
+ declare enum FileSystemProviderErrorCode {
169
+ FileExists = "EntryExists",
170
+ FileNotFound = "EntryNotFound",
171
+ FileNotADirectory = "EntryNotADirectory",
172
+ FileIsADirectory = "EntryIsADirectory",
173
+ FileExceedsStorageQuota = "EntryExceedsStorageQuota",
174
+ FileTooLarge = "EntryTooLarge",
175
+ FileWriteLocked = "EntryWriteLocked",
176
+ NoPermissions = "NoPermissions",
177
+ Unavailable = "Unavailable",
178
+ Unknown = "Unknown"
179
+ }
180
+ //#endregion
181
+ //#region src/error.d.ts
182
+ declare function createFileSystemError(error: Error | string, code: FileSystemProviderErrorCode): FileSystemError;
183
+ declare function toFileSystemError(error: NodeJS.ErrnoException): FileSystemError;
184
+ //#endregion
185
+ //#region src/node.d.ts
186
+ declare function createNodeFileSystem(): Promise<FileSystem>;
187
+ //#endregion
188
+ export { FileStat, FileSystem, FileSystemError, FileSystemProviderErrorCode, FileType, createFileSystemError, createNodeFileSystem, toFileSystemError };
@@ -0,0 +1,188 @@
1
+ import { URI } from "vscode-uri";
2
+
3
+ //#region src/types.d.ts
4
+ /**
5
+ * Enumeration of file types. The types `File` and `Directory` can also be
6
+ * a symbolic links, in that case use `FileType.File | FileType.SymbolicLink` and
7
+ * `FileType.Directory | FileType.SymbolicLink`.
8
+ */
9
+ declare enum FileType {
10
+ /**
11
+ * The file type is unknown.
12
+ */
13
+ Unknown = 0,
14
+ /**
15
+ * A regular file.
16
+ */
17
+ File = 1,
18
+ /**
19
+ * A directory.
20
+ */
21
+ Directory = 2,
22
+ /**
23
+ * A symbolic link to a file.
24
+ */
25
+ SymbolicLink = 64
26
+ }
27
+ /**
28
+ * The file system interface exposes the editor's built-in and contributed
29
+ * {@link FileSystemProvider file system providers}. It allows extensions to work
30
+ * with files from the local disk as well as files from remote places, like the
31
+ * remote extension host or ftp-servers.
32
+ */
33
+ interface FileSystem {
34
+ /**
35
+ * Retrieve metadata about a file.
36
+ *
37
+ * @param uri The uri of the file to retrieve metadata about.
38
+ * @returns The file metadata about the file.
39
+ */
40
+ stat(uri: URI): Promise<FileStat>;
41
+ /**
42
+ * Retrieve all entries of a {@link FileType.Directory directory}.
43
+ *
44
+ * @param uri The uri of the folder.
45
+ * @returns An array of name/type-tuples or a thenable that resolves to such.
46
+ */
47
+ readDirectory(uri: URI): Promise<[string, FileType][]>;
48
+ /**
49
+ * Create a new directory (Note, that new files are created via `write`-calls).
50
+ *
51
+ * Note* that missing directories are created automatically, e.g this call has
52
+ * `mkdirp` semantics.
53
+ *
54
+ * @param uri The uri of the new folder.
55
+ */
56
+ createDirectory(uri: URI): Promise<void>;
57
+ /**
58
+ * Read the entire contents of a file.
59
+ *
60
+ * @param uri The uri of the file.
61
+ * @returns An array of bytes or a thenable that resolves to such.
62
+ */
63
+ readFile(uri: URI): Promise<Uint8Array>;
64
+ /**
65
+ * Write data to a file, replacing its entire contents.
66
+ *
67
+ * @param uri The uri of the file.
68
+ * @param content The new content of the file.
69
+ */
70
+ writeFile(uri: URI, content: Uint8Array): Promise<void>;
71
+ /**
72
+ * Delete a file.
73
+ *
74
+ * @param uri The resource that is to be deleted.
75
+ * @param options Defines if trash can should be used and if deletion of folders is recursive
76
+ * @param options.recursive Delete the content recursively if a folder is denoted.
77
+ * @param options.useTrash Use the os's trashcan instead of permanently deleting files whenever possible.
78
+ */
79
+ delete(uri: URI, options?: {
80
+ /**
81
+ * Delete the content recursively if a folder is denoted.
82
+ */
83
+ recursive?: boolean;
84
+ /**
85
+ * Use the os's trashcan instead of permanently deleting files whenever possible.
86
+ */
87
+ useTrash?: boolean;
88
+ }): Promise<void>;
89
+ /**
90
+ * Rename a file or folder.
91
+ *
92
+ * @param source The existing file.
93
+ * @param target The new location.
94
+ * @param options Defines if existing files should be overwritten.
95
+ * @param options.overwrite Overwrite the file if it does exist.
96
+ */
97
+ rename(source: URI, target: URI, options?: {
98
+ /**
99
+ * Overwrite the file if it does exist.
100
+ */
101
+ overwrite?: boolean;
102
+ }): Promise<void>;
103
+ /**
104
+ * Copy files or folders.
105
+ *
106
+ * @param source The existing file.
107
+ * @param target The destination location.
108
+ * @param options Defines if existing files should be overwritten.
109
+ * @param options.overwrite Overwrite the file if it does exist.
110
+ */
111
+ copy(source: URI, target: URI, options?: {
112
+ /**
113
+ * Overwrite the file if it does exist.
114
+ */
115
+ overwrite?: boolean;
116
+ }): Promise<void>;
117
+ }
118
+ /**
119
+ * The `FileStat`-type represents metadata about a file
120
+ */
121
+ interface FileStat {
122
+ /**
123
+ * The type of the file, e.g. is a regular file, a directory, or symbolic link
124
+ * to a file.
125
+ *
126
+ * Note:* This value might be a bitmask, e.g. `FileType.File | FileType.SymbolicLink`.
127
+ */
128
+ type: FileType;
129
+ /**
130
+ * The creation timestamp in milliseconds elapsed since January 1, 1970 00:00:00 UTC.
131
+ */
132
+ ctime: number;
133
+ /**
134
+ * The modification timestamp in milliseconds elapsed since January 1, 1970 00:00:00 UTC.
135
+ *
136
+ * Note:* If the file changed, it is important to provide an updated `mtime` that advanced
137
+ * from the previous value. Otherwise there may be optimizations in place that will not show
138
+ * the updated file contents in an editor for example.
139
+ */
140
+ mtime: number;
141
+ /**
142
+ * The size in bytes.
143
+ *
144
+ * Note:* If the file changed, it is important to provide an updated `size`. Otherwise there
145
+ * may be optimizations in place that will not show the updated file contents in an editor for
146
+ * example.
147
+ */
148
+ size: number;
149
+ }
150
+ /**
151
+ * A type that filesystem providers should use to signal errors.
152
+ *
153
+ * This class has factory methods for common error-cases, like `FileNotFound` when
154
+ * a file or folder doesn't exist, use them like so: `throw vscode.FileSystemError.FileNotFound(someUri);`
155
+ */
156
+ interface FileSystemError extends Error {
157
+ /**
158
+ * A code that identifies this error.
159
+ *
160
+ * Possible values are names of errors, like {@linkcode FileSystemError.FileNotFound FileNotFound},
161
+ * or `Unknown` for unspecified errors.
162
+ */
163
+ readonly code: string;
164
+ }
165
+ declare namespace FileSystemError {
166
+ function isFileSystemError(error: unknown): error is FileSystemError;
167
+ }
168
+ declare enum FileSystemProviderErrorCode {
169
+ FileExists = "EntryExists",
170
+ FileNotFound = "EntryNotFound",
171
+ FileNotADirectory = "EntryNotADirectory",
172
+ FileIsADirectory = "EntryIsADirectory",
173
+ FileExceedsStorageQuota = "EntryExceedsStorageQuota",
174
+ FileTooLarge = "EntryTooLarge",
175
+ FileWriteLocked = "EntryWriteLocked",
176
+ NoPermissions = "NoPermissions",
177
+ Unavailable = "Unavailable",
178
+ Unknown = "Unknown"
179
+ }
180
+ //#endregion
181
+ //#region src/error.d.ts
182
+ declare function createFileSystemError(error: Error | string, code: FileSystemProviderErrorCode): FileSystemError;
183
+ declare function toFileSystemError(error: NodeJS.ErrnoException): FileSystemError;
184
+ //#endregion
185
+ //#region src/node.d.ts
186
+ declare function createNodeFileSystem(): Promise<FileSystem>;
187
+ //#endregion
188
+ export { FileStat, FileSystem, FileSystemError, FileSystemProviderErrorCode, FileType, createFileSystemError, createNodeFileSystem, toFileSystemError };
package/dist/index.mjs ADDED
@@ -0,0 +1,206 @@
1
+ import { URI, Utils } from "vscode-uri";
2
+
3
+ //#region src/types.ts
4
+ /**
5
+ * Enumeration of file types. The types `File` and `Directory` can also be
6
+ * a symbolic links, in that case use `FileType.File | FileType.SymbolicLink` and
7
+ * `FileType.Directory | FileType.SymbolicLink`.
8
+ */
9
+ let FileType = /* @__PURE__ */ function(FileType) {
10
+ /**
11
+ * The file type is unknown.
12
+ */
13
+ FileType[FileType["Unknown"] = 0] = "Unknown";
14
+ /**
15
+ * A regular file.
16
+ */
17
+ FileType[FileType["File"] = 1] = "File";
18
+ /**
19
+ * A directory.
20
+ */
21
+ FileType[FileType["Directory"] = 2] = "Directory";
22
+ /**
23
+ * A symbolic link to a file.
24
+ */
25
+ FileType[FileType["SymbolicLink"] = 64] = "SymbolicLink";
26
+ return FileType;
27
+ }({});
28
+ let FileSystemError;
29
+ (function(_FileSystemError) {
30
+ function isFileSystemError(error) {
31
+ return error instanceof FileSystemErrorImpl;
32
+ }
33
+ _FileSystemError.isFileSystemError = isFileSystemError;
34
+ })(FileSystemError || (FileSystemError = {}));
35
+ let FileSystemProviderErrorCode = /* @__PURE__ */ function(FileSystemProviderErrorCode) {
36
+ FileSystemProviderErrorCode["FileExists"] = "EntryExists";
37
+ FileSystemProviderErrorCode["FileNotFound"] = "EntryNotFound";
38
+ FileSystemProviderErrorCode["FileNotADirectory"] = "EntryNotADirectory";
39
+ FileSystemProviderErrorCode["FileIsADirectory"] = "EntryIsADirectory";
40
+ FileSystemProviderErrorCode["FileExceedsStorageQuota"] = "EntryExceedsStorageQuota";
41
+ FileSystemProviderErrorCode["FileTooLarge"] = "EntryTooLarge";
42
+ FileSystemProviderErrorCode["FileWriteLocked"] = "EntryWriteLocked";
43
+ FileSystemProviderErrorCode["NoPermissions"] = "NoPermissions";
44
+ FileSystemProviderErrorCode["Unavailable"] = "Unavailable";
45
+ FileSystemProviderErrorCode["Unknown"] = "Unknown";
46
+ return FileSystemProviderErrorCode;
47
+ }({});
48
+
49
+ //#endregion
50
+ //#region src/error.ts
51
+ var FileSystemErrorImpl = class FileSystemErrorImpl extends Error {
52
+ static create(error, code) {
53
+ const providerError = new FileSystemErrorImpl(error.toString(), code);
54
+ this.markAsFileSystemProviderError(providerError, code);
55
+ return providerError;
56
+ }
57
+ static markAsFileSystemProviderError(error, code) {
58
+ error.name = code ? `${code} (FileSystemError)` : `FileSystemError`;
59
+ return error;
60
+ }
61
+ constructor(message, code) {
62
+ super(message);
63
+ this.code = code;
64
+ }
65
+ };
66
+ function createFileSystemError(error, code) {
67
+ return FileSystemErrorImpl.create(error, code);
68
+ }
69
+ function toFileSystemError(error) {
70
+ let resultError = error;
71
+ let code;
72
+ switch (error.code) {
73
+ case "ENOENT":
74
+ code = FileSystemProviderErrorCode.FileNotFound;
75
+ break;
76
+ case "EISDIR":
77
+ code = FileSystemProviderErrorCode.FileIsADirectory;
78
+ break;
79
+ case "ENOTDIR":
80
+ code = FileSystemProviderErrorCode.FileNotADirectory;
81
+ break;
82
+ case "EEXIST":
83
+ code = FileSystemProviderErrorCode.FileExists;
84
+ break;
85
+ case "EPERM":
86
+ case "EACCES":
87
+ code = FileSystemProviderErrorCode.NoPermissions;
88
+ break;
89
+ case "ERR_UNC_HOST_NOT_ALLOWED":
90
+ resultError = `${error.message}. Please update the 'security.allowedUNCHosts' setting if you want to allow this host.`;
91
+ code = FileSystemProviderErrorCode.Unknown;
92
+ break;
93
+ default: code = FileSystemProviderErrorCode.Unknown;
94
+ }
95
+ return createFileSystemError(resultError, code);
96
+ }
97
+
98
+ //#endregion
99
+ //#region src/node.ts
100
+ function isErrnoException(err) {
101
+ return err !== null && typeof err === "object" && "code" in err;
102
+ }
103
+ function toFileType(stats) {
104
+ if (stats.isFile()) return FileType.File;
105
+ if (stats.isDirectory()) return FileType.Directory;
106
+ if (stats.isSymbolicLink()) return FileType.SymbolicLink;
107
+ return FileType.Unknown;
108
+ }
109
+ async function wrap(fn) {
110
+ try {
111
+ return await fn();
112
+ } catch (error) {
113
+ if (FileSystemError.isFileSystemError(error)) throw error;
114
+ throw toFileSystemError(error);
115
+ }
116
+ }
117
+ function joinPath(basePath, ...segments) {
118
+ return Utils.joinPath(URI.file(basePath), ...segments).fsPath;
119
+ }
120
+ async function createNodeFileSystem() {
121
+ const [fs, trash] = await Promise.all([import("node:fs"), import("trash").then((m) => m.default)]);
122
+ async function resolveFileType(path) {
123
+ const lstats = await fs.promises.lstat(path);
124
+ if (!lstats.isSymbolicLink()) return {
125
+ type: toFileType(lstats),
126
+ stats: lstats
127
+ };
128
+ let targetStats = null;
129
+ try {
130
+ targetStats = await fs.promises.stat(path);
131
+ } catch {}
132
+ const baseType = targetStats ? toFileType(targetStats) : FileType.Unknown;
133
+ const stats = targetStats ?? lstats;
134
+ return {
135
+ type: baseType | FileType.SymbolicLink,
136
+ stats
137
+ };
138
+ }
139
+ async function getEntryType(dirPath, entry) {
140
+ if (!entry.isSymbolicLink()) return toFileType(entry);
141
+ try {
142
+ return toFileType(await fs.promises.stat(joinPath(dirPath, entry.name))) | FileType.SymbolicLink;
143
+ } catch {
144
+ return FileType.SymbolicLink;
145
+ }
146
+ }
147
+ async function ensureTargetNotExists(path) {
148
+ try {
149
+ await fs.promises.access(path, fs.constants.F_OK);
150
+ throw createFileSystemError(`File exists: ${path}`, FileSystemProviderErrorCode.FileExists);
151
+ } catch (err) {
152
+ if (isErrnoException(err) && err.code !== "ENOENT") throw err;
153
+ }
154
+ }
155
+ async function copyRecursive(sourcePath, targetPath, overwrite) {
156
+ const stats = await fs.promises.stat(sourcePath);
157
+ if (stats.isFile()) {
158
+ const mode = overwrite ? void 0 : fs.constants.COPYFILE_EXCL;
159
+ await fs.promises.copyFile(sourcePath, targetPath, mode);
160
+ return;
161
+ }
162
+ if (stats.isDirectory()) {
163
+ if (!overwrite) await ensureTargetNotExists(targetPath);
164
+ await fs.promises.mkdir(targetPath, { recursive: true });
165
+ const entries = await fs.promises.readdir(sourcePath, { withFileTypes: true });
166
+ for (const entry of entries) await copyRecursive(joinPath(sourcePath, entry.name), joinPath(targetPath, entry.name), overwrite);
167
+ return;
168
+ }
169
+ throw createFileSystemError(`Unsupported file type: ${sourcePath}`, FileSystemProviderErrorCode.Unknown);
170
+ }
171
+ return {
172
+ stat: (uri) => wrap(async () => {
173
+ const { type, stats } = await resolveFileType(uri.fsPath);
174
+ return {
175
+ type,
176
+ ctime: stats.birthtime.getTime(),
177
+ mtime: stats.mtime.getTime(),
178
+ size: stats.size
179
+ };
180
+ }),
181
+ readDirectory: (uri) => wrap(async () => {
182
+ const entries = await fs.promises.readdir(uri.fsPath, { withFileTypes: true });
183
+ return Promise.all(entries.map(async (entry) => [entry.name, await getEntryType(uri.fsPath, entry)]));
184
+ }),
185
+ createDirectory: (uri) => wrap(async () => {
186
+ await fs.promises.mkdir(uri.fsPath, { recursive: true });
187
+ }),
188
+ readFile: (uri) => wrap(() => fs.promises.readFile(uri.fsPath)),
189
+ writeFile: (uri, content) => wrap(() => fs.promises.writeFile(uri.fsPath, content)),
190
+ delete: (uri, options) => wrap(async () => {
191
+ if (options?.useTrash) await trash(uri.fsPath);
192
+ else await fs.promises.rm(uri.fsPath, { recursive: options?.recursive });
193
+ }),
194
+ rename: (source, target, options) => wrap(async () => {
195
+ if (options?.overwrite === false) await ensureTargetNotExists(target.fsPath);
196
+ await fs.promises.rename(source.fsPath, target.fsPath);
197
+ }),
198
+ copy: (source, target, options) => wrap(async () => {
199
+ const overwrite = options?.overwrite !== false;
200
+ await copyRecursive(source.fsPath, target.fsPath, overwrite);
201
+ })
202
+ };
203
+ }
204
+
205
+ //#endregion
206
+ export { FileSystemError, FileSystemProviderErrorCode, FileType, createFileSystemError, createNodeFileSystem, toFileSystemError };
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "vscode-fs",
3
+ "type": "module",
4
+ "version": "0.0.1",
5
+ "description": "VSCode like simple、serializable and cross-platform file system utilities.",
6
+ "author": "Naily Zero <zero@naily.cc> (https://naily.cc)",
7
+ "license": "MIT",
8
+ "homepage": "https://github.com/groupguanfang/vscode-fs",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/groupguanfang/vscode-fs"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/groupguanfang/vscode-fs/issues",
15
+ "email": "zero@naily.cc"
16
+ },
17
+ "keywords": [
18
+ "vscode",
19
+ "file system",
20
+ "serializable",
21
+ "cross-platform"
22
+ ],
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "exports": {
27
+ ".": {
28
+ "types": {
29
+ "import": "./dist/index.d.mts",
30
+ "require": "./dist/index.d.cts"
31
+ },
32
+ "import": "./dist/index.mjs",
33
+ "require": "./dist/index.cjs"
34
+ },
35
+ "./package.json": "./package.json",
36
+ "./dist/*": "./dist/*"
37
+ },
38
+ "main": "dist/index.cjs",
39
+ "module": "dist/index.mjs",
40
+ "types": "dist/index.d.cts",
41
+ "files": [
42
+ "dist"
43
+ ],
44
+ "peerDependencies": {
45
+ "vscode-uri": "^3.1.0"
46
+ },
47
+ "dependencies": {
48
+ "trash": "^10.1.1"
49
+ },
50
+ "devDependencies": {
51
+ "@changesets/cli": "^2.29.8",
52
+ "@types/node": "^25.3.2",
53
+ "naily-eslint-config": "^0.0.1",
54
+ "tsdown": "0.21.0-beta.2"
55
+ },
56
+ "scripts": {
57
+ "build": "tsdown --dts --format esm,cjs src/index.ts",
58
+ "test": "vitest --coverage --ui",
59
+ "lint": "eslint ."
60
+ }
61
+ }