@gjsify/fs 0.0.4 → 0.1.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.
- package/README.md +31 -2
- package/lib/esm/callback.js +251 -15
- package/lib/esm/dirent.js +47 -6
- package/lib/esm/encoding.js +2 -3
- package/lib/esm/errors.js +13 -0
- package/lib/esm/file-handle.js +108 -66
- package/lib/esm/fs-watcher.js +44 -7
- package/lib/esm/index.js +140 -5
- package/lib/esm/promises.js +290 -69
- package/lib/esm/read-stream.js +82 -57
- package/lib/esm/stats.js +138 -18
- package/lib/esm/sync.js +293 -44
- package/lib/esm/write-stream.js +4 -4
- package/lib/types/callback.d.ts +233 -0
- package/lib/types/dirent.d.ts +77 -0
- package/lib/types/encoding.d.ts +6 -0
- package/lib/types/errors.d.ts +7 -0
- package/lib/types/file-handle.d.ts +367 -0
- package/lib/types/fs-watcher.d.ts +17 -0
- package/lib/types/index.d.ts +149 -0
- package/lib/types/promises.d.ts +158 -0
- package/lib/types/read-stream.d.ts +21 -0
- package/lib/types/stats.d.ts +67 -0
- package/lib/types/sync.d.ts +109 -0
- package/lib/types/types/encoding-option.d.ts +2 -0
- package/lib/types/types/file-read-options.d.ts +15 -0
- package/lib/types/types/file-read-result.d.ts +4 -0
- package/lib/types/types/flag-and-open-mode.d.ts +5 -0
- package/lib/types/types/index.d.ts +6 -0
- package/lib/types/types/open-flags.d.ts +1 -0
- package/lib/types/types/read-options.d.ts +5 -0
- package/lib/types/utils.d.ts +2 -0
- package/lib/types/write-stream.d.ts +45 -0
- package/package.json +22 -35
- package/src/callback.spec.ts +284 -30
- package/src/callback.ts +352 -39
- package/src/dirent.ts +56 -8
- package/src/encoding.ts +7 -2
- package/src/errors.spec.ts +389 -0
- package/src/errors.ts +19 -0
- package/src/extended.spec.ts +706 -0
- package/src/file-handle.spec.ts +104 -23
- package/src/file-handle.ts +147 -79
- package/src/fs-watcher.ts +55 -8
- package/src/index.ts +146 -2
- package/src/new-apis.spec.ts +505 -0
- package/src/promises.spec.ts +651 -11
- package/src/promises.ts +353 -81
- package/src/read-stream.ts +98 -74
- package/src/stat.spec.ts +22 -14
- package/src/stats.ts +176 -75
- package/src/streams.spec.ts +455 -0
- package/src/symlink.spec.ts +176 -26
- package/src/sync.spec.ts +204 -32
- package/src/sync.ts +363 -58
- package/src/test.mts +7 -2
- package/src/types/encoding-option.ts +1 -1
- package/src/types/flag-and-open-mode.ts +1 -1
- package/src/types/read-options.ts +2 -2
- package/src/utils.ts +2 -0
- package/src/write-stream.ts +9 -7
- package/tsconfig.json +23 -10
- package/tsconfig.tsbuildinfo +1 -0
- package/lib/cjs/callback.js +0 -112
- package/lib/cjs/dirent.js +0 -98
- package/lib/cjs/encoding.js +0 -34
- package/lib/cjs/file-handle.js +0 -444
- package/lib/cjs/fs-watcher.js +0 -50
- package/lib/cjs/index.js +0 -95
- package/lib/cjs/promises.js +0 -160
- package/lib/cjs/read-stream.js +0 -78
- package/lib/cjs/stats.js +0 -45
- package/lib/cjs/sync.js +0 -126
- package/lib/cjs/types/encoding-option.js +0 -0
- package/lib/cjs/types/file-read-options.js +0 -0
- package/lib/cjs/types/file-read-result.js +0 -0
- package/lib/cjs/types/flag-and-open-mode.js +0 -0
- package/lib/cjs/types/index.js +0 -6
- package/lib/cjs/types/open-flags.js +0 -0
- package/lib/cjs/types/read-options.js +0 -0
- package/lib/cjs/utils.js +0 -18
- package/lib/cjs/write-stream.js +0 -116
- package/test/watch.js +0 -1
- package/test.gjs.js +0 -35359
- package/test.gjs.js.map +0 -7
- package/test.gjs.mjs +0 -40534
- package/test.gjs.mjs.meta.json +0 -1
- package/test.node.js +0 -1479
- package/test.node.js.map +0 -7
- package/test.node.mjs +0 -710
- package/tsconfig.types.json +0 -8
package/src/promises.ts
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
|
+
// Reference: Node.js lib/internal/fs/promises.js
|
|
2
|
+
// Reimplemented for GJS using Gio.File
|
|
3
|
+
|
|
1
4
|
import Gio from '@girs/gio-2.0';
|
|
2
5
|
import GLib from '@girs/glib-2.0';
|
|
3
|
-
import {
|
|
4
|
-
import { join } from 'path';
|
|
6
|
+
import { join, dirname } from 'node:path';
|
|
5
7
|
import { getEncodingFromOptions, encodeUint8Array, decode } from './encoding.js';
|
|
6
|
-
import {
|
|
8
|
+
import { realpathSync, readdirSync as readdirSyncFn, renameSync, copyFileSync, accessSync, appendFileSync, readlinkSync, truncateSync, chmodSync, chownSync, linkSync } from './sync.js';
|
|
7
9
|
import { FileHandle } from './file-handle.js';
|
|
8
10
|
import { tempDirPath } from './utils.js';
|
|
9
11
|
import { Dirent } from './dirent.js';
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
import { readdirPromise as readdir } from '@gjsify/deno_std/node/_fs/_fs_readdir';
|
|
13
|
-
import { symlinkPromise as symlink } from '@gjsify/deno_std/node/_fs/_fs_symlink';
|
|
14
|
-
import { lstatPromise as lstat } from '@gjsify/deno_std/node/_fs/_fs_lstat';
|
|
15
|
-
import { statPromise as stat } from '@gjsify/deno_std/node/_fs/_fs_stat';
|
|
12
|
+
import { Stats, BigIntStats, STAT_ATTRIBUTES } from './stats.js';
|
|
13
|
+
import { createNodeError } from './errors.js';
|
|
16
14
|
|
|
17
15
|
import type {
|
|
18
16
|
OpenFlags,
|
|
@@ -26,7 +24,7 @@ import type {
|
|
|
26
24
|
BufferEncodingOption,
|
|
27
25
|
MakeDirectoryOptions,
|
|
28
26
|
RmDirOptions
|
|
29
|
-
} from 'fs';
|
|
27
|
+
} from 'node:fs';
|
|
30
28
|
|
|
31
29
|
/**
|
|
32
30
|
* Asynchronously creates a directory.
|
|
@@ -70,39 +68,110 @@ async function mkdir(path: PathLike, options?: Mode | MakeDirectoryOptions | nul
|
|
|
70
68
|
async function mkdir(path: PathLike, options?: Mode | MakeDirectoryOptions | null): Promise<string | undefined | void> {
|
|
71
69
|
|
|
72
70
|
let recursive: boolean | undefined;
|
|
73
|
-
let
|
|
71
|
+
let _mode: Mode | undefined = 0o777;
|
|
74
72
|
|
|
75
73
|
if (typeof options === 'object') {
|
|
76
74
|
if(options.recursive) recursive = options.recursive;
|
|
77
|
-
if(options.mode)
|
|
75
|
+
if(options.mode) _mode = options.mode
|
|
78
76
|
} else {
|
|
79
|
-
|
|
77
|
+
_mode = options;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const pathStr = path.toString();
|
|
81
|
+
|
|
82
|
+
if (recursive) {
|
|
83
|
+
return mkdirRecursiveAsync(pathStr);
|
|
80
84
|
}
|
|
81
85
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
const file = Gio.File.new_for_path(pathStr);
|
|
87
|
+
return new Promise<undefined>((resolve, reject) => {
|
|
88
|
+
file.make_directory_async(GLib.PRIORITY_DEFAULT, null, (_s: unknown, res: Gio.AsyncResult) => {
|
|
89
|
+
try {
|
|
90
|
+
file.make_directory_finish(res);
|
|
91
|
+
resolve(undefined);
|
|
92
|
+
} catch (err: unknown) {
|
|
93
|
+
reject(createNodeError(err, 'mkdir', path));
|
|
94
|
+
}
|
|
95
|
+
});
|
|
86
96
|
});
|
|
87
|
-
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Recursively creates directories, similar to `mkdir -p`.
|
|
101
|
+
* Returns the first directory path created, or undefined if all directories already existed.
|
|
102
|
+
*/
|
|
103
|
+
async function mkdirRecursiveAsync(pathStr: string): Promise<string | undefined> {
|
|
104
|
+
const file = Gio.File.new_for_path(pathStr);
|
|
105
|
+
|
|
106
|
+
// Try to create the directory directly first
|
|
107
|
+
try {
|
|
108
|
+
await new Promise<void>((resolve, reject) => {
|
|
109
|
+
file.make_directory_async(GLib.PRIORITY_DEFAULT, null, (_s: unknown, res: Gio.AsyncResult) => {
|
|
110
|
+
try {
|
|
111
|
+
file.make_directory_finish(res);
|
|
112
|
+
resolve();
|
|
113
|
+
} catch (err: unknown) {
|
|
114
|
+
reject(err);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
// This directory was created; it's the deepest one.
|
|
119
|
+
// Now check if we also created parents by recursing on the parent first.
|
|
120
|
+
// Since we succeeded directly, this is the "first created" path candidate.
|
|
121
|
+
return pathStr;
|
|
122
|
+
} catch (err: unknown) {
|
|
123
|
+
const gErr = err as { code?: number };
|
|
124
|
+
// If it already exists, nothing to create
|
|
125
|
+
if (gErr.code === Gio.IOErrorEnum.EXISTS) {
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
// If parent doesn't exist, create parent first then retry
|
|
129
|
+
if (gErr.code === Gio.IOErrorEnum.NOT_FOUND) {
|
|
130
|
+
const parentPath = dirname(pathStr);
|
|
131
|
+
if (parentPath === pathStr) {
|
|
132
|
+
// Reached root, cannot go further
|
|
133
|
+
throw createNodeError(err, 'mkdir', pathStr);
|
|
134
|
+
}
|
|
135
|
+
const firstCreated = await mkdirRecursiveAsync(parentPath);
|
|
136
|
+
// Now create this directory
|
|
137
|
+
const retryFile = Gio.File.new_for_path(pathStr);
|
|
138
|
+
await new Promise<void>((resolve, reject) => {
|
|
139
|
+
retryFile.make_directory_async(GLib.PRIORITY_DEFAULT, null, (_s: unknown, res: Gio.AsyncResult) => {
|
|
140
|
+
try {
|
|
141
|
+
retryFile.make_directory_finish(res);
|
|
142
|
+
resolve();
|
|
143
|
+
} catch (retryErr: unknown) {
|
|
144
|
+
reject(createNodeError(retryErr, 'mkdir', pathStr));
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
return firstCreated ?? pathStr;
|
|
149
|
+
}
|
|
150
|
+
throw createNodeError(err, 'mkdir', pathStr);
|
|
151
|
+
}
|
|
88
152
|
}
|
|
89
153
|
|
|
90
154
|
async function readFile(path: PathLike | FileHandle, options: ReadOptions = { encoding: null, flag: 'r' }) {
|
|
91
155
|
const file = Gio.File.new_for_path(path.toString());
|
|
92
156
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
157
|
+
let ok: boolean;
|
|
158
|
+
let data: Uint8Array;
|
|
159
|
+
try {
|
|
160
|
+
[ok, data] = await new Promise<[boolean, Uint8Array, string]>((resolve, reject) => {
|
|
161
|
+
file.load_contents_async(null, (self, res) => {
|
|
162
|
+
try {
|
|
163
|
+
resolve(file.load_contents_finish(res));
|
|
164
|
+
} catch (error) {
|
|
165
|
+
reject(error);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
100
168
|
});
|
|
101
|
-
})
|
|
169
|
+
} catch (error) {
|
|
170
|
+
throw createNodeError(error, 'open', path.toString() as PathLike);
|
|
171
|
+
}
|
|
102
172
|
|
|
103
173
|
if (!ok) {
|
|
104
|
-
|
|
105
|
-
throw new Error('failed to read file');
|
|
174
|
+
throw createNodeError(new Error('failed to read file'), 'open', path.toString() as PathLike);
|
|
106
175
|
}
|
|
107
176
|
|
|
108
177
|
return encodeUint8Array(getEncodingFromOptions(options, 'buffer'), data);
|
|
@@ -119,7 +188,7 @@ async function readFile(path: PathLike | FileHandle, options: ReadOptions = { en
|
|
|
119
188
|
* object with an `encoding` property specifying the character encoding to use.
|
|
120
189
|
*
|
|
121
190
|
* ```js
|
|
122
|
-
* import { mkdtemp } from 'fs/promises';
|
|
191
|
+
* import { mkdtemp } from 'node:fs/promises';
|
|
123
192
|
*
|
|
124
193
|
* try {
|
|
125
194
|
* await mkdtemp(path.join(os.tmpdir(), 'foo-'));
|
|
@@ -161,9 +230,57 @@ async function mkdtemp(prefix: string, options?: BufferEncodingOption | ObjectEn
|
|
|
161
230
|
return decode(path, encoding);
|
|
162
231
|
}
|
|
163
232
|
|
|
164
|
-
async function writeFile(path: string, data:
|
|
165
|
-
|
|
166
|
-
|
|
233
|
+
async function writeFile(path: string, data: string | Uint8Array | unknown) {
|
|
234
|
+
const file = Gio.File.new_for_path(path);
|
|
235
|
+
|
|
236
|
+
// Convert data to Uint8Array if it's a string
|
|
237
|
+
let bytes: Uint8Array;
|
|
238
|
+
if (typeof data === 'string') {
|
|
239
|
+
bytes = new TextEncoder().encode(data);
|
|
240
|
+
} else if (data instanceof Uint8Array) {
|
|
241
|
+
bytes = data;
|
|
242
|
+
} else {
|
|
243
|
+
// Fallback: convert to string first
|
|
244
|
+
bytes = new TextEncoder().encode(String(data));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Open the file for writing (replace contents), creating if needed
|
|
248
|
+
const outputStream = await new Promise<Gio.FileOutputStream>((resolve, reject) => {
|
|
249
|
+
file.replace_async(null, false, Gio.FileCreateFlags.REPLACE_DESTINATION, GLib.PRIORITY_DEFAULT, null, (_s: unknown, res: Gio.AsyncResult) => {
|
|
250
|
+
try {
|
|
251
|
+
resolve(file.replace_finish(res));
|
|
252
|
+
} catch (err: unknown) {
|
|
253
|
+
reject(createNodeError(err, 'open', path));
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// Write the bytes to the stream (skip if empty — GLib rejects null/empty buffer)
|
|
259
|
+
if (bytes.length > 0) {
|
|
260
|
+
const glibBytes = new GLib.Bytes(bytes);
|
|
261
|
+
await new Promise<void>((resolve, reject) => {
|
|
262
|
+
outputStream.write_bytes_async(glibBytes, GLib.PRIORITY_DEFAULT, null, (_s: unknown, res: Gio.AsyncResult) => {
|
|
263
|
+
try {
|
|
264
|
+
outputStream.write_bytes_finish(res);
|
|
265
|
+
resolve();
|
|
266
|
+
} catch (err: unknown) {
|
|
267
|
+
reject(createNodeError(err, 'write', path));
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Close the output stream
|
|
274
|
+
await new Promise<void>((resolve, reject) => {
|
|
275
|
+
outputStream.close_async(GLib.PRIORITY_DEFAULT, null, (_s: unknown, res: Gio.AsyncResult) => {
|
|
276
|
+
try {
|
|
277
|
+
outputStream.close_finish(res);
|
|
278
|
+
resolve();
|
|
279
|
+
} catch (err: unknown) {
|
|
280
|
+
reject(createNodeError(err, 'close', path));
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
});
|
|
167
284
|
}
|
|
168
285
|
|
|
169
286
|
/**
|
|
@@ -176,22 +293,67 @@ async function writeFile(path: string, data: any) {
|
|
|
176
293
|
* @since v10.0.0
|
|
177
294
|
* @return Fulfills with `undefined` upon success.
|
|
178
295
|
*/
|
|
179
|
-
async function rmdir(path: PathLike,
|
|
180
|
-
|
|
181
|
-
|
|
296
|
+
async function rmdir(path: PathLike, _options?: RmDirOptions): Promise<void> {
|
|
297
|
+
const file = Gio.File.new_for_path(path.toString());
|
|
298
|
+
// Check if it's a directory
|
|
299
|
+
const info = await new Promise<Gio.FileInfo>((resolve, reject) => {
|
|
300
|
+
file.query_info_async('standard::type', Gio.FileQueryInfoFlags.NONE, GLib.PRIORITY_DEFAULT, null, (_s: unknown, res: Gio.AsyncResult) => {
|
|
301
|
+
try {
|
|
302
|
+
resolve(file.query_info_finish(res));
|
|
303
|
+
} catch (err: unknown) {
|
|
304
|
+
reject(createNodeError(err, 'rmdir', path));
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
if (info.get_file_type() !== Gio.FileType.DIRECTORY) {
|
|
309
|
+
const err = Object.assign(new Error(), { code: 4 }); // Gio.IOErrorEnum.NOT_DIRECTORY
|
|
310
|
+
throw createNodeError(err, 'rmdir', path);
|
|
311
|
+
}
|
|
312
|
+
// Check if empty
|
|
313
|
+
const children = await new Promise<Gio.FileEnumerator>((resolve, reject) => {
|
|
314
|
+
file.enumerate_children_async('standard::name', Gio.FileQueryInfoFlags.NONE, GLib.PRIORITY_DEFAULT, null, (_s: unknown, res: Gio.AsyncResult) => {
|
|
315
|
+
try {
|
|
316
|
+
resolve(file.enumerate_children_finish(res));
|
|
317
|
+
} catch (err: unknown) {
|
|
318
|
+
reject(createNodeError(err, 'rmdir', path));
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
const firstChild = children.next_file(null);
|
|
323
|
+
if (firstChild !== null) {
|
|
324
|
+
const err = Object.assign(new Error(), { code: 5 }); // Gio.IOErrorEnum.NOT_EMPTY
|
|
325
|
+
throw createNodeError(err, 'rmdir', path);
|
|
326
|
+
}
|
|
327
|
+
// Delete the empty directory
|
|
328
|
+
await new Promise<void>((resolve, reject) => {
|
|
329
|
+
file.delete_async(GLib.PRIORITY_DEFAULT, null, (_s: unknown, res: Gio.AsyncResult) => {
|
|
330
|
+
try {
|
|
331
|
+
file.delete_finish(res);
|
|
332
|
+
resolve();
|
|
333
|
+
} catch (err: unknown) {
|
|
334
|
+
reject(createNodeError(err, 'rmdir', path));
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
});
|
|
182
338
|
}
|
|
183
339
|
|
|
184
|
-
async function unlink(path: string) {
|
|
185
|
-
|
|
186
|
-
|
|
340
|
+
async function unlink(path: string): Promise<void> {
|
|
341
|
+
const file = Gio.File.new_for_path(path);
|
|
342
|
+
await new Promise<void>((resolve, reject) => {
|
|
343
|
+
file.delete_async(GLib.PRIORITY_DEFAULT, null, (_s: unknown, res: Gio.AsyncResult) => {
|
|
344
|
+
try {
|
|
345
|
+
file.delete_finish(res);
|
|
346
|
+
resolve();
|
|
347
|
+
} catch (err: unknown) {
|
|
348
|
+
reject(createNodeError(err, 'unlink', path));
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
});
|
|
187
352
|
}
|
|
188
353
|
|
|
189
354
|
async function open(path: PathLike, flags?: OpenFlags, mode?: Mode): Promise<FileHandle> {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
flags,
|
|
193
|
-
mode,
|
|
194
|
-
});
|
|
355
|
+
// FileHandle constructor maps GLib.FileError to NodeJS.ErrnoException on failure.
|
|
356
|
+
return new FileHandle({ path, flags, mode });
|
|
195
357
|
}
|
|
196
358
|
|
|
197
359
|
async function write<TBuffer extends Uint8Array>(
|
|
@@ -228,7 +390,7 @@ async function write<TBuffer extends Uint8Array>(
|
|
|
228
390
|
if(typeof data === 'string') {
|
|
229
391
|
return _writeStr(fd, data, positionOrOffset, encodingOrLength as BufferEncoding | null);
|
|
230
392
|
}
|
|
231
|
-
return _writeBuf
|
|
393
|
+
return _writeBuf(fd, data, positionOrOffset as number | null, encodingOrLength as null | number, position) as unknown as Promise<{ bytesWritten: number; buffer: string }>;
|
|
232
394
|
}
|
|
233
395
|
|
|
234
396
|
async function _writeBuf<TBuffer extends Uint8Array>(
|
|
@@ -241,11 +403,9 @@ async function _writeBuf<TBuffer extends Uint8Array>(
|
|
|
241
403
|
bytesWritten: number;
|
|
242
404
|
buffer: TBuffer;
|
|
243
405
|
}> {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
buffer
|
|
248
|
-
}
|
|
406
|
+
const fileHandle = FileHandle.getInstance(fd);
|
|
407
|
+
const result = await fileHandle.write(buffer, offset, length, position);
|
|
408
|
+
return { bytesWritten: result.bytesWritten, buffer };
|
|
249
409
|
}
|
|
250
410
|
|
|
251
411
|
async function _writeStr(
|
|
@@ -257,61 +417,155 @@ async function _writeStr(
|
|
|
257
417
|
bytesWritten: number;
|
|
258
418
|
buffer: string;
|
|
259
419
|
}> {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
420
|
+
const fileHandle = FileHandle.getInstance(fd);
|
|
421
|
+
const result = await fileHandle.write(data, position, encoding);
|
|
422
|
+
return { bytesWritten: result.bytesWritten, buffer: data };
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// --- helpers ---
|
|
426
|
+
|
|
427
|
+
function queryInfoAsync(path: PathLike, flags: Gio.FileQueryInfoFlags, syscall: string, options?: { bigint?: boolean }): Promise<Stats | BigIntStats> {
|
|
428
|
+
return new Promise((resolve, reject) => {
|
|
429
|
+
const file = Gio.File.new_for_path(path.toString());
|
|
430
|
+
file.query_info_async(STAT_ATTRIBUTES, flags, GLib.PRIORITY_DEFAULT, null, (_s: unknown, res: Gio.AsyncResult) => {
|
|
431
|
+
try {
|
|
432
|
+
const info = file.query_info_finish(res);
|
|
433
|
+
resolve(options?.bigint ? new BigIntStats(info, path) : new Stats(info, path));
|
|
434
|
+
} catch (err: unknown) {
|
|
435
|
+
reject(createNodeError(err, syscall, path));
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// --- stat / lstat ---
|
|
442
|
+
|
|
443
|
+
async function stat(path: PathLike, options?: { bigint?: boolean }): Promise<Stats | BigIntStats> {
|
|
444
|
+
return queryInfoAsync(path, Gio.FileQueryInfoFlags.NONE, 'stat', options);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
async function lstat(path: PathLike, options?: { bigint?: boolean }): Promise<Stats | BigIntStats> {
|
|
448
|
+
return queryInfoAsync(path, Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, 'lstat', options);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// --- readdir / realpath / symlink — delegate to sync (sync is the canonical impl) ---
|
|
452
|
+
|
|
453
|
+
async function readdir(path: PathLike, options?: { withFileTypes?: boolean; encoding?: string; recursive?: boolean }): Promise<string[] | Dirent[]> {
|
|
454
|
+
try {
|
|
455
|
+
return readdirSyncFn(path, options);
|
|
456
|
+
} catch (error) {
|
|
457
|
+
throw createNodeError(error, 'scandir', path);
|
|
264
458
|
}
|
|
265
459
|
}
|
|
266
460
|
|
|
461
|
+
async function realpath(path: PathLike): Promise<string> {
|
|
462
|
+
return realpathSync(path);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
async function symlink(target: PathLike, path: PathLike, _type?: string): Promise<void> {
|
|
466
|
+
return new Promise((resolve, reject) => {
|
|
467
|
+
const file = Gio.File.new_for_path(path.toString());
|
|
468
|
+
file.make_symbolic_link_async(target.toString(), GLib.PRIORITY_DEFAULT, null, (_s: unknown, res: Gio.AsyncResult) => {
|
|
469
|
+
try {
|
|
470
|
+
file.make_symbolic_link_finish(res);
|
|
471
|
+
resolve();
|
|
472
|
+
} catch (err: unknown) {
|
|
473
|
+
reject(createNodeError(err, 'symlink', target, path));
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
|
|
267
479
|
/**
|
|
268
480
|
* Removes files and directories (modeled on the standard POSIX `rm` utility).
|
|
269
481
|
* @since v14.14.0
|
|
270
482
|
* @return Fulfills with `undefined` upon success.
|
|
271
483
|
*/
|
|
272
484
|
async function rm(path: PathLike, options?: RmOptions): Promise<void> {
|
|
273
|
-
const
|
|
274
|
-
|
|
485
|
+
const pathStr = path.toString();
|
|
486
|
+
const file = Gio.File.new_for_path(pathStr);
|
|
275
487
|
const recursive = options?.recursive || false;
|
|
276
|
-
|
|
277
|
-
|
|
488
|
+
const force = options?.force || false;
|
|
489
|
+
|
|
490
|
+
let dirent: Dirent;
|
|
491
|
+
try {
|
|
492
|
+
dirent = new Dirent(pathStr);
|
|
493
|
+
} catch (err: unknown) {
|
|
494
|
+
if (force) return; // force: ignore non-existent paths
|
|
495
|
+
throw createNodeError(err, 'rm', path);
|
|
496
|
+
}
|
|
278
497
|
|
|
279
498
|
if (dirent.isDirectory()) {
|
|
280
499
|
const childFiles = await readdir(path, { withFileTypes: true });
|
|
281
500
|
|
|
282
501
|
if (!recursive && childFiles.length) {
|
|
283
|
-
|
|
502
|
+
const err = Object.assign(new Error(), { code: 5 }); // Gio.IOErrorEnum.NOT_EMPTY
|
|
503
|
+
throw createNodeError(err, 'rm', path);
|
|
284
504
|
}
|
|
285
|
-
|
|
505
|
+
|
|
286
506
|
for (const childFile of childFiles) {
|
|
287
|
-
if (childFile
|
|
288
|
-
await
|
|
289
|
-
} else if (childFile.isFile()) {
|
|
290
|
-
await rm(join(path.toString(), childFile.name), options);
|
|
507
|
+
if (typeof childFile !== 'string') {
|
|
508
|
+
await rm(join(pathStr, childFile.name), options);
|
|
291
509
|
}
|
|
292
510
|
}
|
|
293
511
|
}
|
|
294
512
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
reject(error);
|
|
306
|
-
}
|
|
307
|
-
|
|
513
|
+
await new Promise<void>((resolve, reject) => {
|
|
514
|
+
file.delete_async(GLib.PRIORITY_DEFAULT, null, (_self: unknown, res: Gio.AsyncResult) => {
|
|
515
|
+
try {
|
|
516
|
+
file.delete_finish(res);
|
|
517
|
+
resolve();
|
|
518
|
+
} catch (err: unknown) {
|
|
519
|
+
if (force) { resolve(); return; }
|
|
520
|
+
reject(createNodeError(err, 'rm', path));
|
|
521
|
+
}
|
|
522
|
+
});
|
|
308
523
|
});
|
|
524
|
+
}
|
|
309
525
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
526
|
+
// --- rename ---
|
|
527
|
+
async function rename(oldPath: PathLike, newPath: PathLike): Promise<void> {
|
|
528
|
+
renameSync(oldPath, newPath);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// --- copyFile ---
|
|
532
|
+
async function copyFile(src: PathLike, dest: PathLike, mode?: number): Promise<void> {
|
|
533
|
+
copyFileSync(src, dest, mode);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// --- access ---
|
|
537
|
+
async function access(path: PathLike, mode?: number): Promise<void> {
|
|
538
|
+
accessSync(path, mode);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// --- appendFile ---
|
|
542
|
+
async function appendFile(path: PathLike, data: string | Uint8Array, options?: { encoding?: string; mode?: number; flag?: string } | string): Promise<void> {
|
|
543
|
+
appendFileSync(path, data, options);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// --- readlink ---
|
|
547
|
+
async function readlink(path: PathLike, options?: { encoding?: string } | string): Promise<string | Buffer> {
|
|
548
|
+
return readlinkSync(path, options);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// --- truncate ---
|
|
552
|
+
async function truncate(path: PathLike, len?: number): Promise<void> {
|
|
553
|
+
truncateSync(path, len);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// --- chmod ---
|
|
557
|
+
async function chmod(path: PathLike, mode: number | string): Promise<void> {
|
|
558
|
+
chmodSync(path, mode);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// --- chown ---
|
|
562
|
+
async function chown(path: PathLike, uid: number, gid: number): Promise<void> {
|
|
563
|
+
chownSync(path, uid, gid);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// --- link ---
|
|
567
|
+
async function link(existingPath: PathLike, newPath: PathLike): Promise<void> {
|
|
568
|
+
linkSync(existingPath, newPath);
|
|
315
569
|
}
|
|
316
570
|
|
|
317
571
|
export {
|
|
@@ -329,6 +583,15 @@ export {
|
|
|
329
583
|
lstat,
|
|
330
584
|
symlink,
|
|
331
585
|
stat,
|
|
586
|
+
rename,
|
|
587
|
+
copyFile,
|
|
588
|
+
access,
|
|
589
|
+
appendFile,
|
|
590
|
+
readlink,
|
|
591
|
+
truncate,
|
|
592
|
+
chmod,
|
|
593
|
+
chown,
|
|
594
|
+
link,
|
|
332
595
|
};
|
|
333
596
|
|
|
334
597
|
export default {
|
|
@@ -346,4 +609,13 @@ export default {
|
|
|
346
609
|
lstat,
|
|
347
610
|
symlink,
|
|
348
611
|
stat,
|
|
612
|
+
rename,
|
|
613
|
+
copyFile,
|
|
614
|
+
access,
|
|
615
|
+
appendFile,
|
|
616
|
+
readlink,
|
|
617
|
+
truncate,
|
|
618
|
+
chmod,
|
|
619
|
+
chown,
|
|
620
|
+
link,
|
|
349
621
|
};
|