1import * as DenoStdio from "@effect/platform-deno/DenoStdio"
2import { assert, describe, it } from "@effect/vitest"
3import * as Effect from "effect/Effect"
4import * as Stdio from "effect/Stdio"
5
6const streams = [Deno.stdin, Deno.stdout] as const
7
8const setIsTerminal = (stdin: boolean, stdout: boolean) =>
9 Effect.sync(() => {
10 Object.defineProperty(streams[0], "isTerminal", { configurable: true, value: () => stdin })
11 Object.defineProperty(streams[1], "isTerminal", { configurable: true, value: () => stdout })
12 })
13
14const withRestoredIsTerminal = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
15 Effect.acquireUseRelease(
16 Effect.sync(() => streams.map((stream) => Object.getOwnPropertyDescriptor(stream, "isTerminal"))),
17 () => effect,
18 (descriptors) =>
19 Effect.sync(() => {
20 streams.forEach((stream, index) => {
21 const descriptor = descriptors[index]
22 if (descriptor === undefined) {
23 Reflect.deleteProperty(stream, "isTerminal")
24 } else {
25 Object.defineProperty(stream, "isTerminal", descriptor)
26 }
27 })
28 })
29 )
30
31describe("DenoStdio", () => {
32 it.effect("reads terminal state when the effects run", () =>
33 withRestoredIsTerminal(
34 Effect.gen(function*() {
35 const stdio = yield* Stdio.Stdio
36
37 yield* setIsTerminal(true, false)
38 assert.deepStrictEqual(
39 yield* Effect.all([stdio.stdinIsTerminal, stdio.stdoutIsTerminal]),
40 [true, false]
41 )
42
43 yield* setIsTerminal(false, true)
44 assert.deepStrictEqual(
45 yield* Effect.all([stdio.stdinIsTerminal, stdio.stdoutIsTerminal]),
46 [false, true]
47 )
48 }).pipe(Effect.provide(DenoStdio.layer))
49 ))
50})