@effect/platform-node 0.0.0 → 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.
- package/Console.d.ts +1 -11
- package/Console.d.ts.map +1 -1
- package/Console.js +10 -12
- package/Console.js.map +1 -1
- package/Path.d.ts +27 -0
- package/Path.d.ts.map +1 -0
- package/Path.js +39 -0
- package/Path.js.map +1 -0
- package/Stream.d.ts +3 -2
- package/Stream.d.ts.map +1 -1
- package/Stream.js.map +1 -1
- package/internal/fileSystem.js +55 -27
- package/internal/fileSystem.js.map +1 -1
- package/internal/path.d.ts +2 -0
- package/internal/path.d.ts.map +1 -0
- package/internal/path.js +49 -0
- package/internal/path.js.map +1 -0
- package/internal/stream.js +2 -4
- package/internal/stream.js.map +1 -1
- package/mjs/Console.mjs +1 -11
- package/mjs/Console.mjs.map +1 -1
- package/mjs/Path.mjs +26 -0
- package/mjs/Path.mjs.map +1 -0
- package/mjs/Stream.mjs.map +1 -1
- package/mjs/internal/fileSystem.mjs +55 -27
- package/mjs/internal/fileSystem.mjs.map +1 -1
- package/mjs/internal/path.mjs +37 -0
- package/mjs/internal/path.mjs.map +1 -0
- package/mjs/internal/stream.mjs +2 -4
- package/mjs/internal/stream.mjs.map +1 -1
- package/package.json +5 -5
- package/src/Console.ts +1 -13
- package/src/Path.ts +33 -0
- package/src/Stream.ts +3 -2
- package/src/internal/fileSystem.ts +85 -41
- package/src/internal/path.ts +62 -0
- package/src/internal/stream.ts +5 -7
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { pipe } from "@effect/data/Function"
|
|
1
|
+
import { identity, pipe } from "@effect/data/Function"
|
|
2
2
|
import * as Option from "@effect/data/Option"
|
|
3
3
|
import * as Effect from "@effect/io/Effect"
|
|
4
4
|
import * as Layer from "@effect/io/Layer"
|
|
5
5
|
import { effectify } from "@effect/platform/Effectify"
|
|
6
6
|
import * as Error from "@effect/platform/Error"
|
|
7
7
|
import * as FileSystem from "@effect/platform/FileSystem"
|
|
8
|
-
import * as File from "@effect/platform/FileSystem/File"
|
|
9
8
|
import * as Crypto from "node:crypto"
|
|
10
9
|
import * as NFS from "node:fs"
|
|
11
10
|
import * as OS from "node:os"
|
|
@@ -54,7 +53,7 @@ const handleErrnoException = (method: string) =>
|
|
|
54
53
|
reason,
|
|
55
54
|
module: "FileSystem",
|
|
56
55
|
method,
|
|
57
|
-
pathOrDescriptor: path
|
|
56
|
+
pathOrDescriptor: path as string | number,
|
|
58
57
|
syscall: err.syscall,
|
|
59
58
|
message: err.message
|
|
60
59
|
})
|
|
@@ -88,6 +87,22 @@ const access = (() => {
|
|
|
88
87
|
}
|
|
89
88
|
})()
|
|
90
89
|
|
|
90
|
+
// == copy
|
|
91
|
+
|
|
92
|
+
const copy = (() => {
|
|
93
|
+
const nodeCp = effectify(
|
|
94
|
+
NFS.cp,
|
|
95
|
+
handleErrnoException("copy"),
|
|
96
|
+
handleBadArgument("copy")
|
|
97
|
+
)
|
|
98
|
+
return (fromPath: string, toPath: string, options?: FileSystem.CopyOptions) =>
|
|
99
|
+
nodeCp(fromPath, toPath, {
|
|
100
|
+
force: options?.overwrite ?? false,
|
|
101
|
+
preserveTimestamps: options?.preserveTimestamps ?? false,
|
|
102
|
+
recursive: true
|
|
103
|
+
})
|
|
104
|
+
})()
|
|
105
|
+
|
|
91
106
|
// == copyFile
|
|
92
107
|
|
|
93
108
|
const copyFile = (() => {
|
|
@@ -162,7 +177,7 @@ const makeTempDirectoryFactory = (method: string) => {
|
|
|
162
177
|
? Path.join(options.directory, ".")
|
|
163
178
|
: OS.tmpdir()
|
|
164
179
|
|
|
165
|
-
return nodeMkdtemp(prefix ? Path.join(directory, prefix) : directory)
|
|
180
|
+
return nodeMkdtemp(prefix ? Path.join(directory, prefix) : directory + "/")
|
|
166
181
|
})
|
|
167
182
|
}
|
|
168
183
|
const makeTempDirectory = makeTempDirectoryFactory("makeTempDirectory")
|
|
@@ -175,7 +190,11 @@ const removeFactory = (method: string) => {
|
|
|
175
190
|
handleErrnoException(method),
|
|
176
191
|
handleBadArgument(method)
|
|
177
192
|
)
|
|
178
|
-
return (path: string, options?: FileSystem.RemoveOptions) =>
|
|
193
|
+
return (path: string, options?: FileSystem.RemoveOptions) =>
|
|
194
|
+
nodeRm(
|
|
195
|
+
path,
|
|
196
|
+
{ recursive: options?.recursive ?? false }
|
|
197
|
+
)
|
|
179
198
|
}
|
|
180
199
|
const remove = removeFactory("remove")
|
|
181
200
|
|
|
@@ -193,31 +212,18 @@ const makeTempDirectoryScoped = (() => {
|
|
|
193
212
|
)
|
|
194
213
|
})()
|
|
195
214
|
|
|
196
|
-
// == makeTempFile
|
|
197
|
-
|
|
198
|
-
const makeTempFile = (() => {
|
|
199
|
-
const makeDirectory = makeTempDirectoryFactory("makeTempFile")
|
|
200
|
-
const randomHexString = (bytes: number) => Effect.sync(() => Crypto.randomBytes(bytes).toString("hex"))
|
|
201
|
-
return (options?: FileSystem.MakeTempFileOptions) =>
|
|
202
|
-
pipe(
|
|
203
|
-
Effect.zip(makeDirectory(options), randomHexString(6)),
|
|
204
|
-
Effect.map(([directory, random]) => Path.join(directory, random)),
|
|
205
|
-
Effect.flatMap((path) => open(path, { flag: "w+" }))
|
|
206
|
-
)
|
|
207
|
-
})()
|
|
208
|
-
|
|
209
215
|
// == open
|
|
210
216
|
|
|
211
|
-
const
|
|
217
|
+
const openFactory = (method: string) => {
|
|
212
218
|
const nodeOpen = effectify(
|
|
213
219
|
NFS.open,
|
|
214
|
-
handleErrnoException(
|
|
215
|
-
handleBadArgument(
|
|
220
|
+
handleErrnoException(method),
|
|
221
|
+
handleBadArgument(method)
|
|
216
222
|
)
|
|
217
223
|
const nodeClose = effectify(
|
|
218
224
|
NFS.close,
|
|
219
|
-
handleErrnoException(
|
|
220
|
-
handleBadArgument(
|
|
225
|
+
handleErrnoException(method),
|
|
226
|
+
handleBadArgument(method)
|
|
221
227
|
)
|
|
222
228
|
|
|
223
229
|
return (path: string, options?: FileSystem.OpenFileOptions) =>
|
|
@@ -226,9 +232,10 @@ const open = (() => {
|
|
|
226
232
|
nodeOpen(path, options?.flag ?? "r", options?.mode),
|
|
227
233
|
(fd) => Effect.orDie(nodeClose(fd))
|
|
228
234
|
),
|
|
229
|
-
Effect.map((fd) => makeFile(
|
|
235
|
+
Effect.map((fd) => makeFile(FileSystem.FileDescriptor(fd)))
|
|
230
236
|
)
|
|
231
|
-
}
|
|
237
|
+
}
|
|
238
|
+
const open = openFactory("open")
|
|
232
239
|
|
|
233
240
|
const makeFile = (() => {
|
|
234
241
|
const nodeReadFactory = (method: string) =>
|
|
@@ -259,11 +266,11 @@ const makeFile = (() => {
|
|
|
259
266
|
const nodeWrite = nodeWriteFactory("write")
|
|
260
267
|
const nodeWriteAll = nodeWriteFactory("writeAll")
|
|
261
268
|
|
|
262
|
-
class FileImpl {
|
|
263
|
-
readonly [
|
|
269
|
+
class FileImpl implements FileSystem.File {
|
|
270
|
+
readonly [FileSystem.FileTypeId] = identity
|
|
264
271
|
|
|
265
272
|
constructor(
|
|
266
|
-
readonly fd:
|
|
273
|
+
readonly fd: FileSystem.File.Descriptor
|
|
267
274
|
) {}
|
|
268
275
|
|
|
269
276
|
get stat() {
|
|
@@ -272,7 +279,7 @@ const makeFile = (() => {
|
|
|
272
279
|
|
|
273
280
|
read(
|
|
274
281
|
buffer: Uint8Array,
|
|
275
|
-
options?:
|
|
282
|
+
options?: FileSystem.FileReadOptions
|
|
276
283
|
) {
|
|
277
284
|
return Effect.map(
|
|
278
285
|
nodeRead(this.fd, {
|
|
@@ -284,7 +291,7 @@ const makeFile = (() => {
|
|
|
284
291
|
)
|
|
285
292
|
}
|
|
286
293
|
|
|
287
|
-
readAlloc(size: FileSystem.Size, options?:
|
|
294
|
+
readAlloc(size: FileSystem.Size, options?: FileSystem.FileReadOptions | undefined) {
|
|
288
295
|
return Effect.flatMap(
|
|
289
296
|
Effect.sync(() => Buffer.allocUnsafeSlow(Number(size))),
|
|
290
297
|
(buffer) =>
|
|
@@ -323,16 +330,51 @@ const makeFile = (() => {
|
|
|
323
330
|
return Effect.flatMap(
|
|
324
331
|
nodeWriteAll(this.fd, buffer),
|
|
325
332
|
(bytesWritten) => {
|
|
326
|
-
if (bytesWritten ===
|
|
327
|
-
return Effect.
|
|
333
|
+
if (bytesWritten === 0) {
|
|
334
|
+
return Effect.fail(Error.SystemError({
|
|
335
|
+
module: "FileSystem",
|
|
336
|
+
method: "writeAll",
|
|
337
|
+
reason: "WriteZero",
|
|
338
|
+
pathOrDescriptor: this.fd,
|
|
339
|
+
message: "write returned 0 bytes written"
|
|
340
|
+
}))
|
|
341
|
+
} else if (bytesWritten < buffer.length) {
|
|
342
|
+
return this.writeAll(buffer.subarray(bytesWritten))
|
|
328
343
|
}
|
|
329
|
-
return
|
|
344
|
+
return Effect.unit()
|
|
330
345
|
}
|
|
331
346
|
)
|
|
332
347
|
}
|
|
333
348
|
}
|
|
334
349
|
|
|
335
|
-
return (fd:
|
|
350
|
+
return (fd: FileSystem.File.Descriptor): FileSystem.File => new FileImpl(fd)
|
|
351
|
+
})()
|
|
352
|
+
|
|
353
|
+
// == makeTempFile
|
|
354
|
+
|
|
355
|
+
const makeTempFileFactory = (method: string) => {
|
|
356
|
+
const makeDirectory = makeTempDirectoryFactory(method)
|
|
357
|
+
const open = openFactory(method)
|
|
358
|
+
const randomHexString = (bytes: number) => Effect.sync(() => Crypto.randomBytes(bytes).toString("hex"))
|
|
359
|
+
return (options?: FileSystem.MakeTempFileOptions) =>
|
|
360
|
+
pipe(
|
|
361
|
+
Effect.zip(makeDirectory(options), randomHexString(6)),
|
|
362
|
+
Effect.map(([directory, random]) => Path.join(directory, random)),
|
|
363
|
+
Effect.tap((path) => Effect.scoped(open(path, { flag: "w+" })))
|
|
364
|
+
)
|
|
365
|
+
}
|
|
366
|
+
const makeTempFile = makeTempFileFactory("makeTempFile")
|
|
367
|
+
|
|
368
|
+
// == makeTempFileScoped
|
|
369
|
+
|
|
370
|
+
const makeTempFileScoped = (() => {
|
|
371
|
+
const makeFile = makeTempFileFactory("makeTempFileScoped")
|
|
372
|
+
const removeFile = removeFactory("makeTempFileScoped")
|
|
373
|
+
return (options?: FileSystem.MakeTempFileOptions) =>
|
|
374
|
+
Effect.acquireRelease(
|
|
375
|
+
makeFile(options),
|
|
376
|
+
(file) => Effect.orDie(removeFile(file))
|
|
377
|
+
)
|
|
336
378
|
})()
|
|
337
379
|
|
|
338
380
|
// == readDirectory
|
|
@@ -404,7 +446,7 @@ const rename = (() => {
|
|
|
404
446
|
|
|
405
447
|
// == stat
|
|
406
448
|
|
|
407
|
-
const makeFileInfo = (stat: NFS.Stats):
|
|
449
|
+
const makeFileInfo = (stat: NFS.Stats): FileSystem.File.Info => ({
|
|
408
450
|
type: stat.isFile() ?
|
|
409
451
|
"File" :
|
|
410
452
|
stat.isDirectory() ?
|
|
@@ -465,15 +507,15 @@ const truncate = (() => {
|
|
|
465
507
|
return (path: string, length?: FileSystem.Size) => nodeTruncate(path, Number(length))
|
|
466
508
|
})()
|
|
467
509
|
|
|
468
|
-
// ==
|
|
510
|
+
// == utimes
|
|
469
511
|
|
|
470
|
-
const
|
|
471
|
-
const
|
|
512
|
+
const utimes = (() => {
|
|
513
|
+
const nodeUtimes = effectify(
|
|
472
514
|
NFS.utimes,
|
|
473
515
|
handleErrnoException("utime"),
|
|
474
516
|
handleBadArgument("utime")
|
|
475
517
|
)
|
|
476
|
-
return (path: string, atime: number | Date, mtime: number | Date) =>
|
|
518
|
+
return (path: string, atime: number | Date, mtime: number | Date) => nodeUtimes(path, atime, mtime)
|
|
477
519
|
})()
|
|
478
520
|
|
|
479
521
|
// == writeFile
|
|
@@ -501,14 +543,16 @@ const writeFile = (path: string, data: Uint8Array, options?: FileSystem.WriteFil
|
|
|
501
543
|
|
|
502
544
|
const fileSystemImpl = FileSystem.make({
|
|
503
545
|
access,
|
|
504
|
-
copyFile,
|
|
505
546
|
chmod,
|
|
506
547
|
chown,
|
|
548
|
+
copy,
|
|
549
|
+
copyFile,
|
|
507
550
|
link,
|
|
508
551
|
makeDirectory,
|
|
509
552
|
makeTempDirectory,
|
|
510
553
|
makeTempDirectoryScoped,
|
|
511
554
|
makeTempFile,
|
|
555
|
+
makeTempFileScoped,
|
|
512
556
|
open,
|
|
513
557
|
readDirectory,
|
|
514
558
|
readFile,
|
|
@@ -519,7 +563,7 @@ const fileSystemImpl = FileSystem.make({
|
|
|
519
563
|
stat,
|
|
520
564
|
symlink,
|
|
521
565
|
truncate,
|
|
522
|
-
|
|
566
|
+
utimes,
|
|
523
567
|
writeFile
|
|
524
568
|
})
|
|
525
569
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Tag } from "@effect/data/Context"
|
|
2
|
+
import * as Effect from "@effect/io/Effect"
|
|
3
|
+
import * as Layer from "@effect/io/Layer"
|
|
4
|
+
import { BadArgument } from "@effect/platform/Error"
|
|
5
|
+
import type { Path as _Path } from "@effect/platform/Path"
|
|
6
|
+
import * as NodePath from "node:path"
|
|
7
|
+
import * as NodeUrl from "node:url"
|
|
8
|
+
|
|
9
|
+
/** @internal */
|
|
10
|
+
export const Path = Tag<_Path>()
|
|
11
|
+
|
|
12
|
+
const fromFileUrl = (url: URL): Effect.Effect<never, BadArgument, string> =>
|
|
13
|
+
Effect.tryCatch(
|
|
14
|
+
() => NodeUrl.fileURLToPath(url),
|
|
15
|
+
(error) =>
|
|
16
|
+
BadArgument({
|
|
17
|
+
module: "Path",
|
|
18
|
+
method: "fromFileUrl",
|
|
19
|
+
message: `${error}`
|
|
20
|
+
})
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
const toFileUrl = (path: string): Effect.Effect<never, BadArgument, URL> =>
|
|
24
|
+
Effect.tryCatch(
|
|
25
|
+
() => NodeUrl.pathToFileURL(path),
|
|
26
|
+
(error) =>
|
|
27
|
+
BadArgument({
|
|
28
|
+
module: "Path",
|
|
29
|
+
method: "toFileUrl",
|
|
30
|
+
message: `${error}`
|
|
31
|
+
})
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
/** @internal */
|
|
35
|
+
export const layerPosix = Layer.succeed(
|
|
36
|
+
Path,
|
|
37
|
+
Path.of({
|
|
38
|
+
...NodePath.posix,
|
|
39
|
+
fromFileUrl,
|
|
40
|
+
toFileUrl
|
|
41
|
+
})
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
/** @internal */
|
|
45
|
+
export const layerWin32 = Layer.succeed(
|
|
46
|
+
Path,
|
|
47
|
+
Path.of({
|
|
48
|
+
...NodePath.win32,
|
|
49
|
+
fromFileUrl,
|
|
50
|
+
toFileUrl
|
|
51
|
+
})
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
/** @internal */
|
|
55
|
+
export const layer = Layer.succeed(
|
|
56
|
+
Path,
|
|
57
|
+
Path.of({
|
|
58
|
+
...NodePath,
|
|
59
|
+
fromFileUrl,
|
|
60
|
+
toFileUrl
|
|
61
|
+
})
|
|
62
|
+
)
|
package/src/internal/stream.ts
CHANGED
|
@@ -3,17 +3,15 @@ import { pipe } from "@effect/data/Function"
|
|
|
3
3
|
import * as Option from "@effect/data/Option"
|
|
4
4
|
import * as Effect from "@effect/io/Effect"
|
|
5
5
|
import type { FromReadableOptions } from "@effect/platform-node/Stream"
|
|
6
|
-
import { Size } from "@effect/platform/FileSystem"
|
|
6
|
+
import type { Size } from "@effect/platform/FileSystem"
|
|
7
7
|
import * as Stream from "@effect/stream/Stream"
|
|
8
8
|
import type { Readable } from "node:stream"
|
|
9
9
|
|
|
10
|
-
const DEFAULT_CHUNK_SIZE = Size(64 * 1024)
|
|
11
|
-
|
|
12
10
|
/** @internal */
|
|
13
11
|
export const fromReadable = <E, A>(
|
|
14
12
|
evaluate: LazyArg<Readable>,
|
|
15
13
|
onError: (error: unknown) => E,
|
|
16
|
-
{ chunkSize =
|
|
14
|
+
{ chunkSize = Option.none() }: FromReadableOptions = {}
|
|
17
15
|
): Stream.Stream<never, E, A> =>
|
|
18
16
|
pipe(
|
|
19
17
|
Effect.acquireRelease(Effect.sync(evaluate), (stream) =>
|
|
@@ -49,9 +47,9 @@ export const fromReadable = <E, A>(
|
|
|
49
47
|
|
|
50
48
|
const readChunk = <A>(
|
|
51
49
|
stream: Readable,
|
|
52
|
-
size: Size
|
|
50
|
+
size: Option.Option<Size>
|
|
53
51
|
): Effect.Effect<never, Option.Option<never>, A> =>
|
|
54
52
|
pipe(
|
|
55
|
-
Effect.sync(() => stream.read(Number(size)) as A | null),
|
|
56
|
-
Effect.flatMap((
|
|
53
|
+
Effect.sync(() => (size._tag === "Some" ? stream.read(Number(size)) : stream.read()) as A | null),
|
|
54
|
+
Effect.flatMap((_) => (_ ? Effect.succeed(_) : Effect.fail(Option.none())))
|
|
57
55
|
)
|