@effected/cli 0.22.1 → 0.23.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.
- package/CliEnv.js +2 -1
- package/CliFailure.js +15 -29
- package/CliFormat.js +69 -0
- package/CliLog.js +38 -16
- package/CliRuntime.js +70 -48
- package/Fmt.js +123 -2
- package/Render.js +5 -2
- package/index.d.ts +272 -5
- package/index.js +2 -1
- package/internal/causeMessage.js +57 -0
- package/internal/displayPath.js +46 -0
- package/internal/displayWidth.js +11 -3
- package/internal/failureTarget.js +2 -1
- package/internal/inspect.js +40 -0
- package/package.json +7 -5
- package/tsdoc-metadata.json +1 -1
- package/ui/CliUi.js +86 -14
- package/ui/CliUiDetached.js +36 -0
- package/ui/CliUiLive.js +6 -9
- package/ui/CliUiRouteStream.js +72 -0
- package/ui/DocView.js +7 -4
- package/ui/UiProvider.js +4 -1
- package/ui/internal/UiProviders.js +19 -1
- package/ui/internal/inkChalk.js +24 -34
- package/ui/internal/lineRouter.js +70 -0
- package/ui/testing/CliUiTest.js +4 -1
- package/ui.d.ts +200 -3
package/ui.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as Cli from "@effected/cli";
|
|
2
|
-
import { Console, Context, Effect, Option, PubSub, Scope, Stream } from "effect";
|
|
2
|
+
import { Console, Context, Effect, Exit, Layer, Option, PubSub, Scope, Stream } from "effect";
|
|
3
3
|
import { Param } from "effect/cli";
|
|
4
4
|
import { ReactElement, ReactNode } from "react";
|
|
5
|
+
import { Writable } from "node:stream";
|
|
5
6
|
import { Key } from "ink";
|
|
6
7
|
import { ColorLevel } from "@effected/env";
|
|
7
8
|
/**
|
|
@@ -177,6 +178,120 @@ interface LiveHandle<S> {
|
|
|
177
178
|
*/
|
|
178
179
|
readonly close: Effect.Effect<void>;
|
|
179
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* Options for `CliUi.liveDetached`: those of `CliUi.live`, with the events given as a `PubSub` or a stream, and the
|
|
183
|
+
* render given directly or as an effect that makes it.
|
|
184
|
+
*
|
|
185
|
+
* @typeParam R - the services a `render` effect reads, which the `env` layer provides
|
|
186
|
+
*
|
|
187
|
+
* @public
|
|
188
|
+
*/
|
|
189
|
+
interface DetachedLiveOptions<E, S, R = never> extends Omit<LiveOptions<E, S>, "events" | "render"> {
|
|
190
|
+
/**
|
|
191
|
+
* The events to fold. A `PubSub` is subscribed before `liveDetached` returns, in the view's own scope, so an event
|
|
192
|
+
* published right after the call is seen and `close` folds every message still queued. A stream is read as
|
|
193
|
+
* `CliUi.live` reads one.
|
|
194
|
+
*/
|
|
195
|
+
readonly events: PubSub.PubSub<E> | Stream.Stream<E>;
|
|
196
|
+
/**
|
|
197
|
+
* Draw the state, as `CliUi.live`'s `render`; or an effect that makes that function, run once under `env` before
|
|
198
|
+
* the view is set up, so a render that needs an environment service (`CliLinks` to build links, `TerminalEnv` for
|
|
199
|
+
* the terminal's capabilities) reads it from the layer the view already builds rather than from a second build.
|
|
200
|
+
*
|
|
201
|
+
* @remarks
|
|
202
|
+
* A render effect that dies is the view's setup failing: `handle` rejects, `close` resolves, and `exit` carries
|
|
203
|
+
* the die, as for an `env` layer that dies. It can return a `CliUi.lazyView`.
|
|
204
|
+
*/
|
|
205
|
+
readonly render: LiveOptions<E, S>["render"] | Effect.Effect<LiveOptions<E, S>["render"], never, R>;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* A live view running outside Effect, from `CliUi.liveDetached`.
|
|
209
|
+
*
|
|
210
|
+
* @public
|
|
211
|
+
*/
|
|
212
|
+
interface DetachedLive<S> {
|
|
213
|
+
/**
|
|
214
|
+
* The view's handle once `CliUi.live` has set it up (it loads Ink asynchronously). Rejects if the view could not be
|
|
215
|
+
* set up; the rejection is handled, so a host that never awaits it sees no unhandled rejection.
|
|
216
|
+
*/
|
|
217
|
+
readonly handle: Promise<LiveHandle<S>>;
|
|
218
|
+
/**
|
|
219
|
+
* The handle's `printAbove`: print one line above the frame and say whether it did. `false`, with nothing written,
|
|
220
|
+
* before the handle is set up, whenever no run's frame is mounted, and from the moment `close` is called, so the
|
|
221
|
+
* host writes the line itself.
|
|
222
|
+
*/
|
|
223
|
+
readonly printAbove: (stream: "stdout" | "stderr", line: string) => boolean;
|
|
224
|
+
/**
|
|
225
|
+
* End the view and release it.
|
|
226
|
+
*
|
|
227
|
+
* @remarks
|
|
228
|
+
* In order: `printAbove` stops printing; the view's setup is awaited (one that died counts as settled); the
|
|
229
|
+
* handle's `close` folds every message still queued in the subscription and commits the last run; then the view's
|
|
230
|
+
* scope is closed, which unsubscribes and unmounts. Shut the `PubSub` down only after the returned promise
|
|
231
|
+
* resolves: a `PubSub.shutdown` before it drops the events the view has not taken yet.
|
|
232
|
+
*
|
|
233
|
+
* Idempotent: every call returns the same promise. It never rejects; how the view ended is `exit`.
|
|
234
|
+
*/
|
|
235
|
+
readonly close: () => Promise<void>;
|
|
236
|
+
/**
|
|
237
|
+
* How the view ended: a success when its events ended or `close` ended them, the failure it died of (a `reduce`
|
|
238
|
+
* that threw, a stream that died, a setup that failed), or an interrupt when its scope closed under it.
|
|
239
|
+
*/
|
|
240
|
+
readonly exit: Promise<Exit.Exit<void>>;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Options for `CliUi.routeStream`.
|
|
244
|
+
*
|
|
245
|
+
* @public
|
|
246
|
+
*/
|
|
247
|
+
interface RouteStreamOptions {
|
|
248
|
+
/** Which of the printer's streams the lines belong on. */
|
|
249
|
+
readonly stream: "stdout" | "stderr";
|
|
250
|
+
/**
|
|
251
|
+
* The most characters held back waiting for a line break; 8192 by default. Past it, the held text is offered as a
|
|
252
|
+
* line of its own, so a writer that never ends a line cannot grow the buffer without bound.
|
|
253
|
+
*/
|
|
254
|
+
readonly maxHeld?: number | undefined;
|
|
255
|
+
/**
|
|
256
|
+
* What a line holding a carriage return is printed as: `keep` (the default) prints it as written, and `last` prints
|
|
257
|
+
* only the text after its last `\r`, which is what a terminal would have shown of a progress bar redrawn in place.
|
|
258
|
+
* A CRLF line ending is a line ending either way. A line written to the original stream is always written as it came.
|
|
259
|
+
*/
|
|
260
|
+
readonly carriageReturn?: "keep" | "last" | undefined;
|
|
261
|
+
/**
|
|
262
|
+
* Called with every piece of text written, decoded, before it is routed: a tap for a recorder.
|
|
263
|
+
*
|
|
264
|
+
* @remarks
|
|
265
|
+
* Every write reaches it, a write of nothing but escape sequences (a cursor hide, a clear-screen) included, though
|
|
266
|
+
* such a write is never offered to the printer. A write holding only the first bytes of a character reaches it when
|
|
267
|
+
* the character completes, or as U+FFFD at `flush`.
|
|
268
|
+
*/
|
|
269
|
+
readonly onText?: ((text: string) => void) | undefined;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* A stream routed line by line through a printer, from `CliUi.routeStream`.
|
|
273
|
+
*
|
|
274
|
+
* @public
|
|
275
|
+
*/
|
|
276
|
+
interface RoutedStream {
|
|
277
|
+
/**
|
|
278
|
+
* The stream to hand to the writer in place of the original. It reports the original's `isTTY`, `columns`, `rows`,
|
|
279
|
+
* `getColorDepth`, `hasColors` and `getWindowSize`, where the original has them, so a library that sizes its output
|
|
280
|
+
* to the terminal still sees one.
|
|
281
|
+
*/
|
|
282
|
+
readonly writable: Writable;
|
|
283
|
+
/**
|
|
284
|
+
* Turn routing on (the default) or off. Turned off, the text held waiting for a line break is written to the
|
|
285
|
+
* original, and every later write goes straight to it, decoded, until routing is turned back on.
|
|
286
|
+
*/
|
|
287
|
+
readonly route: (on: boolean) => void;
|
|
288
|
+
/**
|
|
289
|
+
* Offer the text held waiting for a line break to the printer now, or write it to the original if it declines.
|
|
290
|
+
* It ends the decoding too: a character split across writes whose second half has not arrived is written as
|
|
291
|
+
* U+FFFD. Ending `writable` (`end()`) flushes the same way, so a last line with no line break is never lost.
|
|
292
|
+
*/
|
|
293
|
+
readonly flush: () => void;
|
|
294
|
+
}
|
|
180
295
|
/**
|
|
181
296
|
* What the kit's hooks read in a tree the kit did not mount: the theme, the glyph set, and optionally the size.
|
|
182
297
|
*
|
|
@@ -200,6 +315,12 @@ interface UiContextValue {
|
|
|
200
315
|
readonly columns: number;
|
|
201
316
|
readonly rows: number;
|
|
202
317
|
};
|
|
318
|
+
/**
|
|
319
|
+
* How a `DocView` under it shows an absolute path: `CliUi.context` sets it from the run's `displayPath`
|
|
320
|
+
* (`CliEnvOptions.displayPath`), so a frame shows a path as `Doc.print` and a live view's `final` do. Absent, a
|
|
321
|
+
* nested provider keeps the one above it, and with none the path is shown as given.
|
|
322
|
+
*/
|
|
323
|
+
readonly displayPath?: ((absolute: string) => string) | undefined;
|
|
203
324
|
/**
|
|
204
325
|
* Whether the GitHub Actions runner reads the output (`CliUi.context` sets it from `CurrentRuntimeEnv`, when one is
|
|
205
326
|
* provided): a `DocView` under it neutralizes any line its data would turn into a workflow command. `false` opts the
|
|
@@ -452,6 +573,82 @@ export declare class CliUi {
|
|
|
452
573
|
* @param options - the events, the fold, the drawing, and what starts and ends a run
|
|
453
574
|
*/
|
|
454
575
|
static readonly live: <E, S>(options: LiveOptions<E, S>) => Effect.Effect<LiveHandle<S>, never, Scope.Scope | Cli.CliTheme>;
|
|
576
|
+
/**
|
|
577
|
+
* A live view hosted by code that is not built on Effect: a test runner's reporter, a bundler plugin, a build hook.
|
|
578
|
+
*
|
|
579
|
+
* @remarks
|
|
580
|
+
* It runs `CliUi.live` in a fiber of its own, under `env` and in a scope of its own, and returns at once. A `PubSub`
|
|
581
|
+
* given as `events` is subscribed before it returns, so the first event published after the call is not lost.
|
|
582
|
+
* `env` is the environment the view reads, built by the host, which owns the platform: under Node,
|
|
583
|
+
* `CliEnv.layer().pipe(Layer.provide(NodeServices.layer))`; a test gives `CliEnv.layerTest` with a session's layer.
|
|
584
|
+
*
|
|
585
|
+
* End it with `close`, and only then shut the `PubSub` down: `close` folds the subscription's queued tail, commits
|
|
586
|
+
* the last run and releases the scope, and a shutdown before it drops that tail. `close` never rejects; `exit`
|
|
587
|
+
* says how the view ended. Forward output the host did not write through `printAbove`, or hand
|
|
588
|
+
* `CliUi.routeStream` the detached view's `printAbove` as its printer.
|
|
589
|
+
*
|
|
590
|
+
* A render that needs an environment service is given as an effect that makes the render function: it runs once
|
|
591
|
+
* under `env`, before the view is set up, so `CliLinks` or `TerminalEnv` come from the same build the view reads and
|
|
592
|
+
* the layer is not built a second time to resolve them. `env` must provide what that effect reads.
|
|
593
|
+
*
|
|
594
|
+
* Inside an Effect program, use `CliUi.live` in a scope instead.
|
|
595
|
+
*
|
|
596
|
+
* @example
|
|
597
|
+
* ```ts
|
|
598
|
+
* const view = CliUi.liveDetached(
|
|
599
|
+
* {
|
|
600
|
+
* ...options,
|
|
601
|
+
* render: Effect.gen(function* () {
|
|
602
|
+
* const links = yield* CliLinks
|
|
603
|
+
* return (state: State, frame: number) => drawWith(links, state, frame)
|
|
604
|
+
* }),
|
|
605
|
+
* },
|
|
606
|
+
* CliEnv.layer().pipe(Layer.provide(NodeServices.layer)),
|
|
607
|
+
* )
|
|
608
|
+
* ```
|
|
609
|
+
*
|
|
610
|
+
* @param options - the live view's options, with the events as a `PubSub` or a stream and the render given directly
|
|
611
|
+
* or as an effect that makes it
|
|
612
|
+
* @param env - the environment the view runs under, providing what a render effect reads
|
|
613
|
+
*/
|
|
614
|
+
static readonly liveDetached: <E, S, R = never>(options: DetachedLiveOptions<E, S, R>, env: Layer.Layer<Cli.CliTheme | NoInfer<R>>) => DetachedLive<S>;
|
|
615
|
+
/**
|
|
616
|
+
* A stream to hand to a writer in place of a terminal stream, which routes what it writes line by line through
|
|
617
|
+
* `printer`, usually a live view's `printAbove`, and writes whatever the printer declines to `original`.
|
|
618
|
+
*
|
|
619
|
+
* @remarks
|
|
620
|
+
* For output the program does not write itself: a child process's stderr, or the streams of a test runner or a
|
|
621
|
+
* bundler running in-process. Each complete line is offered to `printer`; a `false` (no frame mounted) writes it,
|
|
622
|
+
* with its line break, to `original`. Text without a line break yet is held until one comes, until `flush`, or
|
|
623
|
+
* until it passes `maxHeld` characters, when it is offered as a line of its own. Bytes are decoded as UTF-8 across
|
|
624
|
+
* writes, so a character split between two writes arrives whole.
|
|
625
|
+
*
|
|
626
|
+
* Everything written to `original` is the decoded text, so a character split across two writes, by whichever path,
|
|
627
|
+
* arrives once and whole. A write that is nothing but escape sequences (a cursor hide, a clear-screen) goes
|
|
628
|
+
* straight to `original` when no partial line is held, since there is nothing to print above a frame. Ending
|
|
629
|
+
* `writable` flushes the held text, so a writer's last line with no line break is printed, not lost. A line's own cursor
|
|
630
|
+
* movements still tear the frame; `carriageReturn: "last"` keeps only what a progress bar redrawn with `\r` would
|
|
631
|
+
* have shown.
|
|
632
|
+
*
|
|
633
|
+
* The returned `writable` reports the original's `isTTY`, `columns`, `rows`, `getColorDepth`, `hasColors` and
|
|
634
|
+
* `getWindowSize` where the original has them. A printer that throws fails the write. Node only, as `./ui` is.
|
|
635
|
+
*
|
|
636
|
+
* @example
|
|
637
|
+
* ```ts
|
|
638
|
+
* const view = CliUi.liveDetached(options, env)
|
|
639
|
+
* const routed = CliUi.routeStream(process.stderr, view.printAbove, { stream: "stderr" })
|
|
640
|
+
* runner.errorStream = routed.writable
|
|
641
|
+
* // ...at the end
|
|
642
|
+
* routed.flush()
|
|
643
|
+
* await view.close()
|
|
644
|
+
* ```
|
|
645
|
+
*
|
|
646
|
+
* @param original - the stream the writer would have written to
|
|
647
|
+
* @param printer - where each line is offered first: `true` when it printed it, `false` with nothing written
|
|
648
|
+
* @param options - the printer's stream, the hold limit, carriage returns and a text tap
|
|
649
|
+
* @throws RangeError when `maxHeld` is not a non-negative integer
|
|
650
|
+
*/
|
|
651
|
+
static readonly routeStream: (original: NodeJS.WritableStream, printer: (stream: "stdout" | "stderr", line: string) => boolean, options: RouteStreamOptions) => RoutedStream;
|
|
455
652
|
/**
|
|
456
653
|
* Run `screen` from a handler when the run is interactive; otherwise answer with `otherwise`, or fail with
|
|
457
654
|
* `NotInteractive` when there is none.
|
|
@@ -908,7 +1105,7 @@ interface DocViewProps {
|
|
|
908
1105
|
/**
|
|
909
1106
|
* The render context. Omitted, it is built from the tree's theme (`useTheme`): its colour, its `paint` (token
|
|
910
1107
|
* overrides included) and its glyphs, the width `useTerminalSize().columns`, a human audience, links off, the
|
|
911
|
-
*
|
|
1108
|
+
* run's `displayPath` (the identity outside `CliRuntime.main`'s `env`), and `neutralizeWorkflowCommands` when the tree is under the GitHub Actions runner. Given,
|
|
912
1109
|
* it replaces that context entirely, neutralizing included (set `neutralizeWorkflowCommands` on it when the runner
|
|
913
1110
|
* reads the output), and the view needs no provider.
|
|
914
1111
|
*/
|
|
@@ -1786,5 +1983,5 @@ export declare const Styled: (props: StyledProps) => ReactElement;
|
|
|
1786
1983
|
* @public
|
|
1787
1984
|
*/
|
|
1788
1985
|
export declare const useTerminalSize: () => TerminalSize;
|
|
1789
|
-
export type { Binding, CliUiFallbackOptions, CliUiPromptOptions, CliUiRunOptions, ConfirmAction, ConfirmInitOptions, ConfirmResult, ConfirmScreenOptions, ConfirmState, ConfirmToggle, ConfirmViewProps, DocViewProps, InkTextProps, KeyHelpProps, KeyHelpRow, KeyName, LiveHandle, LiveOptions, MultiSelectAction, MultiSelectInitOptions, MultiSelectItem, MultiSelectScreenOptions, MultiSelectSection, MultiSelectState, MultiSelectViewProps, Screen, ScreenControl, SelectAction, SelectChoice, SelectInitOptions, SelectScreenOptions, SelectState, SelectViewProps, StyledProps, Tab, TabsAction, TabsProps, TerminalSize, TextInputInitOptions, TextInputScreenOptions, TextInputState, TextInputViewProps, ToggleViewProps, UiContextValue, UiProviderProps, UiStreamsShape, UseKeysOptions, ViewportMove, ViewportRow, ViewportState, ViewportViewProps };
|
|
1986
|
+
export type { Binding, CliUiFallbackOptions, CliUiPromptOptions, CliUiRunOptions, ConfirmAction, ConfirmInitOptions, ConfirmResult, ConfirmScreenOptions, ConfirmState, ConfirmToggle, ConfirmViewProps, DetachedLive, DetachedLiveOptions, DocViewProps, InkTextProps, KeyHelpProps, KeyHelpRow, KeyName, LiveHandle, LiveOptions, MultiSelectAction, MultiSelectInitOptions, MultiSelectItem, MultiSelectScreenOptions, MultiSelectSection, MultiSelectState, MultiSelectViewProps, RouteStreamOptions, RoutedStream, Screen, ScreenControl, SelectAction, SelectChoice, SelectInitOptions, SelectScreenOptions, SelectState, SelectViewProps, StyledProps, Tab, TabsAction, TabsProps, TerminalSize, TextInputInitOptions, TextInputScreenOptions, TextInputState, TextInputViewProps, ToggleViewProps, UiContextValue, UiProviderProps, UiStreamsShape, UseKeysOptions, ViewportMove, ViewportRow, ViewportState, ViewportViewProps };
|
|
1790
1987
|
//# sourceMappingURL=ui.d.ts.map
|