@gjsify/fs 0.0.4 → 0.1.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.
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/index.ts CHANGED
@@ -1,3 +1,6 @@
1
+ // Reference: Node.js lib/fs.js
2
+ // Reimplemented for GJS using Gio.File
3
+
1
4
  import {
2
5
  existsSync,
3
6
  readdirSync,
@@ -14,8 +17,18 @@ import {
14
17
  realpathSync,
15
18
  symlinkSync,
16
19
  lstatSync,
20
+ renameSync,
21
+ copyFileSync,
22
+ accessSync,
23
+ appendFileSync,
24
+ readlinkSync,
25
+ linkSync,
26
+ truncateSync,
27
+ chmodSync,
28
+ chownSync,
17
29
  } from './sync.js';
18
- import { open,
30
+ import {
31
+ open,
19
32
  close,
20
33
  read,
21
34
  write,
@@ -24,16 +37,88 @@ import { open,
24
37
  readdir,
25
38
  symlink,
26
39
  lstat,
40
+ stat,
41
+ rename,
42
+ copyFile,
43
+ access,
44
+ appendFile,
45
+ readlink,
46
+ truncate,
47
+ chmod,
48
+ chown,
49
+ mkdir,
50
+ rmdir,
51
+ readFile,
52
+ writeFile,
53
+ unlink,
54
+ link,
27
55
  } from './callback.js';
28
56
  import FSWatcher from './fs-watcher.js';
29
57
  import {
30
58
  createReadStream,
31
59
  ReadStream
32
60
  } from './read-stream.js';
61
+ import {
62
+ createWriteStream,
63
+ WriteStream
64
+ } from './write-stream.js';
33
65
  import * as promises from './promises.js';
66
+ import { Stats, BigIntStats } from './stats.js';
67
+ import { Dirent } from './dirent.js';
68
+
69
+ // --- fs.constants ---
70
+ export const constants = {
71
+ // File access constants
72
+ F_OK: 0,
73
+ R_OK: 4,
74
+ W_OK: 2,
75
+ X_OK: 1,
76
+ // File copy constants
77
+ COPYFILE_EXCL: 1,
78
+ COPYFILE_FICLONE: 2,
79
+ COPYFILE_FICLONE_FORCE: 4,
80
+ // File open constants
81
+ O_RDONLY: 0,
82
+ O_WRONLY: 1,
83
+ O_RDWR: 2,
84
+ O_CREAT: 64,
85
+ O_EXCL: 128,
86
+ O_TRUNC: 512,
87
+ O_APPEND: 1024,
88
+ O_SYNC: 1052672,
89
+ O_NONBLOCK: 2048,
90
+ O_DIRECTORY: 65536,
91
+ O_NOFOLLOW: 131072,
92
+ // File type constants
93
+ S_IFMT: 61440,
94
+ S_IFREG: 32768,
95
+ S_IFDIR: 16384,
96
+ S_IFCHR: 8192,
97
+ S_IFBLK: 24576,
98
+ S_IFIFO: 4096,
99
+ S_IFLNK: 40960,
100
+ S_IFSOCK: 49152,
101
+ // File mode constants
102
+ S_IRWXU: 448,
103
+ S_IRUSR: 256,
104
+ S_IWUSR: 128,
105
+ S_IXUSR: 64,
106
+ S_IRWXG: 56,
107
+ S_IRGRP: 32,
108
+ S_IWGRP: 16,
109
+ S_IXGRP: 8,
110
+ S_IRWXO: 7,
111
+ S_IROTH: 4,
112
+ S_IWOTH: 2,
113
+ S_IXOTH: 1,
114
+ };
34
115
 
35
116
  export {
36
117
  FSWatcher,
118
+ Stats,
119
+ BigIntStats,
120
+ Dirent,
121
+ // Sync API
37
122
  existsSync,
38
123
  readdirSync,
39
124
  readFileSync,
@@ -48,10 +133,24 @@ export {
48
133
  realpathSync,
49
134
  symlinkSync,
50
135
  lstatSync,
136
+ renameSync,
137
+ copyFileSync,
138
+ accessSync,
139
+ appendFileSync,
140
+ readlinkSync,
141
+ linkSync,
142
+ truncateSync,
143
+ chmodSync,
144
+ chownSync,
51
145
  watch,
146
+ // Streams
52
147
  createReadStream,
53
148
  ReadStream,
149
+ createWriteStream,
150
+ WriteStream,
151
+ // Promises
54
152
  promises,
153
+ // Callback API
55
154
  open,
56
155
  close,
57
156
  read,
@@ -61,10 +160,29 @@ export {
61
160
  readdir,
62
161
  symlink,
63
162
  lstat,
163
+ stat,
164
+ rename,
165
+ copyFile,
166
+ access,
167
+ appendFile,
168
+ readlink,
169
+ truncate,
170
+ chmod,
171
+ chown,
172
+ mkdir,
173
+ rmdir,
174
+ readFile,
175
+ writeFile,
176
+ unlink,
177
+ link,
64
178
  };
65
179
 
66
180
  export default {
67
181
  FSWatcher,
182
+ Stats,
183
+ BigIntStats,
184
+ Dirent,
185
+ constants,
68
186
  existsSync,
69
187
  readdirSync,
70
188
  readFileSync,
@@ -79,9 +197,20 @@ export default {
79
197
  realpathSync,
80
198
  symlinkSync,
81
199
  lstatSync,
200
+ renameSync,
201
+ copyFileSync,
202
+ accessSync,
203
+ appendFileSync,
204
+ readlinkSync,
205
+ linkSync,
206
+ truncateSync,
207
+ chmodSync,
208
+ chownSync,
82
209
  watch,
83
210
  createReadStream,
84
211
  ReadStream,
212
+ createWriteStream,
213
+ WriteStream,
85
214
  promises,
86
215
  open,
87
216
  close,
@@ -92,4 +221,19 @@ export default {
92
221
  readdir,
93
222
  symlink,
94
223
  lstat,
95
- };
224
+ stat,
225
+ rename,
226
+ copyFile,
227
+ access,
228
+ appendFile,
229
+ readlink,
230
+ truncate,
231
+ chmod,
232
+ chown,
233
+ mkdir,
234
+ rmdir,
235
+ readFile,
236
+ writeFile,
237
+ unlink,
238
+ link,
239
+ };
@@ -0,0 +1,505 @@
1
+ // Ported from refs/node/test/parallel/test-fs-*.js
2
+ // Original: MIT license, Node.js contributors
3
+
4
+ import { describe, it, expect } from '@gjsify/unit';
5
+ import {
6
+ existsSync, mkdtempSync, rmdirSync, rmSync, writeFileSync, readFileSync,
7
+ renameSync, copyFileSync, accessSync, appendFileSync, readlinkSync,
8
+ symlinkSync, unlinkSync, truncateSync, createReadStream, createWriteStream,
9
+ constants, mkdirSync,
10
+ rename, copyFile, access, appendFile, readFile, writeFile,
11
+ } from 'node:fs';
12
+ import * as promises from 'node:fs/promises';
13
+ import { Buffer } from 'node:buffer';
14
+ import { join } from 'node:path';
15
+
16
+ export default async () => {
17
+
18
+ // ==================== constants ====================
19
+
20
+ await describe('fs.constants', async () => {
21
+ await it('should export F_OK, R_OK, W_OK, X_OK', async () => {
22
+ expect(constants.F_OK).toBe(0);
23
+ expect(constants.R_OK).toBe(4);
24
+ expect(constants.W_OK).toBe(2);
25
+ expect(constants.X_OK).toBe(1);
26
+ });
27
+
28
+ await it('should export COPYFILE_EXCL', async () => {
29
+ expect(constants.COPYFILE_EXCL).toBe(1);
30
+ });
31
+
32
+ await it('should export file type constants', async () => {
33
+ expect(constants.S_IFMT).toBeDefined();
34
+ expect(constants.S_IFREG).toBeDefined();
35
+ expect(constants.S_IFDIR).toBeDefined();
36
+ });
37
+
38
+ await it('should export file mode constants', async () => {
39
+ expect(constants.S_IRUSR).toBeDefined();
40
+ expect(constants.S_IWUSR).toBeDefined();
41
+ expect(constants.S_IXUSR).toBeDefined();
42
+ });
43
+ });
44
+
45
+ // ==================== renameSync ====================
46
+
47
+ await describe('fs.renameSync', async () => {
48
+ await it('should rename a file', async () => {
49
+ const dir = mkdtempSync('fs-test-');
50
+ const oldPath = join(dir, 'old.txt');
51
+ const newPath = join(dir, 'new.txt');
52
+ writeFileSync(oldPath, 'content');
53
+ renameSync(oldPath, newPath);
54
+
55
+ expect(existsSync(newPath)).toBeTruthy();
56
+ expect(existsSync(oldPath)).toBeFalsy();
57
+ expect(String(readFileSync(newPath, 'utf-8'))).toBe('content');
58
+
59
+ rmSync(newPath);
60
+ rmdirSync(dir);
61
+ });
62
+ });
63
+
64
+ // ==================== rename (callback) ====================
65
+
66
+ await describe('fs.rename (callback)', async () => {
67
+ await it('should rename a file asynchronously', async () => {
68
+ const dir = mkdtempSync('fs-test-');
69
+ const oldPath = join(dir, 'old.txt');
70
+ const newPath = join(dir, 'new.txt');
71
+ writeFileSync(oldPath, 'data');
72
+
73
+ await new Promise<void>((resolve, reject) => {
74
+ rename(oldPath, newPath, (err) => {
75
+ if (err) reject(err);
76
+ else resolve();
77
+ });
78
+ });
79
+
80
+ expect(existsSync(newPath)).toBeTruthy();
81
+ expect(existsSync(oldPath)).toBeFalsy();
82
+
83
+ rmSync(newPath);
84
+ rmdirSync(dir);
85
+ });
86
+ });
87
+
88
+ // ==================== copyFileSync ====================
89
+
90
+ await describe('fs.copyFileSync', async () => {
91
+ await it('should copy a file', async () => {
92
+ const dir = mkdtempSync('fs-test-');
93
+ const src = join(dir, 'src.txt');
94
+ const dest = join(dir, 'dest.txt');
95
+ writeFileSync(src, 'copy me');
96
+ copyFileSync(src, dest);
97
+
98
+ expect(existsSync(dest)).toBeTruthy();
99
+ expect(String(readFileSync(dest, 'utf-8'))).toBe('copy me');
100
+
101
+ rmSync(src);
102
+ rmSync(dest);
103
+ rmdirSync(dir);
104
+ });
105
+
106
+ await it('should overwrite existing file by default', async () => {
107
+ const dir = mkdtempSync('fs-test-');
108
+ const src = join(dir, 'src.txt');
109
+ const dest = join(dir, 'dest.txt');
110
+ writeFileSync(src, 'new content');
111
+ writeFileSync(dest, 'old content');
112
+ copyFileSync(src, dest);
113
+
114
+ expect(String(readFileSync(dest, 'utf-8'))).toBe('new content');
115
+
116
+ rmSync(src);
117
+ rmSync(dest);
118
+ rmdirSync(dir);
119
+ });
120
+ });
121
+
122
+ // ==================== copyFile (callback) ====================
123
+
124
+ await describe('fs.copyFile (callback)', async () => {
125
+ await it('should copy a file asynchronously', async () => {
126
+ const dir = mkdtempSync('fs-test-');
127
+ const src = join(dir, 'src.txt');
128
+ const dest = join(dir, 'dest.txt');
129
+ writeFileSync(src, 'async copy');
130
+
131
+ await new Promise<void>((resolve, reject) => {
132
+ copyFile(src, dest, (err) => {
133
+ if (err) reject(err);
134
+ else resolve();
135
+ });
136
+ });
137
+
138
+ expect(existsSync(dest)).toBeTruthy();
139
+
140
+ rmSync(src);
141
+ rmSync(dest);
142
+ rmdirSync(dir);
143
+ });
144
+ });
145
+
146
+ // ==================== accessSync ====================
147
+
148
+ await describe('fs.accessSync', async () => {
149
+ await it('should not throw for existing file with F_OK', async () => {
150
+ const dir = mkdtempSync('fs-test-');
151
+ const file = join(dir, 'test.txt');
152
+ writeFileSync(file, '');
153
+
154
+ let threw = false;
155
+ try {
156
+ accessSync(file, constants.F_OK);
157
+ } catch {
158
+ threw = true;
159
+ }
160
+ expect(threw).toBeFalsy();
161
+
162
+ rmSync(file);
163
+ rmdirSync(dir);
164
+ });
165
+
166
+ await it('should throw for non-existing file', async () => {
167
+ let threw = false;
168
+ try {
169
+ accessSync('/nonexistent/path/file.txt');
170
+ } catch {
171
+ threw = true;
172
+ }
173
+ expect(threw).toBeTruthy();
174
+ });
175
+
176
+ await it('should check read permission with R_OK', async () => {
177
+ const dir = mkdtempSync('fs-test-');
178
+ const file = join(dir, 'test.txt');
179
+ writeFileSync(file, '');
180
+
181
+ let threw = false;
182
+ try {
183
+ accessSync(file, constants.R_OK);
184
+ } catch {
185
+ threw = true;
186
+ }
187
+ expect(threw).toBeFalsy();
188
+
189
+ rmSync(file);
190
+ rmdirSync(dir);
191
+ });
192
+ });
193
+
194
+ // ==================== access (callback) ====================
195
+
196
+ await describe('fs.access (callback)', async () => {
197
+ await it('should callback without error for existing file', async () => {
198
+ const dir = mkdtempSync('fs-test-');
199
+ const file = join(dir, 'test.txt');
200
+ writeFileSync(file, '');
201
+
202
+ await new Promise<void>((resolve, reject) => {
203
+ access(file, (err) => {
204
+ if (err) reject(err);
205
+ else resolve();
206
+ });
207
+ });
208
+
209
+ rmSync(file);
210
+ rmdirSync(dir);
211
+ });
212
+
213
+ await it('should callback with error for non-existing file', async () => {
214
+ const err = await new Promise<Error>((resolve) => {
215
+ access('/nonexistent/path', (e) => {
216
+ resolve(e as Error);
217
+ });
218
+ });
219
+ expect(err).toBeDefined();
220
+ });
221
+ });
222
+
223
+ // ==================== appendFileSync ====================
224
+
225
+ await describe('fs.appendFileSync', async () => {
226
+ await it('should append data to a file', async () => {
227
+ const dir = mkdtempSync('fs-test-');
228
+ const file = join(dir, 'append.txt');
229
+ writeFileSync(file, 'hello');
230
+ appendFileSync(file, ' world');
231
+
232
+ expect(String(readFileSync(file, 'utf-8'))).toBe('hello world');
233
+
234
+ rmSync(file);
235
+ rmdirSync(dir);
236
+ });
237
+
238
+ await it('should create file if it does not exist', async () => {
239
+ const dir = mkdtempSync('fs-test-');
240
+ const file = join(dir, 'new.txt');
241
+ appendFileSync(file, 'created');
242
+
243
+ expect(existsSync(file)).toBeTruthy();
244
+ expect(String(readFileSync(file, 'utf-8'))).toBe('created');
245
+
246
+ rmSync(file);
247
+ rmdirSync(dir);
248
+ });
249
+ });
250
+
251
+ // ==================== appendFile (callback) ====================
252
+
253
+ await describe('fs.appendFile (callback)', async () => {
254
+ await it('should append data asynchronously', async () => {
255
+ const dir = mkdtempSync('fs-test-');
256
+ const file = join(dir, 'append.txt');
257
+ writeFileSync(file, 'start');
258
+
259
+ await new Promise<void>((resolve, reject) => {
260
+ appendFile(file, '-end', (err) => {
261
+ if (err) reject(err);
262
+ else resolve();
263
+ });
264
+ });
265
+
266
+ expect(String(readFileSync(file, 'utf-8'))).toBe('start-end');
267
+
268
+ rmSync(file);
269
+ rmdirSync(dir);
270
+ });
271
+ });
272
+
273
+ // ==================== truncateSync ====================
274
+
275
+ await describe('fs.truncateSync', async () => {
276
+ await it('should truncate a file to 0 bytes', async () => {
277
+ const dir = mkdtempSync('fs-test-');
278
+ const file = join(dir, 'truncate.txt');
279
+ writeFileSync(file, 'hello world');
280
+ truncateSync(file);
281
+
282
+ expect(String(readFileSync(file, 'utf-8'))).toBe('');
283
+
284
+ rmSync(file);
285
+ rmdirSync(dir);
286
+ });
287
+ });
288
+
289
+ // ==================== readlinkSync ====================
290
+
291
+ await describe('fs.readlinkSync', async () => {
292
+ await it('should read symlink target', async () => {
293
+ const dir = mkdtempSync('fs-test-');
294
+ const target = join(dir, 'target.txt');
295
+ const link = join(dir, 'link.txt');
296
+ writeFileSync(target, 'data');
297
+ symlinkSync(target, link);
298
+
299
+ const result = readlinkSync(link);
300
+ expect(String(result)).toBe(target);
301
+
302
+ unlinkSync(link);
303
+ rmSync(target);
304
+ rmdirSync(dir);
305
+ });
306
+ });
307
+
308
+ // ==================== readFile / writeFile (callback) ====================
309
+
310
+ await describe('fs.readFile / fs.writeFile (callback)', async () => {
311
+ await it('should write and read a file', async () => {
312
+ const dir = mkdtempSync('fs-test-');
313
+ const file = join(dir, 'rw.txt');
314
+
315
+ await new Promise<void>((resolve, reject) => {
316
+ writeFile(file, 'callback data', (err) => {
317
+ if (err) reject(err);
318
+ else resolve();
319
+ });
320
+ });
321
+
322
+ const data = await new Promise<string>((resolve, reject) => {
323
+ readFile(file, 'utf-8', (err, data) => {
324
+ if (err) reject(err);
325
+ else resolve(String(data));
326
+ });
327
+ });
328
+
329
+ expect(data).toBe('callback data');
330
+
331
+ rmSync(file);
332
+ rmdirSync(dir);
333
+ });
334
+ });
335
+
336
+ // ==================== createReadStream ====================
337
+
338
+ await describe('fs.createReadStream', async () => {
339
+ await it('should read file contents via stream', async () => {
340
+ const dir = mkdtempSync('fs-test-');
341
+ const file = join(dir, 'stream.txt');
342
+ writeFileSync(file, 'stream data');
343
+
344
+ const rs = createReadStream(file);
345
+ const chunks: Buffer[] = [];
346
+
347
+ await new Promise<void>((resolve, reject) => {
348
+ rs.on('data', (chunk: Buffer) => chunks.push(chunk));
349
+ rs.on('end', () => resolve());
350
+ rs.on('error', reject);
351
+ });
352
+
353
+ const content = Buffer.concat(chunks).toString('utf-8');
354
+ expect(content).toBe('stream data');
355
+ expect(rs.bytesRead).toBe(11);
356
+
357
+ rmSync(file);
358
+ rmdirSync(dir);
359
+ });
360
+
361
+ await it('should emit open and ready events', async () => {
362
+ const dir = mkdtempSync('fs-test-');
363
+ const file = join(dir, 'events.txt');
364
+ writeFileSync(file, 'test');
365
+
366
+ const rs = createReadStream(file);
367
+ let openEmitted = false;
368
+ let readyEmitted = false;
369
+
370
+ rs.on('open', () => { openEmitted = true; });
371
+ rs.on('ready', () => { readyEmitted = true; });
372
+
373
+ await new Promise<void>((resolve) => {
374
+ rs.on('end', () => resolve());
375
+ rs.resume();
376
+ });
377
+
378
+ expect(openEmitted).toBeTruthy();
379
+ expect(readyEmitted).toBeTruthy();
380
+
381
+ rmSync(file);
382
+ rmdirSync(dir);
383
+ });
384
+ });
385
+
386
+ // ==================== createWriteStream ====================
387
+
388
+ await describe('fs.createWriteStream', async () => {
389
+ await it('should write file contents via stream', async () => {
390
+ const dir = mkdtempSync('fs-test-');
391
+ const file = join(dir, 'ws.txt');
392
+
393
+ const ws = createWriteStream(file, {});
394
+
395
+ await new Promise<void>((resolve, reject) => {
396
+ ws.on('open', () => {
397
+ ws.write('hello ');
398
+ ws.end('world');
399
+ });
400
+ ws.on('finish', () => resolve());
401
+ ws.on('error', reject);
402
+ });
403
+
404
+ const content = String(readFileSync(file, 'utf-8'));
405
+ expect(content).toBe('hello world');
406
+
407
+ rmSync(file);
408
+ rmdirSync(dir);
409
+ });
410
+ });
411
+
412
+ // ==================== promises.rename ====================
413
+
414
+ await describe('fs.promises.rename', async () => {
415
+ await it('should rename a file', async () => {
416
+ const dir = mkdtempSync('fs-test-');
417
+ const oldPath = join(dir, 'old.txt');
418
+ const newPath = join(dir, 'new.txt');
419
+ writeFileSync(oldPath, 'data');
420
+
421
+ await promises.rename(oldPath, newPath);
422
+ expect(existsSync(newPath)).toBeTruthy();
423
+ expect(existsSync(oldPath)).toBeFalsy();
424
+
425
+ rmSync(newPath);
426
+ rmdirSync(dir);
427
+ });
428
+ });
429
+
430
+ // ==================== promises.copyFile ====================
431
+
432
+ await describe('fs.promises.copyFile', async () => {
433
+ await it('should copy a file', async () => {
434
+ const dir = mkdtempSync('fs-test-');
435
+ const src = join(dir, 'src.txt');
436
+ const dest = join(dir, 'dest.txt');
437
+ writeFileSync(src, 'copy data');
438
+
439
+ await promises.copyFile(src, dest);
440
+ expect(existsSync(dest)).toBeTruthy();
441
+ expect(String(readFileSync(dest, 'utf-8'))).toBe('copy data');
442
+
443
+ rmSync(src);
444
+ rmSync(dest);
445
+ rmdirSync(dir);
446
+ });
447
+ });
448
+
449
+ // ==================== promises.access ====================
450
+
451
+ await describe('fs.promises.access', async () => {
452
+ await it('should resolve for existing file', async () => {
453
+ const dir = mkdtempSync('fs-test-');
454
+ const file = join(dir, 'test.txt');
455
+ writeFileSync(file, '');
456
+
457
+ await promises.access(file);
458
+
459
+ rmSync(file);
460
+ rmdirSync(dir);
461
+ });
462
+
463
+ await it('should reject for non-existing file', async () => {
464
+ let threw = false;
465
+ try {
466
+ await promises.access('/nonexistent/path/file.txt');
467
+ } catch {
468
+ threw = true;
469
+ }
470
+ expect(threw).toBeTruthy();
471
+ });
472
+ });
473
+
474
+ // ==================== promises.appendFile ====================
475
+
476
+ await describe('fs.promises.appendFile', async () => {
477
+ await it('should append data to a file', async () => {
478
+ const dir = mkdtempSync('fs-test-');
479
+ const file = join(dir, 'append.txt');
480
+ writeFileSync(file, 'hello');
481
+
482
+ await promises.appendFile(file, ' world');
483
+ expect(String(readFileSync(file, 'utf-8'))).toBe('hello world');
484
+
485
+ rmSync(file);
486
+ rmdirSync(dir);
487
+ });
488
+ });
489
+
490
+ // ==================== promises.truncate ====================
491
+
492
+ await describe('fs.promises.truncate', async () => {
493
+ await it('should truncate a file', async () => {
494
+ const dir = mkdtempSync('fs-test-');
495
+ const file = join(dir, 'trunc.txt');
496
+ writeFileSync(file, 'hello world');
497
+
498
+ await promises.truncate(file);
499
+ expect(String(readFileSync(file, 'utf-8'))).toBe('');
500
+
501
+ rmSync(file);
502
+ rmdirSync(dir);
503
+ });
504
+ });
505
+ };