@fncts/node 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/_src/fs/api.ts ADDED
@@ -0,0 +1,580 @@
1
+ import * as fs from "fs";
2
+
3
+ type ErrnoException = NodeJS.ErrnoException;
4
+
5
+ interface FileDescriptorN extends HKT {
6
+ readonly [HKT.T]: FileDescriptor;
7
+ }
8
+ export interface FileDescriptor
9
+ extends Newtype<
10
+ {
11
+ readonly FileDescriptor: unique symbol;
12
+ },
13
+ number
14
+ > {}
15
+ export const FileDescriptor = Newtype<FileDescriptorN>();
16
+
17
+ function unitErrorCallback(cb: (_: IO<unknown, ErrnoException, void>) => void): (err: ErrnoException | null) => void {
18
+ return (err) => (err ? cb(IO.fail(err)) : cb(IO.unit));
19
+ }
20
+
21
+ export function access(path: fs.PathLike, mode: number | undefined): FIO<ErrnoException, void> {
22
+ return IO.async<unknown, ErrnoException, void>((cb) => {
23
+ fs.access(path, mode, (err) => (err ? cb(IO.fail(err)) : cb(IO.unit)));
24
+ });
25
+ }
26
+
27
+ export function appendFile(
28
+ path: fs.PathLike | FileDescriptor,
29
+ data: string | Buffer,
30
+ options?: fs.WriteFileOptions,
31
+ ): FIO<ErrnoException, void> {
32
+ return IO.async<unknown, ErrnoException, void>((cb) => {
33
+ fs.appendFile(path as any, data, options ?? {}, (err) => (err ? cb(IO.fail(err)) : cb(IO.unit)));
34
+ });
35
+ }
36
+
37
+ export function chmod(path: fs.PathLike, mode: fs.Mode): FIO<ErrnoException, void> {
38
+ return IO.async<unknown, ErrnoException, void>((cb) => {
39
+ fs.chmod(path, mode, (err) => (err ? cb(IO.fail(err)) : cb(IO.unit)));
40
+ });
41
+ }
42
+
43
+ export function close(fd: FileDescriptor): FIO<ErrnoException, void> {
44
+ return IO.async<unknown, ErrnoException, void>((cb) => {
45
+ fs.close(FileDescriptor.reverseGet(fd), (err) => (err ? cb(IO.fail(err)) : cb(IO.unit)));
46
+ });
47
+ }
48
+
49
+ export function chown(path: fs.PathLike, uid: number, gid: number): FIO<ErrnoException, void> {
50
+ return IO.async<unknown, ErrnoException, void>((cb) => {
51
+ fs.chown(path, uid, gid, (err) => (err ? cb(IO.fail(err)) : cb(IO.unit)));
52
+ });
53
+ }
54
+
55
+ export function copyFile(src: fs.PathLike, dest: fs.PathLike, flags: number): FIO<ErrnoException, void> {
56
+ return IO.async<unknown, ErrnoException, void>((cb) => {
57
+ fs.copyFile(src, dest, flags, (err) => (err ? cb(IO.fail(err)) : cb(IO.unit)));
58
+ });
59
+ }
60
+
61
+ interface CreateReadStreamOptions {
62
+ chunkSize?: number;
63
+ flags?: fs.OpenMode;
64
+ mode?: string | number;
65
+ start?: number;
66
+ end?: number;
67
+ }
68
+
69
+ export function createReadStream(
70
+ path: fs.PathLike,
71
+ options?: CreateReadStreamOptions,
72
+ ): Stream<unknown, ErrnoException, Byte> {
73
+ const chunkSize = options?.chunkSize ?? 1024 * 64;
74
+ return Stream.acquireRelease(
75
+ open(path, options?.flags ?? fs.constants.O_RDONLY, options?.mode).zipC(
76
+ IO.defer(() => {
77
+ const start = options?.start ?? 0;
78
+ const end = options?.end ?? Infinity;
79
+ if (end < start) {
80
+ return IO.fail(new RangeError(`start (${start}) must be <= end (${end})`));
81
+ } else {
82
+ return Ref.make([start, end] as const);
83
+ }
84
+ }),
85
+ ),
86
+ ([fd, _]) => close(fd).orHalt,
87
+ ).flatMap(([fd, state]) =>
88
+ Stream.repeatIOChunkMaybe(
89
+ Do((Δ) => {
90
+ const [pos, end] = Δ(state.get);
91
+ const n = Math.min(end - pos + 1, chunkSize);
92
+ const [bytes, chunk] = Δ(read(fd, n, pos).mapError(Maybe.just));
93
+
94
+ Δ(IO.fail(Nothing()).when(() => bytes === 0));
95
+ Δ(state.set([pos + n, end]));
96
+ if (bytes !== chunk.length) {
97
+ const dst = Buffer.allocUnsafeSlow(bytes);
98
+ chunk.copy(dst, 0, 0, bytes);
99
+ return Conc.fromBuffer(dst);
100
+ } else {
101
+ return Conc.fromBuffer(chunk);
102
+ }
103
+ }),
104
+ ),
105
+ );
106
+ }
107
+
108
+ interface CreateWriteSinkOptions {
109
+ flags?: fs.OpenMode;
110
+ mode?: string | number;
111
+ start?: number;
112
+ }
113
+
114
+ export function createWriteSink<InErr>(
115
+ path: fs.PathLike,
116
+ options?: CreateWriteSinkOptions,
117
+ ): Sink<unknown, InErr | ErrnoException, Byte, never, void> {
118
+ return new Sink(
119
+ Channel.unwrapScoped(
120
+ Do((_) => {
121
+ const errorRef = _(Ref.make<Maybe<ErrnoException>>(Nothing()));
122
+ const st = _(
123
+ open(path, options?.flags ?? fs.constants.O_CREAT | fs.constants.O_WRONLY, options?.mode)
124
+ .zipC(Ref.make(options?.start ?? undefined))
125
+ .acquireRelease(([fd, _]) => close(fd).orHalt)
126
+ .catchAll((err) => errorRef.set(Just(err))),
127
+ );
128
+
129
+ const maybeError = _(errorRef.get);
130
+ if (!st && maybeError.isJust()) {
131
+ const reader = Channel.readWith(
132
+ (_: Conc<Byte>) => Channel.fail(maybeError.value) > Channel.end(undefined),
133
+ (err: InErr) => Channel.failCause(Cause.then(Cause.fail(maybeError.value), Cause.fail(err))),
134
+ (_: unknown) => Channel.fail(maybeError.value),
135
+ );
136
+ return reader;
137
+ } else {
138
+ const reader: Channel<
139
+ unknown,
140
+ InErr,
141
+ Conc<Byte>,
142
+ unknown,
143
+ InErr | ErrnoException,
144
+ Conc<never>,
145
+ void
146
+ > = Channel.readWith(
147
+ (inp: Conc<Byte>) =>
148
+ Channel.unwrap(
149
+ st![1].get
150
+ .flatMap((pos) => write(st[0], inp, pos))
151
+ .flatMap(() => st![1].update((n) => (n !== undefined ? n + inp.length : undefined)))
152
+ .map(() => reader),
153
+ ),
154
+ (err) => Channel.fail(err),
155
+ (_: unknown) => Channel.end(undefined),
156
+ );
157
+ return reader;
158
+ }
159
+ }),
160
+ ),
161
+ );
162
+ }
163
+
164
+ export function fchmod(fd: FileDescriptor, mode: fs.Mode): FIO<ErrnoException, void> {
165
+ return IO.async<unknown, ErrnoException, void>((cb) => {
166
+ fs.fchmod(FileDescriptor.reverseGet(fd), mode, unitErrorCallback(cb));
167
+ });
168
+ }
169
+
170
+ export function fchown(fd: FileDescriptor, uid: number, gid: number): FIO<ErrnoException, void> {
171
+ return IO.async<unknown, ErrnoException, void>((cb) => {
172
+ fs.fchown(FileDescriptor.reverseGet(fd), uid, gid, unitErrorCallback(cb));
173
+ });
174
+ }
175
+
176
+ export function fdatasync(fd: FileDescriptor): FIO<ErrnoException, void> {
177
+ return IO.async<unknown, ErrnoException, void>((cb) => {
178
+ fs.fdatasync(FileDescriptor.reverseGet(fd), unitErrorCallback(cb));
179
+ });
180
+ }
181
+
182
+ export function fstat(fd: FileDescriptor): FIO<ErrnoException, fs.Stats> {
183
+ return IO.async<unknown, ErrnoException, fs.Stats>((cb) => {
184
+ fs.fstat(FileDescriptor.reverseGet(fd), (err, stats) => (err ? cb(IO.fail(err)) : cb(IO.succeedNow(stats))));
185
+ });
186
+ }
187
+
188
+ export function fsync(fd: FileDescriptor): FIO<ErrnoException, void> {
189
+ return IO.async<unknown, ErrnoException, void>((cb) => {
190
+ fs.fsync(FileDescriptor.reverseGet(fd), unitErrorCallback(cb));
191
+ });
192
+ }
193
+
194
+ export function ftruncate(fd: FileDescriptor, len: number): FIO<ErrnoException, void> {
195
+ return IO.async<unknown, ErrnoException, void>((cb) => {
196
+ fs.ftruncate(FileDescriptor.reverseGet(fd), len, unitErrorCallback(cb));
197
+ });
198
+ }
199
+
200
+ export function futimes(
201
+ fd: FileDescriptor,
202
+ atime: string | number | Date,
203
+ mtime: string | number | Date,
204
+ ): FIO<ErrnoException, void> {
205
+ return IO.async<unknown, ErrnoException, void>((cb) => {
206
+ fs.futimes(FileDescriptor.reverseGet(fd), atime, mtime, unitErrorCallback(cb));
207
+ });
208
+ }
209
+
210
+ export function lchmod(path: fs.PathLike, mode: fs.Mode): FIO<ErrnoException, void> {
211
+ return IO.async<unknown, ErrnoException, void>((cb) => {
212
+ fs.lchmod(path, mode, unitErrorCallback(cb));
213
+ });
214
+ }
215
+
216
+ export function lchown(path: fs.PathLike, uid: number, gid: number): FIO<ErrnoException, void> {
217
+ return IO.async<unknown, ErrnoException, void>((cb) => {
218
+ fs.lchown(path, uid, gid, unitErrorCallback(cb));
219
+ });
220
+ }
221
+
222
+ export function lutimes(
223
+ path: fs.PathLike,
224
+ atime: string | number | Date,
225
+ mtime: string | number | Date,
226
+ ): FIO<ErrnoException, void> {
227
+ return IO.async<unknown, ErrnoException, void>((cb) => {
228
+ fs.lutimes(path, atime, mtime, unitErrorCallback(cb));
229
+ });
230
+ }
231
+
232
+ export function link(path: fs.PathLike, newPath: fs.PathLike): FIO<ErrnoException, void> {
233
+ return IO.async<unknown, ErrnoException, void>((cb) => {
234
+ fs.link(path, newPath, (err) => (err ? cb(IO.fail(err)) : cb(IO.unit)));
235
+ });
236
+ }
237
+
238
+ export function lstat(path: fs.PathLike): FIO<ErrnoException, fs.Stats> {
239
+ return IO.async<unknown, ErrnoException, fs.Stats>((cb) => {
240
+ fs.lstat(path, (err, stats) => (err ? cb(IO.fail(err)) : cb(IO.succeedNow(stats))));
241
+ });
242
+ }
243
+
244
+ export function mkdir(
245
+ path: fs.PathLike,
246
+ options?: { recursive?: boolean; mode?: fs.Mode },
247
+ ): FIO<ErrnoException, Maybe<string>> {
248
+ return IO.async<unknown, ErrnoException, Maybe<string>>((cb) => {
249
+ fs.mkdir(path, options, (err, path) => (err ? cb(IO.fail(err)) : cb(IO.succeed(Maybe.fromNullable(path)))));
250
+ });
251
+ }
252
+
253
+ export function mkdtemp(prefix: string, options?: { encoding?: BufferEncoding }): FIO<ErrnoException, string> {
254
+ return IO.async<unknown, ErrnoException, string>((cb) => {
255
+ fs.mkdtemp(prefix, options, (err, folder) => (err ? cb(IO.failNow(err)) : cb(IO.succeedNow(folder))));
256
+ });
257
+ }
258
+
259
+ export function open(
260
+ path: fs.PathLike,
261
+ flags: fs.OpenMode,
262
+ mode?: string | number,
263
+ ): FIO<NodeJS.ErrnoException, FileDescriptor> {
264
+ return IO.async<unknown, ErrnoException, FileDescriptor>((cb) => {
265
+ fs.open(path, flags, mode ?? null, (err, fd) => (err ? cb(IO.fail(err)) : cb(IO.succeed(FileDescriptor.get(fd)))));
266
+ });
267
+ }
268
+
269
+ export class Dir {
270
+ readonly path: string;
271
+ private readonly _dir: fs.Dir;
272
+ constructor(dir: fs.Dir) {
273
+ this.path = dir.path;
274
+ this._dir = dir;
275
+ }
276
+
277
+ close(): FIO<ErrnoException, void> {
278
+ return IO.async<unknown, ErrnoException, void>((cb) => {
279
+ this._dir.close(unitErrorCallback(cb));
280
+ });
281
+ }
282
+
283
+ read(): FIO<ErrnoException, Maybe<fs.Dirent>> {
284
+ return IO.async<unknown, ErrnoException, Maybe<fs.Dirent>>((cb) => {
285
+ this._dir.read((err, dirEnt) => (err ? cb(IO.fail(err)) : cb(IO.succeedNow(Maybe.fromNullable(dirEnt)))));
286
+ });
287
+ }
288
+ }
289
+
290
+ export function opendir(path: fs.PathLike, options?: fs.OpenDirOptions): FIO<ErrnoException, Dir> {
291
+ return IO.async<unknown, ErrnoException, Dir>((cb) => {
292
+ fs.opendir(path as any, options ?? {}, (err, dir) => (err ? cb(IO.fail(err)) : cb(IO.succeedNow(new Dir(dir)))));
293
+ });
294
+ }
295
+
296
+ export function read(
297
+ fd: FileDescriptor,
298
+ length: number,
299
+ position?: number,
300
+ ): FIO<ErrnoException, readonly [number, Buffer]> {
301
+ return IO.async<unknown, ErrnoException, readonly [number, Buffer]>((cb) => {
302
+ const buf = Buffer.alloc(length);
303
+ fs.read(FileDescriptor.reverseGet(fd), buf, 0, length, position ?? null, (err, bytesRead, buffer) =>
304
+ err ? cb(IO.fail(err)) : cb(IO.succeed([bytesRead, buffer])),
305
+ );
306
+ });
307
+ }
308
+
309
+ export function readFile(
310
+ file: fs.PathOrFileDescriptor,
311
+ options: { flag?: string; encoding: BufferEncoding },
312
+ ): FIO<ErrnoException, string>;
313
+ export function readFile(file: fs.PathOrFileDescriptor, options?: { flag?: string }): FIO<ErrnoException, Buffer>;
314
+ export function readFile(
315
+ file: fs.PathOrFileDescriptor,
316
+ options: { flag?: string; encoding?: BufferEncoding | null | undefined } = {},
317
+ ): FIO<ErrnoException, string | Buffer> {
318
+ return IO.asyncInterrupt((cb) => {
319
+ const abortController = new AbortController();
320
+ fs.readFile(file, { ...options, signal: abortController.signal }, (err, data) =>
321
+ err ? cb(IO.fail(err)) : cb(IO.succeedNow(data)),
322
+ );
323
+ return Either.left(IO.succeed(abortController.abort()));
324
+ });
325
+ }
326
+
327
+ export function readdir(
328
+ path: fs.PathLike,
329
+ options?: {
330
+ encoding?: BufferEncoding;
331
+ withFileTypes?: false;
332
+ },
333
+ ): FIO<ErrnoException, ReadonlyArray<string>>;
334
+ export function readdir(
335
+ path: fs.PathLike,
336
+ options: {
337
+ encoding: "buffer";
338
+ withFileTypes?: false;
339
+ },
340
+ ): FIO<ErrnoException, ReadonlyArray<Buffer>>;
341
+ export function readdir(
342
+ path: fs.PathLike,
343
+ options: {
344
+ encoding?: BufferEncoding;
345
+ withFileTypes: true;
346
+ },
347
+ ): FIO<ErrnoException, ReadonlyArray<Dir>>;
348
+ export function readdir(
349
+ path: fs.PathLike,
350
+ options?: {
351
+ encoding?: BufferEncoding | "buffer";
352
+ withFileTypes?: boolean;
353
+ },
354
+ ): FIO<ErrnoException, ReadonlyArray<any>> {
355
+ return IO.async((cb) => {
356
+ fs.readdir(path, options ?? ({} as any), (err, files: Array<any>) =>
357
+ err ? cb(IO.fail(err)) : files[0] && files[0] instanceof fs.Dir ? files.map((a: fs.Dir) => new Dir(a)) : files,
358
+ );
359
+ });
360
+ }
361
+
362
+ export function realpath(
363
+ path: fs.PathLike,
364
+ options?: {
365
+ encoding?: BufferEncoding;
366
+ },
367
+ ): FIO<ErrnoException, string>;
368
+ export function realpath(
369
+ path: fs.PathLike,
370
+ options: {
371
+ encoding: "buffer";
372
+ },
373
+ ): FIO<ErrnoException, Buffer>;
374
+ export function realpath(path: fs.PathLike, options?: any): FIO<ErrnoException, any> {
375
+ return IO.async<unknown, ErrnoException, any>((cb) => {
376
+ fs.realpath(path, options ?? {}, (err, resolvedPath) => (err ? cb(IO.fail(err)) : cb(IO.succeedNow(resolvedPath))));
377
+ });
378
+ }
379
+
380
+ export function realpathNative(
381
+ path: fs.PathLike,
382
+ options?: {
383
+ encoding?: BufferEncoding;
384
+ },
385
+ ): FIO<ErrnoException, string>;
386
+ export function realpathNative(
387
+ path: fs.PathLike,
388
+ options: {
389
+ encoding: "buffer";
390
+ },
391
+ ): FIO<ErrnoException, Buffer>;
392
+ export function realpathNative(path: fs.PathLike, options?: any): FIO<ErrnoException, any> {
393
+ return IO.async<unknown, ErrnoException, any>((cb) => {
394
+ fs.realpath.native(path, options ?? {}, (err, resolvedPath) =>
395
+ err ? cb(IO.fail(err)) : cb(IO.succeed(resolvedPath)),
396
+ );
397
+ });
398
+ }
399
+
400
+ export function rename(oldPath: fs.PathLike, newPath: fs.PathLike): FIO<ErrnoException, void> {
401
+ return IO.async<unknown, ErrnoException, void>((cb) => {
402
+ fs.rename(oldPath, newPath, unitErrorCallback(cb));
403
+ });
404
+ }
405
+
406
+ export function rm(path: fs.PathLike, options?: fs.RmOptions): FIO<ErrnoException, void> {
407
+ return IO.async<unknown, NodeJS.ErrnoException, void>((cb) => {
408
+ fs.rm(path, options ?? {}, unitErrorCallback(cb));
409
+ });
410
+ }
411
+
412
+ export function rmdir(path: fs.PathLike, options?: fs.RmDirOptions): FIO<ErrnoException, void> {
413
+ return IO.async<unknown, NodeJS.ErrnoException, void>((cb) => {
414
+ fs.rmdir(path, options ?? {}, unitErrorCallback(cb));
415
+ });
416
+ }
417
+
418
+ export function stat(path: fs.PathLike, options?: { bigint?: false }): FIO<ErrnoException, fs.Stats>;
419
+ export function stat(path: fs.PathLike, options: { bigint: true }): FIO<ErrnoException, fs.BigIntStats>;
420
+ export function stat(
421
+ path: fs.PathLike,
422
+ options?: { bigint?: boolean },
423
+ ): FIO<ErrnoException, fs.Stats | fs.BigIntStats> {
424
+ return IO.async<unknown, ErrnoException, fs.Stats | fs.BigIntStats>((cb) => {
425
+ fs.stat(path, options ?? ({} as any), (err, stats) => (err ? cb(IO.fail(err)) : cb(IO.succeedNow(stats))));
426
+ });
427
+ }
428
+
429
+ export function symlink(target: fs.PathLike, path: fs.PathLike): FIO<ErrnoException, void> {
430
+ return IO.async<unknown, ErrnoException, void>((cb) => {
431
+ fs.symlink(target, path, unitErrorCallback(cb));
432
+ });
433
+ }
434
+
435
+ export function truncate(path: fs.PathLike, len?: number): FIO<ErrnoException, void> {
436
+ return IO.async<unknown, ErrnoException, void>((cb) => {
437
+ fs.truncate(path, len, unitErrorCallback(cb));
438
+ });
439
+ }
440
+
441
+ export function unlink(path: fs.PathLike): FIO<ErrnoException, void> {
442
+ return IO.async<unknown, ErrnoException, void>((cb) => {
443
+ fs.unlink(path, unitErrorCallback(cb));
444
+ });
445
+ }
446
+
447
+ export function utimes(
448
+ path: fs.PathLike,
449
+ atime: string | number | Date,
450
+ mtime: string | number | Date,
451
+ ): FIO<ErrnoException, void> {
452
+ return IO.async<unknown, ErrnoException, void>((cb) => {
453
+ fs.utimes(path, atime, mtime, unitErrorCallback(cb));
454
+ });
455
+ }
456
+
457
+ export function write(fd: FileDescriptor, buffer: Conc<Byte>, position?: number): FIO<ErrnoException, number> {
458
+ return IO.async<unknown, ErrnoException, number>((cb) => {
459
+ const b = buffer.toBuffer;
460
+ fs.write(FileDescriptor.reverseGet(fd), b, position ?? null, b.byteLength, (err, bytesWritten) =>
461
+ err ? cb(IO.failNow(err)) : cb(IO.succeedNow(bytesWritten)),
462
+ );
463
+ });
464
+ }
465
+
466
+ export interface WriteFileOptions {
467
+ readonly encoding?: BufferEncoding;
468
+ readonly mode?: fs.Mode;
469
+ readonly flag?: string;
470
+ }
471
+
472
+ export function writeFile(
473
+ file: fs.PathOrFileDescriptor,
474
+ data: string | NodeJS.ArrayBufferView,
475
+ options: WriteFileOptions = {},
476
+ ): IO<unknown, ErrnoException, void> {
477
+ return IO.asyncInterrupt((cb) => {
478
+ const abortController = new AbortController();
479
+ fs.writeFile(file, data, { ...options, signal: abortController.signal }, (err) =>
480
+ err ? cb(IO.fail(err)) : IO.unit,
481
+ );
482
+ return Either.left(IO.succeed(abortController.abort()));
483
+ });
484
+ }
485
+
486
+ export function writev(
487
+ fd: FileDescriptor,
488
+ buffers: ReadonlyArray<Uint8Array>,
489
+ position?: number,
490
+ ): FIO<ErrnoException, number> {
491
+ return IO.async<unknown, ErrnoException, number>((cb) => {
492
+ if (position) {
493
+ fs.writev(FileDescriptor.reverseGet(fd), buffers, position, (err, bytesWritten) =>
494
+ err ? cb(IO.fail(err)) : cb(IO.succeedNow(bytesWritten)),
495
+ );
496
+ } else {
497
+ fs.writev(FileDescriptor.reverseGet(fd), buffers, (err, bytesWritten) =>
498
+ err ? cb(IO.fail(err)) : cb(IO.succeedNow(bytesWritten)),
499
+ );
500
+ }
501
+ });
502
+ }
503
+
504
+ export function watch(
505
+ filename: fs.PathLike,
506
+ options: {
507
+ persistent?: boolean;
508
+ recursive?: boolean;
509
+ encoding: "buffer";
510
+ },
511
+ ): Stream<unknown, Error, { eventType: "rename" | "change"; filename: Buffer }>;
512
+ export function watch(
513
+ filename: fs.PathLike,
514
+ options?: {
515
+ persistent?: boolean;
516
+ recursive?: boolean;
517
+ encoding?: BufferEncoding;
518
+ },
519
+ ): Stream<unknown, Error, { eventType: "rename" | "change"; filename: string }>;
520
+ export function watch(
521
+ filename: fs.PathLike,
522
+ options?: any,
523
+ ): Stream<unknown, Error, { eventType: "rename" | "change"; filename: string | Buffer }> {
524
+ return Stream.fromIO(
525
+ IO.tryCatch(
526
+ () => fs.watch(filename, options ?? {}),
527
+ (err) => err as Error,
528
+ ),
529
+ ).flatMap((watcher) =>
530
+ Stream.repeatIOMaybe(
531
+ IO.async<unknown, Maybe<Error>, { eventType: "rename" | "change"; filename: string | Buffer }>((cb) => {
532
+ watcher.once("change", (eventType, filename) => {
533
+ watcher.removeAllListeners();
534
+ cb(IO.succeedNow({ eventType: eventType as any, filename }));
535
+ });
536
+ watcher.once("error", (error) => {
537
+ watcher.removeAllListeners();
538
+ cb(IO.failNow(Just(error)));
539
+ });
540
+ watcher.once("close", () => {
541
+ watcher.removeAllListeners();
542
+ cb(IO.failNow(Nothing()));
543
+ });
544
+ }),
545
+ ),
546
+ );
547
+ }
548
+
549
+ export function watchFile(
550
+ filename: fs.PathLike,
551
+ options: {
552
+ bigint: true;
553
+ persistent?: boolean;
554
+ interval?: number;
555
+ },
556
+ ): Stream<unknown, never, [fs.BigIntStats, fs.BigIntStats]>;
557
+ export function watchFile(
558
+ filename: fs.PathLike,
559
+ options?: {
560
+ bigint?: false;
561
+ persistent?: boolean;
562
+ interval?: number;
563
+ },
564
+ ): Stream<unknown, never, [fs.Stats, fs.Stats]>;
565
+ export function watchFile(
566
+ filename: fs.PathLike,
567
+ options?: any,
568
+ ): Stream<unknown, never, [fs.BigIntStats | fs.Stats, fs.BigIntStats | fs.Stats]> {
569
+ return Stream.acquireRelease(
570
+ Do((_) => {
571
+ const queue = _(Queue.makeUnbounded<[fs.BigIntStats | fs.Stats, fs.BigIntStats | fs.Stats]>());
572
+ const runtime = _(IO.runtime<unknown>());
573
+ fs.watchFile(filename, options ?? {}, (curr, prev) => {
574
+ runtime.unsafeRunAsync(queue.offer([curr, prev]));
575
+ });
576
+ return queue;
577
+ }),
578
+ (queue) => queue.shutdown,
579
+ ).flatMap((queue) => Stream.repeatIOMaybe(queue.take));
580
+ }
package/_src/fs.ts ADDED
@@ -0,0 +1,3 @@
1
+ // codegen:start { preset: barrel, include: fs/*.ts }
2
+ export * from "./fs/api.js";
3
+ // codegen:end