@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.
Files changed (91) hide show
  1. package/README.md +31 -2
  2. package/lib/esm/callback.js +251 -15
  3. package/lib/esm/dirent.js +47 -6
  4. package/lib/esm/encoding.js +2 -3
  5. package/lib/esm/errors.js +13 -0
  6. package/lib/esm/file-handle.js +108 -66
  7. package/lib/esm/fs-watcher.js +44 -7
  8. package/lib/esm/index.js +140 -5
  9. package/lib/esm/promises.js +290 -69
  10. package/lib/esm/read-stream.js +82 -57
  11. package/lib/esm/stats.js +138 -18
  12. package/lib/esm/sync.js +293 -44
  13. package/lib/esm/write-stream.js +4 -4
  14. package/lib/types/callback.d.ts +233 -0
  15. package/lib/types/dirent.d.ts +77 -0
  16. package/lib/types/encoding.d.ts +6 -0
  17. package/lib/types/errors.d.ts +7 -0
  18. package/lib/types/file-handle.d.ts +367 -0
  19. package/lib/types/fs-watcher.d.ts +17 -0
  20. package/lib/types/index.d.ts +149 -0
  21. package/lib/types/promises.d.ts +158 -0
  22. package/lib/types/read-stream.d.ts +21 -0
  23. package/lib/types/stats.d.ts +67 -0
  24. package/lib/types/sync.d.ts +109 -0
  25. package/lib/types/types/encoding-option.d.ts +2 -0
  26. package/lib/types/types/file-read-options.d.ts +15 -0
  27. package/lib/types/types/file-read-result.d.ts +4 -0
  28. package/lib/types/types/flag-and-open-mode.d.ts +5 -0
  29. package/lib/types/types/index.d.ts +6 -0
  30. package/lib/types/types/open-flags.d.ts +1 -0
  31. package/lib/types/types/read-options.d.ts +5 -0
  32. package/lib/types/utils.d.ts +2 -0
  33. package/lib/types/write-stream.d.ts +45 -0
  34. package/package.json +22 -35
  35. package/src/callback.spec.ts +284 -30
  36. package/src/callback.ts +352 -39
  37. package/src/dirent.ts +56 -8
  38. package/src/encoding.ts +7 -2
  39. package/src/errors.spec.ts +389 -0
  40. package/src/errors.ts +19 -0
  41. package/src/extended.spec.ts +706 -0
  42. package/src/file-handle.spec.ts +104 -23
  43. package/src/file-handle.ts +147 -79
  44. package/src/fs-watcher.ts +55 -8
  45. package/src/index.ts +146 -2
  46. package/src/new-apis.spec.ts +505 -0
  47. package/src/promises.spec.ts +651 -11
  48. package/src/promises.ts +353 -81
  49. package/src/read-stream.ts +98 -74
  50. package/src/stat.spec.ts +22 -14
  51. package/src/stats.ts +176 -75
  52. package/src/streams.spec.ts +455 -0
  53. package/src/symlink.spec.ts +176 -26
  54. package/src/sync.spec.ts +204 -32
  55. package/src/sync.ts +363 -58
  56. package/src/test.mts +7 -2
  57. package/src/types/encoding-option.ts +1 -1
  58. package/src/types/flag-and-open-mode.ts +1 -1
  59. package/src/types/read-options.ts +2 -2
  60. package/src/utils.ts +2 -0
  61. package/src/write-stream.ts +9 -7
  62. package/tsconfig.json +23 -10
  63. package/tsconfig.tsbuildinfo +1 -0
  64. package/lib/cjs/callback.js +0 -112
  65. package/lib/cjs/dirent.js +0 -98
  66. package/lib/cjs/encoding.js +0 -34
  67. package/lib/cjs/file-handle.js +0 -444
  68. package/lib/cjs/fs-watcher.js +0 -50
  69. package/lib/cjs/index.js +0 -95
  70. package/lib/cjs/promises.js +0 -160
  71. package/lib/cjs/read-stream.js +0 -78
  72. package/lib/cjs/stats.js +0 -45
  73. package/lib/cjs/sync.js +0 -126
  74. package/lib/cjs/types/encoding-option.js +0 -0
  75. package/lib/cjs/types/file-read-options.js +0 -0
  76. package/lib/cjs/types/file-read-result.js +0 -0
  77. package/lib/cjs/types/flag-and-open-mode.js +0 -0
  78. package/lib/cjs/types/index.js +0 -6
  79. package/lib/cjs/types/open-flags.js +0 -0
  80. package/lib/cjs/types/read-options.js +0 -0
  81. package/lib/cjs/utils.js +0 -18
  82. package/lib/cjs/write-stream.js +0 -116
  83. package/test/watch.js +0 -1
  84. package/test.gjs.js +0 -35359
  85. package/test.gjs.js.map +0 -7
  86. package/test.gjs.mjs +0 -40534
  87. package/test.gjs.mjs.meta.json +0 -1
  88. package/test.node.js +0 -1479
  89. package/test.node.js.map +0 -7
  90. package/test.node.mjs +0 -710
  91. 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 { warnNotImplemented } from '@gjsify/utils';
4
- import { join } from 'path';
6
+ import { join, dirname } from 'node:path';
5
7
  import { getEncodingFromOptions, encodeUint8Array, decode } from './encoding.js';
6
- import { writeFileSync, mkdirSync, rmdirSync, unlinkSync } from './sync.js';
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 { realpathPromise as realpath } from '@gjsify/deno_std/node/_fs/_fs_realpath';
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 mode: Mode | undefined = 0o777;
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) mode = options.mode
75
+ if(options.mode) _mode = options.mode
78
76
  } else {
79
- mode = options;
77
+ _mode = options;
78
+ }
79
+
80
+ const pathStr = path.toString();
81
+
82
+ if (recursive) {
83
+ return mkdirRecursiveAsync(pathStr);
80
84
  }
81
85
 
82
- // TODO async
83
- const firstPath = mkdirSync(path, {
84
- recursive,
85
- mode
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
- return firstPath;
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
- const [ok, data] = await new Promise<[boolean, Uint8Array, string]>((resolve, reject) => {
94
- file.load_contents_async(null, (self, res) => {
95
- try {
96
- resolve(file.load_contents_finish(res));
97
- } catch (error) {
98
- reject(error);
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
- // TODO: throw a better error
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: any) {
165
- // TODO async
166
- return writeFileSync(path, data);
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, options?: RmDirOptions): Promise<void> {
180
- // TODO async
181
- return rmdirSync(path, options);
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
- // TODO async
186
- return unlinkSync(path);
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
- return new FileHandle({
191
- path,
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<any>(fd, data, positionOrOffset as number | null, encodingOrLength as null | number, position);
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
- warnNotImplemented("fs.promises.write");
245
- return {
246
- bytesWritten: 0,
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
- warnNotImplemented("fs.promises.write");
261
- return {
262
- bytesWritten: 0,
263
- buffer: data,
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 file = Gio.File.new_for_path(path.toString());
274
-
485
+ const pathStr = path.toString();
486
+ const file = Gio.File.new_for_path(pathStr);
275
487
  const recursive = options?.recursive || false;
276
-
277
- const dirent = new Dirent(path.toString());
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
- throw new Error('Dir is not empty!');
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.isDirectory()) {
288
- await rmdir(join(path.toString(), childFile.name), options);
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
- const ok = await new Promise<boolean>((resolve, reject) => {
296
- try {
297
- file.delete_async(GLib.PRIORITY_DEFAULT, null, (self, res) => {
298
- try {
299
- resolve(file.delete_finish(res));
300
- } catch (error) {
301
- reject(error);
302
- }
303
- });
304
- } catch (error) {
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
- if (!ok) {
311
- // TODO: throw a better error
312
- const err = new Error('failed to remove file ' + path);
313
- throw err;
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
  };