@effected/cli 0.10.0 → 0.11.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/Cancelled.js +44 -0
- package/CliAudience.js +178 -0
- package/CliColor.js +13 -19
- package/CliEnv.js +89 -0
- package/CliExit.js +1 -1
- package/CliFailure.js +253 -0
- package/CliInteractive.js +71 -0
- package/CliLinks.js +154 -0
- package/CliLog.js +294 -0
- package/CliLogger.js +34 -33
- package/CliMessage.js +83 -0
- package/CliPrompt.js +104 -0
- package/CliRuntime.js +103 -53
- package/CliTest.js +16 -0
- package/CliTheme.js +128 -0
- package/ConfigIssueRenderer.js +14 -33
- package/Doc.js +512 -0
- package/Fmt.js +133 -0
- package/GithubAnnotation.js +40 -0
- package/Glyphs.js +83 -0
- package/NotInteractive.js +42 -0
- package/README.md +129 -131
- package/Render.js +254 -0
- package/SchemaIssueRenderer.js +7 -10
- package/Status.js +163 -0
- package/TestTerminal.js +80 -0
- package/Token.js +69 -0
- package/index.d.ts +2923 -171
- package/index.js +19 -1
- package/internal/ansi.js +230 -0
- package/internal/autoFormat.js +34 -0
- package/internal/canPrompt.js +15 -0
- package/internal/counts.js +69 -0
- package/internal/diagnostics.js +32 -0
- package/internal/displayWidth.js +35 -0
- package/internal/failureTarget.js +156 -0
- package/internal/fallbackAnswer.js +18 -0
- package/internal/fileSink.js +62 -0
- package/internal/format.js +62 -7
- package/internal/layout.js +250 -0
- package/internal/linkScheme.js +30 -0
- package/internal/linkTarget.js +50 -0
- package/internal/logSafety.js +46 -0
- package/internal/renderAnsi.js +52 -0
- package/internal/renderDoc.js +319 -0
- package/internal/renderGithubLog.js +46 -0
- package/internal/renderMarkdown.js +367 -0
- package/internal/renderPlain.js +50 -0
- package/internal/scanAudience.js +106 -0
- package/internal/splitFrame.js +56 -0
- package/internal/wizardGate.js +18 -0
- package/package.json +35 -5
- package/testing.d.ts +88 -2
- package/testing.js +2 -1
- package/ui/CliUi.js +348 -0
- package/ui/CliUiLive.js +399 -0
- package/ui/Confirm.js +245 -0
- package/ui/DocView.js +74 -0
- package/ui/KeyHelp.js +62 -0
- package/ui/KeyTable.js +199 -0
- package/ui/MultiSelect.js +260 -0
- package/ui/Select.js +226 -0
- package/ui/Tabs.js +202 -0
- package/ui/TextInput.js +250 -0
- package/ui/Toggle.js +32 -0
- package/ui/UiKey.js +44 -0
- package/ui/UiProvider.js +60 -0
- package/ui/UiStreams.js +18 -0
- package/ui/UiTheme.js +119 -0
- package/ui/Viewport.js +204 -0
- package/ui/internal/ErrorBoundary.js +30 -0
- package/ui/internal/Holder.js +74 -0
- package/ui/internal/ScreenContext.js +52 -0
- package/ui/internal/UiProviders.js +21 -0
- package/ui/internal/ink.js +122 -0
- package/ui/internal/inkChalk.js +58 -0
- package/ui/internal/inkConsole.js +146 -0
- package/ui/internal/lineText.js +19 -0
- package/ui/internal/mountPermit.js +16 -0
- package/ui/internal/perfDrain.js +33 -0
- package/ui/internal/processStreams.js +19 -0
- package/ui/internal/renderOptions.js +13 -0
- package/ui/testing/CliUiTest.js +735 -0
- package/ui/testing/fakeStreams.js +76 -0
- package/ui/testing/terminalModel.js +59 -0
- package/ui-testing.d.ts +446 -0
- package/ui-testing.js +3 -0
- package/ui.d.ts +1648 -0
- package/ui.js +17 -0
package/index.d.ts
CHANGED
|
@@ -1,54 +1,2032 @@
|
|
|
1
|
-
import { Cause, Context, Effect, Layer, LogLevel, Logger, MutableRef, Stdio } from "effect";
|
|
2
|
-
import {
|
|
1
|
+
import { Array as Array$1, Cause, Context, Effect, FileSystem, Layer, LogLevel, Logger, MutableRef, Option, Path, Runtime, Schema, Stdio, Terminal } from "effect";
|
|
2
|
+
import { Audience, AudienceKind, ColorLevel, CurrentRuntimeEnv, RuntimeEnv, TerminalEnv } from "@effected/env";
|
|
3
|
+
import { CliError, CliOutput, Command, Flag, Param, Prompt } from "effect/cli";
|
|
3
4
|
import { ConfigValidationError } from "@effected/config-file";
|
|
5
|
+
//#region src/Cancelled.d.ts
|
|
6
|
+
declare const Cancelled_base: Schema.Class<Cancelled, Schema.TaggedStruct<"Cancelled", {
|
|
7
|
+
readonly reason: Schema.Literals<readonly ["escape", "interrupt"]>;
|
|
8
|
+
}>, import("effect/Cause").YieldableError>;
|
|
9
|
+
/**
|
|
10
|
+
* A person backed out of an interactive prompt: they pressed escape, or the
|
|
11
|
+
* prompt was interrupted.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* Exits `130`, the conventional status for a run ended by the user, through
|
|
15
|
+
* core's own `Runtime.errorExitCode` marker, so `CliRuntime.reportFailures`
|
|
16
|
+
* keeps it. Its default rendering is one line, `cancelled; nothing written`,
|
|
17
|
+
* because nothing has been written by the time a prompt is cancelled and a
|
|
18
|
+
* stack trace would only alarm. A consumer `render` still overrides the line, and can hand off to it: the line is
|
|
19
|
+
* the error's `message`, so `error.message` and `String(error)` carry it.
|
|
20
|
+
*
|
|
21
|
+
* @public
|
|
22
|
+
*/
|
|
23
|
+
export declare class Cancelled extends Cancelled_base {
|
|
24
|
+
/**
|
|
25
|
+
* The one line, `cancelled; nothing written`.
|
|
26
|
+
*
|
|
27
|
+
* @remarks
|
|
28
|
+
* A prototype getter, not a field, so it is not part of the encoded form, equality or a JSON dump. Assigning to
|
|
29
|
+
* it is ignored: a library that rewrites `error.message` (to prefix a context, say) must not make this error throw,
|
|
30
|
+
* which a getter-only property does in strict mode. The line is fixed.
|
|
31
|
+
*/
|
|
32
|
+
get message(): string;
|
|
33
|
+
set message(_value: string);
|
|
34
|
+
/**
|
|
35
|
+
* The process exit code: `130`.
|
|
36
|
+
*
|
|
37
|
+
* @remarks
|
|
38
|
+
* A prototype getter rather than an own field, so a JSON or logger dump of the error does not carry the
|
|
39
|
+
* runtime marker.
|
|
40
|
+
*/
|
|
41
|
+
get [Runtime.errorExitCode](): number;
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/CliAudience.d.ts
|
|
45
|
+
/**
|
|
46
|
+
* The four parsed audience flags a root command carries once {@link CliAudience.flags} is shared onto it.
|
|
47
|
+
*
|
|
48
|
+
* @public
|
|
49
|
+
*/
|
|
50
|
+
interface AudienceFlagInput {
|
|
51
|
+
/** Every `--audience <kind>` occurrence. */
|
|
52
|
+
readonly audience: ReadonlyArray<AudienceKind>;
|
|
53
|
+
/** Every `--human` occurrence. */
|
|
54
|
+
readonly human: ReadonlyArray<boolean>;
|
|
55
|
+
/** Every `--agent` occurrence. */
|
|
56
|
+
readonly agent: ReadonlyArray<boolean>;
|
|
57
|
+
/** Every `--ci` occurrence. */
|
|
58
|
+
readonly ci: ReadonlyArray<boolean>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Options for {@link CliAudience.flags}.
|
|
62
|
+
*
|
|
63
|
+
* @public
|
|
64
|
+
*/
|
|
65
|
+
interface CliAudienceFlagsOptions {
|
|
66
|
+
/**
|
|
67
|
+
* Hide all four flags from every help screen. They still parse and resolve; describe them in the root
|
|
68
|
+
* command's description instead.
|
|
69
|
+
*/
|
|
70
|
+
readonly hidden?: boolean | undefined;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Resolves to nothing for a command that carries the four audience flags, and to an unsatisfiable marker otherwise,
|
|
74
|
+
* so `CliAudience.run` on a root that forgot `Command.withSharedFlags(CliAudience.flags())` does not compile. (A
|
|
75
|
+
* plain `Input extends AudienceFlagInput` constraint does not do this: `Command` is contravariant in its input, so
|
|
76
|
+
* a command with no flags still type-checks against it.)
|
|
77
|
+
*
|
|
78
|
+
* @public
|
|
79
|
+
*/
|
|
80
|
+
type RequiresAudienceFlags<Input> = [Input] extends [AudienceFlagInput] ? unknown : {
|
|
81
|
+
readonly "missing shared flags": "pipe the root through Command.withSharedFlags(CliAudience.flags())";
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* The audience flags of a CLI: `--audience <human|agent|ci>` and the shorthands `--human`, `--agent`, `--ci`,
|
|
85
|
+
* resolved into `@effected/env`'s `Audience`.
|
|
86
|
+
*
|
|
87
|
+
* @remarks
|
|
88
|
+
* The one wiring: share the flags on the root command and hand the root to {@link CliAudience.run} (or
|
|
89
|
+
* {@link CliAudience.runWith}), which resolves the flags from argv before core parses and applies
|
|
90
|
+
* {@link CliAudience.provide} itself:
|
|
91
|
+
*
|
|
92
|
+
* ```ts
|
|
93
|
+
* const root = Command.make("tool").pipe(
|
|
94
|
+
* Command.withSharedFlags(CliAudience.flags()),
|
|
95
|
+
* Command.withSubcommands([verify]),
|
|
96
|
+
* )
|
|
97
|
+
* NodeRuntime.runMain(
|
|
98
|
+
* CliRuntime.main(CliAudience.run(root, { version }), { platform: NodeServices.layer, env: {} }),
|
|
99
|
+
* )
|
|
100
|
+
* ```
|
|
101
|
+
*
|
|
102
|
+
* Core lists a shared flag in the help of every subcommand, not only at the root: that is upstream (Effect-TS/effect
|
|
103
|
+
* issue 8642), and `flags({ hidden: true })` is the way to keep them out of help altogether.
|
|
104
|
+
*
|
|
105
|
+
* A root that forgot `Command.withSharedFlags(CliAudience.flags())` does not compile. Giving more than one
|
|
106
|
+
* occurrence across the four flags is a usage error even when they agree; a boolean set to false (`--no-agent`,
|
|
107
|
+
* `--agent=false`) counts as not given. A bad `--audience` value is core's own parse error. Both exit `64` under
|
|
108
|
+
* `CliRuntime.main`. A conflicting audience together with `--help` exits `0` and prints help, because core handles
|
|
109
|
+
* its action flags before the resolver runs.
|
|
110
|
+
*
|
|
111
|
+
* A flag decides `CliInteractive` from the audience it names and the terminal facts: `--human` is interactive when
|
|
112
|
+
* `TerminalEnv` says there is a terminal on stdin and on stdout, even where the environment detected an agent, so a
|
|
113
|
+
* person running the tool inside an agent can ask for the human experience; in a pipe it still cannot prompt. A
|
|
114
|
+
* non-human flag (`--agent`, `--ci`, `--audience agent|ci`) turns it off and drops `--wizard`, and switches
|
|
115
|
+
* diagnostics to NDJSON, for the whole run including the parse step where a fallback prompt fires. Without
|
|
116
|
+
* `TerminalEnv` in the environment a flag only narrows. `--wizard` follows the decision: a run a flag makes
|
|
117
|
+
* interactive gets it back where the environment's gate had dropped it, and only there: a consumer's own `builtIns`
|
|
118
|
+
* without it stay without it.
|
|
119
|
+
* {@link CliAudience.provide} on its own, the path for a bare `Command.run`, acts only on the subcommand handler,
|
|
120
|
+
* because core parses the root flags into a local context before any of it is visible.
|
|
121
|
+
*
|
|
122
|
+
* @public
|
|
123
|
+
*/
|
|
124
|
+
export declare class CliAudience {
|
|
125
|
+
private constructor();
|
|
126
|
+
/**
|
|
127
|
+
* The four flags, for `Command.withSharedFlags` on the root command.
|
|
128
|
+
*
|
|
129
|
+
* @remarks
|
|
130
|
+
* Each is repeatable, so every occurrence is counted; a boolean given as `false` (`--agent=false`,
|
|
131
|
+
* `--no-agent`) is not an occurrence. Core lists shared flags in every command's help; pass
|
|
132
|
+
* `hidden` to remove them from all of them.
|
|
133
|
+
*/
|
|
134
|
+
static readonly flags: (options?: CliAudienceFlagsOptions) => {
|
|
135
|
+
readonly audience: Flag.Flag<ReadonlyArray<AudienceKind>>;
|
|
136
|
+
readonly human: Flag.Flag<ReadonlyArray<boolean>>;
|
|
137
|
+
readonly agent: Flag.Flag<ReadonlyArray<boolean>>;
|
|
138
|
+
readonly ci: Flag.Flag<ReadonlyArray<boolean>>;
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Resolve the flags before every subcommand handler and re-provide `Audience`.
|
|
142
|
+
*
|
|
143
|
+
* @remarks
|
|
144
|
+
* `CliAudience.run` and `runWith` apply this themselves, so a program run through them never needs it. Use it
|
|
145
|
+
* directly only with a bare `Command.run`, which leaves a fallback prompt blind to the flags (see the class
|
|
146
|
+
* remarks).
|
|
147
|
+
*
|
|
148
|
+
* A failure report is written outside the run, where the flag is not in force, so only `runWith` and `run` carry
|
|
149
|
+
* the flag's audience to it; with this on its own the report follows the environment's audience.
|
|
150
|
+
*
|
|
151
|
+
* Pipe it onto the composite root, after `withSubcommands`, since a parent's handler does not run when a
|
|
152
|
+
* subcommand is selected. With exactly one flag the audience is `{ kind, source: "flag" }`; with none the
|
|
153
|
+
* ambient `Audience` is read and provided back unchanged, so `Audience` stays in the requirement a handler
|
|
154
|
+
* reading it already has, and is added to a program whose handlers do not read it.
|
|
155
|
+
*/
|
|
156
|
+
static readonly provide: <const Name extends string, Input extends AudienceFlagInput, ContextInput, E, R>(command: Command.Command<Name, Input, ContextInput, E, R>) => Command.Command<Name, Input, ContextInput, E | CliError.UserError, Exclude<R, Audience> | Audience>;
|
|
157
|
+
/**
|
|
158
|
+
* Run a command the way `Command.runWith` does, with the audience flag resolved BEFORE core parses.
|
|
159
|
+
*
|
|
160
|
+
* @remarks
|
|
161
|
+
* It scans `argv` for the four audience flags first, then runs core around a provided `Audience` (when exactly
|
|
162
|
+
* one is given: `{ kind, source: "flag" }`) and a `CliInteractive` decided from it: `--human` is interactive when
|
|
163
|
+
* `TerminalEnv` reports a terminal on stdin and stdout and `TERM` is not `dumb` (it can turn prompting on under a detected agent), a
|
|
164
|
+
* non-human flag or a conflict makes it false. A fallback prompt fires while core parses, earlier than
|
|
165
|
+
* anything `CliAudience.provide` can reach, so `--agent init` on a terminal would otherwise still prompt. No
|
|
166
|
+
* flag leaves the ambient values untouched. A conflict still gets core's own usage error, exit `64`, from
|
|
167
|
+
* `CliAudience.provide`'s resolver.
|
|
168
|
+
*
|
|
169
|
+
* @param command - the composite root, with the flags shared and `CliAudience.provide` piped on
|
|
170
|
+
* @param config - the same `version` and `renderErrors` as core's
|
|
171
|
+
*/
|
|
172
|
+
static readonly runWith: <const Name extends string, Input, E, R, ContextInput>(command: Command.Command<Name, Input, ContextInput, E, R> & RequiresAudienceFlags<Input>, config: {
|
|
173
|
+
readonly version: string;
|
|
174
|
+
readonly renderErrors?: boolean | undefined;
|
|
175
|
+
}) => ((input: ReadonlyArray<string>) => Effect.Effect<void, Exclude<E | CliError.UserError, Terminal.QuitError> | CliError.CliError, Exclude<R, Audience> | Audience | Command.Environment>);
|
|
176
|
+
/**
|
|
177
|
+
* `Command.run` with the audience flag resolved before parsing: reads `Stdio.args` and calls
|
|
178
|
+
* {@link CliAudience.runWith}.
|
|
179
|
+
*
|
|
180
|
+
* @param command - the composite root
|
|
181
|
+
* @param config - the same `version` and `renderErrors` as core's
|
|
182
|
+
*/
|
|
183
|
+
static readonly run: <const Name extends string, Input, E, R, ContextInput>(command: Command.Command<Name, Input, ContextInput, E, R> & RequiresAudienceFlags<Input>, config: {
|
|
184
|
+
readonly version: string;
|
|
185
|
+
readonly renderErrors?: boolean | undefined;
|
|
186
|
+
}) => Effect.Effect<void, Exclude<E | CliError.UserError, Terminal.QuitError> | CliError.CliError, Exclude<R, Audience> | Audience | Command.Environment>;
|
|
187
|
+
}
|
|
188
|
+
//#endregion
|
|
4
189
|
//#region src/CliColor.d.ts
|
|
5
190
|
/**
|
|
6
|
-
* Whether a CLI's output should carry ANSI colour, decided once and shared by
|
|
7
|
-
* everything that renders — help text, error output, and any rendered result.
|
|
191
|
+
* Whether a CLI's output should carry ANSI colour, decided once and shared by
|
|
192
|
+
* everything that renders — help text, error output, and any rendered result.
|
|
193
|
+
*
|
|
194
|
+
* @remarks
|
|
195
|
+
* The decision is `@effected/env`'s `TerminalEnv.colorLevel("stdout")`, which
|
|
196
|
+
* follows Node's `getColorDepth` precedence: `FORCE_COLOR` first (`0` or an
|
|
197
|
+
* unrecognised value forces colour off; an empty value, `1` or `true` force basic colour, `2` 256 colours and
|
|
198
|
+
* `3` truecolor, even without a terminal), then a non-empty `NO_COLOR` or `NODE_DISABLE_COLORS` and
|
|
199
|
+
* `TERM=dumb`, then the TTY gate. `FORCE_COLOR` therefore beats `NO_COLOR`.
|
|
200
|
+
* The environment
|
|
201
|
+
* is read through the ambient `ConfigProvider`, never `process`, so a test
|
|
202
|
+
* swaps it with `Effect.provideService(ConfigProvider.ConfigProvider, ...)`;
|
|
203
|
+
* an ambient `TerminalEnv`, such as `TerminalEnv.layerTest`, answers instead
|
|
204
|
+
* when one is provided.
|
|
205
|
+
*
|
|
206
|
+
* @public
|
|
207
|
+
*/
|
|
208
|
+
export declare class CliColor {
|
|
209
|
+
private constructor();
|
|
210
|
+
/**
|
|
211
|
+
* The decision, for passing to a pure renderer as a plain boolean.
|
|
212
|
+
*
|
|
213
|
+
* @public
|
|
214
|
+
*/
|
|
215
|
+
static readonly enabled: Effect.Effect<boolean, never, Stdio.Stdio>;
|
|
216
|
+
/**
|
|
217
|
+
* Core's default `CliOutput.Formatter`, coloured by the same decision as
|
|
218
|
+
* {@link CliColor.enabled}, so help text, parse errors and rendered
|
|
219
|
+
* output never disagree on whether colour is on.
|
|
220
|
+
*
|
|
221
|
+
* @remarks
|
|
222
|
+
* `overrides` replaces individual methods of the default formatter — for
|
|
223
|
+
* example `formatVersion`, to append a "via `<carrier>`" line without
|
|
224
|
+
* losing the other defaults. Each call mints a fresh layer; bind the
|
|
225
|
+
* result to a `const` or the decision is re-read every time it is
|
|
226
|
+
* provided.
|
|
227
|
+
*
|
|
228
|
+
* The `never` in its output does not mean it installs nothing.
|
|
229
|
+
* `CliOutput.Formatter` is a `Context.Reference`, whose key type is
|
|
230
|
+
* `never`, so this layer sets the formatter reference rather than
|
|
231
|
+
* providing a service. Every command it is provided to renders with the
|
|
232
|
+
* formatter it sets, and without it they fall back to core's default
|
|
233
|
+
* formatter.
|
|
234
|
+
*
|
|
235
|
+
* @public
|
|
236
|
+
*/
|
|
237
|
+
static readonly formatterLayer: (overrides?: Partial<CliOutput.Formatter>) => Layer.Layer<never, never, Stdio.Stdio>;
|
|
238
|
+
}
|
|
239
|
+
//#endregion
|
|
240
|
+
//#region src/Glyphs.d.ts
|
|
241
|
+
/**
|
|
242
|
+
* The symbols a theme draws with.
|
|
243
|
+
*
|
|
244
|
+
* @public
|
|
245
|
+
*/
|
|
246
|
+
interface GlyphSet {
|
|
247
|
+
/** Which set this is. */
|
|
248
|
+
readonly kind: "unicode" | "ascii";
|
|
249
|
+
/** The truncation marker. */
|
|
250
|
+
readonly ellipsis: string;
|
|
251
|
+
/** The frames of a spinner, in order. */
|
|
252
|
+
readonly spinner: ReadonlyArray<string>;
|
|
253
|
+
/** A list bullet. */
|
|
254
|
+
readonly bullet: string;
|
|
255
|
+
/** A directional arrow. */
|
|
256
|
+
readonly arrow: string;
|
|
257
|
+
/** The separator between the segments of a breadcrumb or path: one for people, one for agents. */
|
|
258
|
+
readonly pathSeparator: {
|
|
259
|
+
readonly human: string;
|
|
260
|
+
readonly agent: string;
|
|
261
|
+
};
|
|
262
|
+
/** How long a spinner frame is shown, in milliseconds. */
|
|
263
|
+
readonly spinnerIntervalMs: number;
|
|
264
|
+
/**
|
|
265
|
+
* The segments a tree is drawn with: `branch` before a child that has later siblings, `last` before the final
|
|
266
|
+
* child, and `pipe` and `blank` as the indent under each. All four are one width so branches align.
|
|
267
|
+
*/
|
|
268
|
+
readonly tree: {
|
|
269
|
+
readonly branch: string;
|
|
270
|
+
readonly last: string;
|
|
271
|
+
readonly pipe: string;
|
|
272
|
+
readonly blank: string;
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Options for {@link Glyphs.select}.
|
|
277
|
+
*
|
|
278
|
+
* @public
|
|
279
|
+
*/
|
|
280
|
+
interface GlyphSelectOptions {
|
|
281
|
+
/**
|
|
282
|
+
* `true` is ASCII, `false` is Unicode, and `auto` (the default) is ASCII only when `term` is `dumb`.
|
|
283
|
+
*/
|
|
284
|
+
readonly ascii?: boolean | "auto" | undefined;
|
|
285
|
+
/**
|
|
286
|
+
* The `TERM` value, which only `auto` reads. It is passed in rather than read: this selection is pure, so a
|
|
287
|
+
* caller with no Effect context (an Ink component) uses it, and `process` is never consulted. Unset is not
|
|
288
|
+
* `dumb`.
|
|
289
|
+
*/
|
|
290
|
+
readonly term?: string | undefined;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* The two glyph sets: Unicode, and a plain-ASCII fallback for terminals that cannot draw it.
|
|
294
|
+
*
|
|
295
|
+
* @remarks
|
|
296
|
+
* The sets are shared, so they and their nested values are frozen.
|
|
297
|
+
*
|
|
298
|
+
* @public
|
|
299
|
+
*/
|
|
300
|
+
export declare class Glyphs {
|
|
301
|
+
private constructor();
|
|
302
|
+
/** Unicode symbols. */
|
|
303
|
+
static readonly unicode: GlyphSet;
|
|
304
|
+
/**
|
|
305
|
+
* Pick a glyph set without a service: the one `CliTheme` uses, as a pure function.
|
|
306
|
+
*
|
|
307
|
+
* @remarks
|
|
308
|
+
* `CliTheme.layer` reads `TERM` through `Config` and calls this, so the two agree. `StreamEnv` carries no
|
|
309
|
+
* `TERM`, and nothing else in it decides ASCII, so the caller passes `term` when it wants `auto` to mean
|
|
310
|
+
* something.
|
|
311
|
+
*
|
|
312
|
+
* @param options - whether to force ASCII or Unicode, and the `TERM` value `auto` reads
|
|
313
|
+
*/
|
|
314
|
+
static readonly select: (options?: GlyphSelectOptions) => GlyphSet;
|
|
315
|
+
/** ASCII-only symbols. */
|
|
316
|
+
static readonly ascii: GlyphSet;
|
|
317
|
+
}
|
|
318
|
+
//#endregion
|
|
319
|
+
//#region src/Token.d.ts
|
|
320
|
+
/**
|
|
321
|
+
* A named terminal colour: the eight ANSI colours and their bright variants.
|
|
322
|
+
*
|
|
323
|
+
* @remarks
|
|
324
|
+
* The bright variants are spelled as chalk and Ink spell them (`redBright`, `blackBright`), so a style maps to
|
|
325
|
+
* either without a rename table. `gray` is chalk's alias for `blackBright`.
|
|
326
|
+
*
|
|
327
|
+
* @public
|
|
328
|
+
*/
|
|
329
|
+
type NamedColor = "black" | "red" | "green" | "yellow" | "blue" | "magenta" | "cyan" | "white" | "blackBright" | "redBright" | "greenBright" | "yellowBright" | "blueBright" | "magentaBright" | "cyanBright" | "whiteBright" | "gray";
|
|
330
|
+
/**
|
|
331
|
+
* A terminal style: an optional foreground colour and text attributes.
|
|
332
|
+
*
|
|
333
|
+
* @remarks
|
|
334
|
+
* A style is data; it carries no escape sequences. `CliTheme.paint` renders it for the terminal's colour
|
|
335
|
+
* level, and at level `none` rendering is the identity. A hex foreground that is not `#rgb` or `#rrggbb`, and
|
|
336
|
+
* a name that is not a {@link NamedColor}, is ignored when rendered rather than failing.
|
|
337
|
+
*
|
|
338
|
+
* @public
|
|
339
|
+
*/
|
|
340
|
+
interface Style {
|
|
341
|
+
/** The foreground: a named colour or a `#rrggbb` hex. */
|
|
342
|
+
readonly fg?: NamedColor | `#${string}`;
|
|
343
|
+
/** Bold. */
|
|
344
|
+
readonly bold?: boolean;
|
|
345
|
+
/** Dim, or faint. */
|
|
346
|
+
readonly dim?: boolean;
|
|
347
|
+
/** Italic. */
|
|
348
|
+
readonly italic?: boolean;
|
|
349
|
+
/** Underline. */
|
|
350
|
+
readonly underline?: boolean;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* The semantic tokens a theme resolves to a {@link Style}.
|
|
354
|
+
*
|
|
355
|
+
* @public
|
|
356
|
+
*/
|
|
357
|
+
type TokenName = "success" | "failure" | "warning" | "info" | "error" | "muted" | "accent" | "emphasis";
|
|
358
|
+
/**
|
|
359
|
+
* Constructors for {@link Style} values, and the pure resolution of a token to one.
|
|
360
|
+
*
|
|
361
|
+
* @public
|
|
362
|
+
*/
|
|
363
|
+
export declare class Token {
|
|
364
|
+
private constructor();
|
|
365
|
+
/**
|
|
366
|
+
* The default {@link Style} of every token, frozen.
|
|
367
|
+
*
|
|
368
|
+
* @remarks
|
|
369
|
+
* Data, not a service: it is what `CliTheme` starts from, and a renderer with no Effect context (an Ink
|
|
370
|
+
* component) reads it directly.
|
|
371
|
+
*/
|
|
372
|
+
static readonly defaults: Readonly<Record<TokenName, Style>>;
|
|
373
|
+
/**
|
|
374
|
+
* The style a token or style resolves to, as a pure function: no service, no terminal.
|
|
375
|
+
*
|
|
376
|
+
* @remarks
|
|
377
|
+
* An explicit style resolves to itself. A token name resolves to its override when `overrides` has one, else
|
|
378
|
+
* its default; a name that is not a token (including an `Object.prototype` member) resolves to the empty
|
|
379
|
+
* style. This is the same resolution `CliTheme.paint` applies, which is what `StreamTheme.style` reports.
|
|
380
|
+
*
|
|
381
|
+
* @param token - a token name or an explicit style
|
|
382
|
+
* @param overrides - styles that replace the default of a token, as `CliThemeOptions.tokens` does
|
|
383
|
+
*/
|
|
384
|
+
static readonly resolve: (token: TokenName | Style, overrides?: Partial<Record<TokenName, Style>>) => Style;
|
|
385
|
+
/**
|
|
386
|
+
* A foreground from a hex colour.
|
|
387
|
+
*
|
|
388
|
+
* @param hex - `#rrggbb` (or `#rgb`)
|
|
389
|
+
*/
|
|
390
|
+
static readonly hex: (hex: `#${string}`) => Style;
|
|
391
|
+
/**
|
|
392
|
+
* A foreground from a named colour.
|
|
393
|
+
*
|
|
394
|
+
* @param color - the colour
|
|
395
|
+
*/
|
|
396
|
+
static readonly named: (color: NamedColor) => Style;
|
|
397
|
+
/**
|
|
398
|
+
* A style, as written. Exists so a style reads as a token at a call site.
|
|
399
|
+
*
|
|
400
|
+
* @param style - the style
|
|
401
|
+
*/
|
|
402
|
+
static readonly style: (style: Style) => Style;
|
|
403
|
+
}
|
|
404
|
+
//#endregion
|
|
405
|
+
//#region src/Status.d.ts
|
|
406
|
+
/**
|
|
407
|
+
* How one status looks: a Unicode glyph, an ASCII fallback, a token and a rank.
|
|
408
|
+
*
|
|
409
|
+
* @public
|
|
410
|
+
*/
|
|
411
|
+
interface StatusDef {
|
|
412
|
+
/** The Unicode glyph. */
|
|
413
|
+
readonly glyph: string;
|
|
414
|
+
/** The ASCII fallback, used when the theme's glyphs are ASCII. */
|
|
415
|
+
readonly ascii: string;
|
|
416
|
+
/** The semantic token, or an explicit style, the glyph is painted with. */
|
|
417
|
+
readonly token: TokenName | Style;
|
|
418
|
+
/** Severity for {@link Status.worst}: the highest rank wins. */
|
|
419
|
+
readonly rank: number;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* The names of the core vocabulary.
|
|
423
|
+
*
|
|
424
|
+
* @public
|
|
425
|
+
*/
|
|
426
|
+
type CoreStatusName = "success" | "failure" | "warning" | "info" | "skip" | "pending";
|
|
427
|
+
/**
|
|
428
|
+
* An open vocabulary of statuses.
|
|
429
|
+
*
|
|
430
|
+
* @remarks
|
|
431
|
+
* Start from `Status.core` and add your own with `extend`. The names are a type parameter,
|
|
432
|
+
* so `def` and `worst` reject a name the vocabulary does not have at compile time.
|
|
433
|
+
*
|
|
434
|
+
* @example
|
|
435
|
+
* ```ts
|
|
436
|
+
* import { Status } from "@effected/cli"
|
|
437
|
+
*
|
|
438
|
+
* const vocab = Status.extend({
|
|
439
|
+
* timeout: { glyph: "⏱", ascii: "[time]", token: "warning", rank: 85 },
|
|
440
|
+
* })
|
|
441
|
+
* const worst = vocab.worst(["success", "timeout"])
|
|
442
|
+
* // => "timeout"
|
|
443
|
+
* ```
|
|
444
|
+
*
|
|
445
|
+
* @public
|
|
446
|
+
*/
|
|
447
|
+
export declare class Status<Names extends string> {
|
|
448
|
+
private readonly defs;
|
|
449
|
+
private constructor();
|
|
450
|
+
/** The core vocabulary: success, skip, pending, info, warning and failure, by rank 10, 20, 30, 40, 60, 90. */
|
|
451
|
+
static readonly core: Status<CoreStatusName>;
|
|
452
|
+
/**
|
|
453
|
+
* The core vocabulary plus `extra`; an entry that reuses a core name replaces it.
|
|
454
|
+
*
|
|
455
|
+
* @param extra - the statuses to add, by name
|
|
456
|
+
*/
|
|
457
|
+
static readonly extend: <const Extra extends Record<string, StatusDef>>(extra: Extra) => Status<CoreStatusName | (keyof Extra & string)>;
|
|
458
|
+
/**
|
|
459
|
+
* This vocabulary plus `extra`; an entry that reuses a name replaces it.
|
|
460
|
+
*
|
|
461
|
+
* @remarks
|
|
462
|
+
* An entry may replace a core name. Replacing `warning` with a lower rank moves the threshold at which
|
|
463
|
+
* `CliMessage.status` defaults to stderr for this vocabulary, since that threshold is `warning`'s rank in the
|
|
464
|
+
* vocabulary it is given.
|
|
465
|
+
*
|
|
466
|
+
* @param extra - the statuses to add, by name
|
|
467
|
+
*/
|
|
468
|
+
extend<const Extra extends Record<string, StatusDef>>(extra: Extra): Status<Names | (keyof Extra & string)>;
|
|
469
|
+
/**
|
|
470
|
+
* The definition of a status.
|
|
471
|
+
*
|
|
472
|
+
* @remarks
|
|
473
|
+
* A name the vocabulary does not have is a defect: it throws an `Error` naming it and the names that exist. The
|
|
474
|
+
* types already reject one, so it is reachable only through a cast.
|
|
475
|
+
*
|
|
476
|
+
* @param name - a name in this vocabulary
|
|
477
|
+
*/
|
|
478
|
+
def(name: Names): StatusDef;
|
|
479
|
+
/**
|
|
480
|
+
* The full definition of a status as an immutable snapshot, for a caller that stores it.
|
|
481
|
+
*
|
|
482
|
+
* @remarks
|
|
483
|
+
* `def` answers the vocabulary's own entry. `resolve` answers a frozen copy, so a document node that holds
|
|
484
|
+
* the definition stays plain data and editing it cannot change the vocabulary. The copy is shallow: a
|
|
485
|
+
* `token` given as a `Style` keeps its own identity. Throws on an unknown name, as {@link Status.def} does;
|
|
486
|
+
* storing an empty definition in a document instead would fail far from the cause.
|
|
487
|
+
*
|
|
488
|
+
* @param name - a name in this vocabulary
|
|
489
|
+
*/
|
|
490
|
+
resolve(name: Names): StatusDef;
|
|
491
|
+
/**
|
|
492
|
+
* A status's glyph from a glyph set: `def.ascii` for an ASCII set, `def.glyph` otherwise. Unpainted, for a caller
|
|
493
|
+
* that draws it itself (an Ink tree, a reporter).
|
|
494
|
+
*
|
|
495
|
+
* @remarks
|
|
496
|
+
* Throws on an unknown name, as {@link Status.def} does.
|
|
497
|
+
*
|
|
498
|
+
* @param name - a name in this vocabulary
|
|
499
|
+
* @param glyphs - the glyph set, such as `Glyphs.unicode`, `Glyphs.ascii` or a theme's
|
|
500
|
+
*/
|
|
501
|
+
glyph(name: Names, glyphs: GlyphSet): string;
|
|
502
|
+
/**
|
|
503
|
+
* The status with the highest rank; a tie goes to the one that comes first in `names`.
|
|
504
|
+
*
|
|
505
|
+
* @remarks
|
|
506
|
+
* `rank` is SEVERITY, not an aggregation policy: the higher rank wins, so in `Status.core` a `skip` outranks a
|
|
507
|
+
* `success`. A consumer whose aggregate differs (a test run where passes dominate skips, say) folds its own
|
|
508
|
+
* rule over the names instead of reading this.
|
|
509
|
+
*
|
|
510
|
+
* Takes at least one name, so the answer is always a name. For an array that may be empty, use
|
|
511
|
+
* {@link Status.worstOption}. They are two methods because a literal and an array variable are the same
|
|
512
|
+
* array at runtime, so one method could not return a name for one and an `Option` for the other.
|
|
513
|
+
*
|
|
514
|
+
* @param names - the statuses to compare
|
|
515
|
+
*/
|
|
516
|
+
worst(names: Array$1.NonEmptyReadonlyArray<Names>): Names;
|
|
517
|
+
/**
|
|
518
|
+
* The status with the highest rank of an array that may be empty: `None` when it is, otherwise `Some` of
|
|
519
|
+
* the worst, a tie going to the one that comes first in `names`. Rank is severity, not an aggregation policy; see
|
|
520
|
+
* {@link Status.worst}.
|
|
521
|
+
*
|
|
522
|
+
* @param names - the statuses to compare
|
|
523
|
+
*/
|
|
524
|
+
worstOption(names: ReadonlyArray<Names>): Option.Option<Names>;
|
|
525
|
+
}
|
|
526
|
+
//#endregion
|
|
527
|
+
//#region src/CliTheme.d.ts
|
|
528
|
+
/**
|
|
529
|
+
* The shape of the {@link CliTheme} service: a colour level, a glyph set and the functions that use them.
|
|
530
|
+
*
|
|
531
|
+
* @remarks
|
|
532
|
+
* The whole shape is one immutable value with no mockable behaviour, so `Layer.succeed` (via
|
|
533
|
+
* {@link CliTheme.layerTest}) is the complete double.
|
|
534
|
+
*
|
|
535
|
+
* @public
|
|
536
|
+
*/
|
|
537
|
+
interface CliThemeShape extends StreamTheme {
|
|
538
|
+
/**
|
|
539
|
+
* The theme of one output stream, painting with THAT stream's colour level.
|
|
540
|
+
*
|
|
541
|
+
* @remarks
|
|
542
|
+
* The members above are the `stdout` ones. Anything written to stderr must be painted through
|
|
543
|
+
* `forStream("stderr")`: redirecting one stream (`tool 2>err.log`, `tool | jq`) changes that stream's colour
|
|
544
|
+
* and not the other's.
|
|
545
|
+
*/
|
|
546
|
+
readonly forStream: (stream: "stdout" | "stderr") => StreamTheme;
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* A theme bound to one stream's colour level.
|
|
550
|
+
*
|
|
551
|
+
* @public
|
|
552
|
+
*/
|
|
553
|
+
interface StreamTheme {
|
|
554
|
+
/** Render `text` in a token or an explicit style; the identity when colour is `none`. */
|
|
555
|
+
readonly paint: (token: TokenName | Style, text: string) => string;
|
|
556
|
+
/**
|
|
557
|
+
* The resolved {@link Style} of a token or style: the one `paint` renders, whatever the colour level.
|
|
558
|
+
*
|
|
559
|
+
* @remarks
|
|
560
|
+
* Pure data, for a renderer that is not ANSI (an Ink component maps it to its own props). It applies this
|
|
561
|
+
* theme's token overrides, so it is `Token.resolve` with them.
|
|
562
|
+
*/
|
|
563
|
+
readonly style: (token: TokenName | Style) => Style;
|
|
564
|
+
/** The raw opening SGR sequence of a token or style; `""` when colour is `none`. */
|
|
565
|
+
readonly sgr: (token: TokenName | Style) => string;
|
|
566
|
+
/** The glyph set in use. */
|
|
567
|
+
readonly glyphs: GlyphSet;
|
|
568
|
+
/** The colour level of the stream. */
|
|
569
|
+
readonly color: ColorLevel;
|
|
570
|
+
/** Render a status from a vocabulary: its glyph, painted with its token, then `text` when given. */
|
|
571
|
+
readonly status: <N extends string>(vocab: Status<N>, name: N, text?: string) => string;
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Options for {@link CliTheme.layer}.
|
|
575
|
+
*
|
|
576
|
+
* @public
|
|
577
|
+
*/
|
|
578
|
+
interface CliThemeOptions {
|
|
579
|
+
/** Styles that replace the default of a token. */
|
|
580
|
+
readonly tokens?: Partial<Record<TokenName, Style>> | undefined;
|
|
581
|
+
/** The glyph set. `auto`, the default, is ASCII only when `TERM=dumb`. */
|
|
582
|
+
readonly glyphs?: "unicode" | "ascii" | "auto" | undefined;
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Options for {@link CliTheme.layerTest}.
|
|
586
|
+
*
|
|
587
|
+
* @public
|
|
588
|
+
*/
|
|
589
|
+
interface CliThemeTestOptions {
|
|
590
|
+
/** The stdout colour level; `none` by default. */
|
|
591
|
+
readonly color?: ColorLevel | undefined;
|
|
592
|
+
/** The stderr colour level; the same as `color` by default. */
|
|
593
|
+
readonly stderrColor?: ColorLevel | undefined;
|
|
594
|
+
/** The glyph set; Unicode by default. */
|
|
595
|
+
readonly glyphs?: "unicode" | "ascii" | undefined;
|
|
596
|
+
}
|
|
597
|
+
declare const CliTheme_base: Context.ServiceClass<CliTheme, "@effected/cli/CliTheme", CliThemeShape>;
|
|
598
|
+
/**
|
|
599
|
+
* The presentation of a CLI: colour tokens, glyphs and statuses, decided once from the terminal.
|
|
600
|
+
*
|
|
601
|
+
* @remarks
|
|
602
|
+
* A `Context.Service`, not a `Reference`. A colour level is a fact about the terminal, not a preference with a
|
|
603
|
+
* safe default, so there is nothing sensible for an unprovided theme to read; requiring it puts `CliTheme` in
|
|
604
|
+
* `R` and a program that forgot to wire it fails to compile rather than printing plain text to a colour
|
|
605
|
+
* terminal. {@link CliTheme.layer} reads `TerminalEnv`.
|
|
606
|
+
*
|
|
607
|
+
* @public
|
|
608
|
+
*/
|
|
609
|
+
export declare class CliTheme extends CliTheme_base {
|
|
610
|
+
/**
|
|
611
|
+
* The theme for the terminal `TerminalEnv` describes.
|
|
612
|
+
*
|
|
613
|
+
* @remarks
|
|
614
|
+
* Bind the layer to a constant and provide it once. With `glyphs: "auto"` the glyph set is ASCII only when
|
|
615
|
+
* `TERM=dumb`, read through `Config`.
|
|
616
|
+
*
|
|
617
|
+
* @param options - token overrides and the glyph set
|
|
618
|
+
*/
|
|
619
|
+
static readonly layer: (options?: CliThemeOptions) => Layer.Layer<CliTheme, never, TerminalEnv>;
|
|
620
|
+
/**
|
|
621
|
+
* A fixed theme that needs nothing; `none` colour and Unicode glyphs unless told otherwise.
|
|
622
|
+
*
|
|
623
|
+
* @param options - the colour level and glyph set
|
|
624
|
+
*/
|
|
625
|
+
static readonly layerTest: (options?: CliThemeTestOptions) => Layer.Layer<CliTheme>;
|
|
626
|
+
/**
|
|
627
|
+
* Sets core's `Prompt.Theme` from the tokens, so built-in prompts match the rest of the output.
|
|
628
|
+
*
|
|
629
|
+
* @remarks
|
|
630
|
+
* The colour fields are raw SGR openers and are empty strings when colour is `none`. Under ASCII glyphs the
|
|
631
|
+
* prompt symbols fall back to ASCII too. A colourless theme is not byte-clean: core's `Ansi.annotate`
|
|
632
|
+
* appends a `\x1b[0m` reset, and prompts write cursor and underline codes, whatever the theme says.
|
|
633
|
+
*/
|
|
634
|
+
static readonly promptTheme: Layer.Layer<never, never, CliTheme>;
|
|
635
|
+
}
|
|
636
|
+
//#endregion
|
|
637
|
+
//#region src/Doc.d.ts
|
|
638
|
+
/**
|
|
639
|
+
* A status as a document stores it: its name and its resolved definition.
|
|
640
|
+
*
|
|
641
|
+
* @remarks
|
|
642
|
+
* The definition is stored, not the vocabulary, so a node stays plain data.
|
|
643
|
+
*
|
|
644
|
+
* @public
|
|
645
|
+
*/
|
|
646
|
+
interface StatusRef {
|
|
647
|
+
/** The name in the vocabulary it was resolved from. */
|
|
648
|
+
readonly name: string;
|
|
649
|
+
/** The resolved definition. */
|
|
650
|
+
readonly def: StatusDef;
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Where a link points: a URL, or a file with an optional position.
|
|
654
|
+
*
|
|
655
|
+
* @public
|
|
656
|
+
*/
|
|
657
|
+
type LinkTarget = {
|
|
658
|
+
readonly url: string;
|
|
659
|
+
} | {
|
|
660
|
+
readonly file: string;
|
|
661
|
+
readonly line?: number;
|
|
662
|
+
readonly col?: number;
|
|
663
|
+
};
|
|
664
|
+
/**
|
|
665
|
+
* Content that flows inside a line.
|
|
666
|
+
*
|
|
667
|
+
* @remarks
|
|
668
|
+
* - `Text`: a run of text, optionally painted with a token or style.
|
|
669
|
+
* - `Code`: code in a monospace span.
|
|
670
|
+
* - `Link`: a labelled link to a URL or a file position.
|
|
671
|
+
* - `StatusMark`: a status glyph, carrying its resolved definition.
|
|
672
|
+
* - `Path`: a path or breadcrumb, joined with the audience's path separator.
|
|
673
|
+
* - `Strong` and `Emphasis`: content in bold or italic; markdown `**` and `_`.
|
|
674
|
+
* - `File`: a path shown through the context's `displayPath`, never linked.
|
|
675
|
+
*
|
|
676
|
+
* @public
|
|
677
|
+
*/
|
|
678
|
+
type Inline = {
|
|
679
|
+
readonly _tag: "Text";
|
|
680
|
+
readonly value: string;
|
|
681
|
+
readonly token?: TokenName | Style;
|
|
682
|
+
} | {
|
|
683
|
+
readonly _tag: "Code";
|
|
684
|
+
readonly value: string;
|
|
685
|
+
} | {
|
|
686
|
+
readonly _tag: "Link";
|
|
687
|
+
readonly target: LinkTarget;
|
|
688
|
+
readonly label: ReadonlyArray<Inline>;
|
|
689
|
+
/**
|
|
690
|
+
* Whether plain text (and `ansi` with links off, and markdown with no URL) follows the label with the target in
|
|
691
|
+
* parentheses. Unset, it does so only when the label does not already show the target's display form.
|
|
692
|
+
*/
|
|
693
|
+
readonly suffix?: boolean;
|
|
694
|
+
} | {
|
|
695
|
+
readonly _tag: "StatusMark";
|
|
696
|
+
readonly name: string;
|
|
697
|
+
readonly def: StatusDef;
|
|
698
|
+
} | {
|
|
699
|
+
readonly _tag: "Path";
|
|
700
|
+
readonly segments: ReadonlyArray<string>;
|
|
701
|
+
} | {
|
|
702
|
+
readonly _tag: "Strong";
|
|
703
|
+
readonly content: ReadonlyArray<Inline>;
|
|
704
|
+
} | {
|
|
705
|
+
readonly _tag: "Emphasis";
|
|
706
|
+
readonly content: ReadonlyArray<Inline>;
|
|
707
|
+
} | {
|
|
708
|
+
readonly _tag: "File";
|
|
709
|
+
readonly path: string;
|
|
710
|
+
};
|
|
711
|
+
/**
|
|
712
|
+
* A node of a {@link TreeNode} tree: a label and its children.
|
|
713
|
+
*
|
|
714
|
+
* @public
|
|
715
|
+
*/
|
|
716
|
+
interface TreeNode {
|
|
717
|
+
/** What the node says. */
|
|
718
|
+
readonly label: ReadonlyArray<Inline>;
|
|
719
|
+
/** Its children, in order. */
|
|
720
|
+
readonly children: ReadonlyArray<TreeNode>;
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* One column of a table.
|
|
724
|
+
*
|
|
725
|
+
* @public
|
|
726
|
+
*/
|
|
727
|
+
interface Column {
|
|
728
|
+
/** The header cell. */
|
|
729
|
+
readonly header: ReadonlyArray<Inline>;
|
|
730
|
+
/** How the column's cells align; left when unset. */
|
|
731
|
+
readonly align?: "left" | "right" | "center";
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* One counter of a `Counts` block.
|
|
735
|
+
*
|
|
736
|
+
* @public
|
|
737
|
+
*/
|
|
738
|
+
interface Counter {
|
|
739
|
+
/** A stable identifier, for a caller's total rule. */
|
|
740
|
+
readonly key: string;
|
|
741
|
+
/** What the counter is called when shown. */
|
|
742
|
+
readonly label: string;
|
|
743
|
+
/** The count. */
|
|
744
|
+
readonly n: number;
|
|
745
|
+
/** The status the count is painted with. */
|
|
746
|
+
readonly status: StatusRef;
|
|
747
|
+
/** Show the counter when `n` is zero; by default a zero counter is hidden. */
|
|
748
|
+
readonly showZero?: boolean;
|
|
749
|
+
}
|
|
750
|
+
/**
|
|
751
|
+
* A block of a document.
|
|
752
|
+
*
|
|
753
|
+
* @remarks
|
|
754
|
+
* - `Paragraph`: one logical line; a paragraph of paragraphs is a `Section`.
|
|
755
|
+
* - `List` and `Table`: with an optional `cap` on the rows shown, and an `overflow` that says what the hidden rows
|
|
756
|
+
* amount to, given how many there are.
|
|
757
|
+
* - `Tree`: nested labels.
|
|
758
|
+
* - `Collapsible`: a titled body a renderer may fold.
|
|
759
|
+
* - `Callout`: a body with a kind.
|
|
760
|
+
* - `CodeBlock`: preformatted text, with an optional language.
|
|
761
|
+
* - `Diff`: expected against received text, with an optional cap on the lines shown.
|
|
762
|
+
* - `Section`: children under an optional title.
|
|
763
|
+
* - `Counts`: labelled counters in one of three layouts. `total` replaces the default sum of every counter, and
|
|
764
|
+
* `durationMs` is how long it took. `share: false` drops the headline's share of the total, and `paint` limits what
|
|
765
|
+
* is painted.
|
|
766
|
+
* - `Verbatim`: lines kept exactly, each indented, never wrapped.
|
|
767
|
+
* - `CountsTable`: a table of `Counts` rows, a column per counter key, a `duration` column when some row has one, and
|
|
768
|
+
* an optional summed total row.
|
|
769
|
+
* - `Lines`: one line per entry; markdown keeps them apart with hard breaks.
|
|
770
|
+
* - `Line`: one line, which `truncate` cuts to the width instead of wrapping.
|
|
771
|
+
* - `DiffText`: a unified diff, as given; `truncate` cuts each line to the width.
|
|
772
|
+
* - A `List` may be `compact`, with no blank lines between an item's children (a blank line of an item's own content
|
|
773
|
+
* keeps the item's indent in plain and `ansi`), and a `Table` may be `style: "pipe"`.
|
|
774
|
+
* - `Annotation`: a GitHub Actions annotation, which only `Render.githubLog` writes.
|
|
775
|
+
*
|
|
776
|
+
* Nodes are plain data and nothing decodes them, so a function field such as `overflow` or `total` is fine.
|
|
777
|
+
*
|
|
778
|
+
* @public
|
|
779
|
+
*/
|
|
780
|
+
type Block = {
|
|
781
|
+
readonly _tag: "Heading";
|
|
782
|
+
readonly level: 1 | 2 | 3 | 4;
|
|
783
|
+
readonly content: ReadonlyArray<Inline>;
|
|
784
|
+
} | {
|
|
785
|
+
readonly _tag: "Paragraph";
|
|
786
|
+
readonly content: ReadonlyArray<Inline>;
|
|
787
|
+
} | {
|
|
788
|
+
readonly _tag: "List";
|
|
789
|
+
readonly items: ReadonlyArray<Block>;
|
|
790
|
+
readonly cap?: number;
|
|
791
|
+
readonly overflow?: (hidden: number) => ReadonlyArray<Inline>;
|
|
792
|
+
readonly compact?: boolean;
|
|
793
|
+
} | {
|
|
794
|
+
readonly _tag: "Table";
|
|
795
|
+
readonly columns: ReadonlyArray<Column>;
|
|
796
|
+
readonly rows: ReadonlyArray<ReadonlyArray<ReadonlyArray<Inline>>>;
|
|
797
|
+
readonly cap?: number;
|
|
798
|
+
readonly overflow?: (hidden: number) => ReadonlyArray<Inline>;
|
|
799
|
+
readonly style?: "pipe";
|
|
800
|
+
} | {
|
|
801
|
+
readonly _tag: "Tree";
|
|
802
|
+
readonly root: TreeNode;
|
|
803
|
+
} | {
|
|
804
|
+
readonly _tag: "Collapsible";
|
|
805
|
+
readonly title: ReadonlyArray<Inline>;
|
|
806
|
+
readonly body: ReadonlyArray<Block>;
|
|
807
|
+
readonly open?: boolean;
|
|
808
|
+
} | {
|
|
809
|
+
readonly _tag: "Callout";
|
|
810
|
+
readonly kind: "note" | "tip" | "important" | "warning" | "caution";
|
|
811
|
+
readonly body: ReadonlyArray<Block>;
|
|
812
|
+
} | {
|
|
813
|
+
readonly _tag: "CodeBlock";
|
|
814
|
+
readonly lang?: string;
|
|
815
|
+
readonly text: string;
|
|
816
|
+
} | {
|
|
817
|
+
readonly _tag: "Diff";
|
|
818
|
+
readonly expected: string;
|
|
819
|
+
readonly received: string;
|
|
820
|
+
readonly cap?: number;
|
|
821
|
+
} | {
|
|
822
|
+
readonly _tag: "Section";
|
|
823
|
+
readonly title?: ReadonlyArray<Inline>;
|
|
824
|
+
readonly children: ReadonlyArray<Block>;
|
|
825
|
+
} | {
|
|
826
|
+
readonly _tag: "Counts";
|
|
827
|
+
readonly label?: ReadonlyArray<Inline>;
|
|
828
|
+
readonly counters: ReadonlyArray<Counter>;
|
|
829
|
+
readonly total?: (counters: ReadonlyArray<Counter>) => number;
|
|
830
|
+
readonly qualifier?: ReadonlyArray<Inline>;
|
|
831
|
+
readonly durationMs?: number;
|
|
832
|
+
readonly layout: "inline" | "columns" | "row";
|
|
833
|
+
readonly share?: boolean;
|
|
834
|
+
readonly paint?: "all" | "glyph" | "none";
|
|
835
|
+
readonly suffix?: ReadonlyArray<Inline>;
|
|
836
|
+
} | {
|
|
837
|
+
readonly _tag: "CountsTable";
|
|
838
|
+
readonly rows: ReadonlyArray<CountsRow>;
|
|
839
|
+
readonly totalRow?: boolean | ReadonlyArray<Inline>;
|
|
840
|
+
readonly labelHeader?: ReadonlyArray<Inline>;
|
|
841
|
+
readonly durationHeader?: ReadonlyArray<Inline>;
|
|
842
|
+
} | {
|
|
843
|
+
readonly _tag: "Lines";
|
|
844
|
+
readonly lines: ReadonlyArray<ReadonlyArray<Inline>>;
|
|
845
|
+
} | {
|
|
846
|
+
readonly _tag: "Line";
|
|
847
|
+
readonly content: ReadonlyArray<Inline>;
|
|
848
|
+
readonly truncate?: boolean;
|
|
849
|
+
} | {
|
|
850
|
+
readonly _tag: "DiffText";
|
|
851
|
+
readonly text: string;
|
|
852
|
+
readonly cap?: number;
|
|
853
|
+
readonly truncate?: boolean;
|
|
854
|
+
} | {
|
|
855
|
+
readonly _tag: "Verbatim";
|
|
856
|
+
readonly text: string;
|
|
857
|
+
readonly indent?: number;
|
|
858
|
+
} | ({
|
|
859
|
+
readonly _tag: "Annotation";
|
|
860
|
+
readonly message: string;
|
|
861
|
+
} & AnnotationOptions);
|
|
862
|
+
/**
|
|
863
|
+
* Where and how a GitHub Actions annotation is shown: its level, and an optional position and title.
|
|
864
|
+
*
|
|
865
|
+
* @public
|
|
866
|
+
*/
|
|
867
|
+
interface AnnotationOptions {
|
|
868
|
+
/** `error`, `warning` or `notice`. */
|
|
869
|
+
readonly level: "error" | "warning" | "notice";
|
|
870
|
+
/** The file it points at, as the runner should show it (relative to the workspace). */
|
|
871
|
+
readonly file?: string;
|
|
872
|
+
/** The line it starts on. */
|
|
873
|
+
readonly line?: number;
|
|
874
|
+
/** The column it starts at. */
|
|
875
|
+
readonly col?: number;
|
|
876
|
+
/** The line it ends on. */
|
|
877
|
+
readonly endLine?: number;
|
|
878
|
+
/** The column it ends at. */
|
|
879
|
+
readonly endColumn?: number;
|
|
880
|
+
/** Its title. */
|
|
881
|
+
readonly title?: string;
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
884
|
+
* One row of a `CountsTable`: its label, its counters and how long it took.
|
|
885
|
+
*
|
|
886
|
+
* @public
|
|
887
|
+
*/
|
|
888
|
+
interface CountsRow {
|
|
889
|
+
/** What the row is, such as a project name. */
|
|
890
|
+
readonly label: ReadonlyArray<Inline>;
|
|
891
|
+
/** Its counters; their keys pick the column each lands in. */
|
|
892
|
+
readonly counters: ReadonlyArray<Counter>;
|
|
893
|
+
/** How long it took, in milliseconds, shown with `Fmt.duration` in the duration column. */
|
|
894
|
+
readonly durationMs?: number;
|
|
895
|
+
}
|
|
896
|
+
/**
|
|
897
|
+
* The options of {@link Doc.countsTable}.
|
|
898
|
+
*
|
|
899
|
+
* @public
|
|
900
|
+
*/
|
|
901
|
+
interface CountsTableOptions {
|
|
902
|
+
/** A last row summing each column: labelled with a plain `Total` when `true`, or with the content given (`Doc.strong("Total")` for a bold one). */
|
|
903
|
+
readonly totalRow?: boolean | InlineInput;
|
|
904
|
+
/** The header of the label column, such as `Project`; empty when unset. */
|
|
905
|
+
readonly labelHeader?: InlineInput;
|
|
906
|
+
/** The header of the duration column, shown only when some row has a `durationMs`; `duration` when unset. */
|
|
907
|
+
readonly durationHeader?: InlineInput;
|
|
908
|
+
}
|
|
909
|
+
/**
|
|
910
|
+
* Options for {@link Doc.list}.
|
|
911
|
+
*
|
|
912
|
+
* @public
|
|
913
|
+
*/
|
|
914
|
+
interface ListOptions extends OverflowOptions {
|
|
915
|
+
/** No blank lines between the children of an item, such as a section's title and body. */
|
|
916
|
+
readonly compact?: boolean;
|
|
917
|
+
}
|
|
918
|
+
/**
|
|
919
|
+
* Options for {@link Doc.table}.
|
|
920
|
+
*
|
|
921
|
+
* @public
|
|
922
|
+
*/
|
|
923
|
+
interface TableOptions extends OverflowOptions {
|
|
924
|
+
/**
|
|
925
|
+
* `pipe` gives plain and `ansi` istanbul's shape: rules above and below the header and at the end, cells joined
|
|
926
|
+
* with ` | `. Markdown's table is a pipe table either way. Unset, the columns are space-aligned.
|
|
927
|
+
*/
|
|
928
|
+
readonly style?: "pipe";
|
|
929
|
+
}
|
|
930
|
+
/**
|
|
931
|
+
* Options for `Doc.link`.
|
|
932
|
+
*
|
|
933
|
+
* @public
|
|
934
|
+
*/
|
|
935
|
+
interface LinkOptions {
|
|
936
|
+
/**
|
|
937
|
+
* Whether the target follows the label in parentheses where a link cannot be followed: plain text, `ansi` with
|
|
938
|
+
* links off, markdown with no URL. `true` always, `false` never; unset, only when the label does not already show
|
|
939
|
+
* the target's display form (`displayPath(file)`, then `:line` and `:col` when present).
|
|
940
|
+
*/
|
|
941
|
+
readonly suffix?: boolean;
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* A whole document: its blocks, in order.
|
|
945
|
+
*
|
|
946
|
+
* @public
|
|
947
|
+
*/
|
|
948
|
+
type Document = ReadonlyArray<Block>;
|
|
949
|
+
/**
|
|
950
|
+
* What a constructor accepts for content: a string, one `Inline`, or an array of either.
|
|
951
|
+
*
|
|
952
|
+
* @remarks
|
|
953
|
+
* A string becomes a `Text` node with no token.
|
|
954
|
+
*
|
|
955
|
+
* @public
|
|
956
|
+
*/
|
|
957
|
+
type InlineInput = string | Inline | ReadonlyArray<string | Inline>;
|
|
958
|
+
/**
|
|
959
|
+
* A tree node as a constructor accepts it: the label may be a string and `children` may be left out.
|
|
960
|
+
*
|
|
961
|
+
* @public
|
|
962
|
+
*/
|
|
963
|
+
interface TreeInput {
|
|
964
|
+
/** What the node says. */
|
|
965
|
+
readonly label: InlineInput;
|
|
966
|
+
/** Its children; none when omitted. */
|
|
967
|
+
readonly children?: ReadonlyArray<TreeInput>;
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* The inline node with a given `_tag`, so a constructor can return its precise type.
|
|
971
|
+
*
|
|
972
|
+
* @public
|
|
973
|
+
*/
|
|
974
|
+
type InlineOf<Tag extends Inline["_tag"]> = Extract<Inline, {
|
|
975
|
+
readonly _tag: Tag;
|
|
976
|
+
}>;
|
|
977
|
+
/**
|
|
978
|
+
* The block node with a given `_tag`, so a constructor can return its precise type.
|
|
979
|
+
*
|
|
980
|
+
* @public
|
|
981
|
+
*/
|
|
982
|
+
type BlockOf<Tag extends Block["_tag"]> = Extract<Block, {
|
|
983
|
+
readonly _tag: Tag;
|
|
984
|
+
}>;
|
|
985
|
+
/**
|
|
986
|
+
* The cap and overflow options of a list or table.
|
|
987
|
+
*
|
|
988
|
+
* @public
|
|
989
|
+
*/
|
|
990
|
+
interface OverflowOptions {
|
|
991
|
+
/** The most rows to show; the renderer hides the rest. */
|
|
992
|
+
readonly cap?: number;
|
|
993
|
+
/** Says what the hidden rows amount to, given how many there are; it is a function and is never serialised. */
|
|
994
|
+
readonly overflow?: (hidden: number) => InlineInput;
|
|
995
|
+
}
|
|
996
|
+
/**
|
|
997
|
+
* The options of {@link Doc.counts}.
|
|
998
|
+
*
|
|
999
|
+
* @public
|
|
1000
|
+
*/
|
|
1001
|
+
interface CountsOptions {
|
|
1002
|
+
/** A leading label. */
|
|
1003
|
+
readonly label?: InlineInput;
|
|
1004
|
+
/** The counters, in the order they are shown. */
|
|
1005
|
+
readonly counters: ReadonlyArray<Counter>;
|
|
1006
|
+
/** Replaces the default total, the sum of `n` over every counter, for example to fold timed-out runs in. */
|
|
1007
|
+
readonly total?: (counters: ReadonlyArray<Counter>) => number;
|
|
1008
|
+
/** Text after the counters, such as `(1 flaky)`. */
|
|
1009
|
+
readonly qualifier?: InlineInput;
|
|
1010
|
+
/** How long it took, in milliseconds. */
|
|
1011
|
+
readonly durationMs?: number;
|
|
1012
|
+
/** How the counters are laid out. */
|
|
1013
|
+
readonly layout: "inline" | "columns" | "row";
|
|
1014
|
+
/** Whether the first counter shows its share of the total, `n/total`; `true` by default. `false` shows `n label`. */
|
|
1015
|
+
readonly share?: boolean;
|
|
1016
|
+
/**
|
|
1017
|
+
* What is painted: `all` (the default) paints the counters, the label, the qualifier and the duration; `glyph`
|
|
1018
|
+
* paints only a status glyph, if one is shown; `none` paints nothing.
|
|
1019
|
+
*/
|
|
1020
|
+
readonly paint?: "all" | "glyph" | "none";
|
|
1021
|
+
/** Text after the duration, such as `across 3 files`. */
|
|
1022
|
+
readonly suffix?: InlineInput;
|
|
1023
|
+
}
|
|
1024
|
+
/**
|
|
1025
|
+
* Options for {@link Doc.print}.
|
|
1026
|
+
*
|
|
1027
|
+
* @public
|
|
1028
|
+
*/
|
|
1029
|
+
interface DocPrintOptions {
|
|
1030
|
+
/** The stream to write to; `stdout` by default. */
|
|
1031
|
+
readonly stream?: "stdout" | "stderr" | undefined;
|
|
1032
|
+
/**
|
|
1033
|
+
* The renderer. `auto`, the default, is chosen from the audience: `plain` for an agent, `githubLog` for a CI
|
|
1034
|
+
* that `CurrentRuntimeEnv` says is GitHub Actions and `plain` for any other, and `ansi` for a human.
|
|
1035
|
+
*/
|
|
1036
|
+
readonly format?: "auto" | "plain" | "ansi" | "markdown" | "githubLog" | undefined;
|
|
1037
|
+
/** Turns an absolute path into its display form, for example relative to the workspace; see `Render.context`. */
|
|
1038
|
+
readonly displayPath?: ((absolute: string) => string) | undefined;
|
|
1039
|
+
/** The display columns to lay out at, replacing the audience's default; see `Render.context`. */
|
|
1040
|
+
readonly width?: number | undefined;
|
|
1041
|
+
}
|
|
1042
|
+
/**
|
|
1043
|
+
* Constructors for the document IR, and two helpers a renderer shares.
|
|
1044
|
+
*
|
|
1045
|
+
* @remarks
|
|
1046
|
+
* Every constructor returns a frozen node and copies the arrays it is given, so editing an input afterwards
|
|
1047
|
+
* cannot change a document. An optional field that is not given is absent from the node, not `undefined`.
|
|
1048
|
+
* Content arguments accept a string, an `Inline` or an array of either.
|
|
1049
|
+
*
|
|
1050
|
+
* A node is plain data: nothing decodes or encodes one, so a function field such as `overflow` or `total` is fine
|
|
1051
|
+
* and a document is not meant to be serialised.
|
|
1052
|
+
*
|
|
1053
|
+
* Freezing covers what a `Doc` constructor builds. A literal you write by hand is not frozen, and a `Style` object
|
|
1054
|
+
* given as a token is shared by reference (the freeze of a status definition is shallow for the same reason).
|
|
1055
|
+
*
|
|
1056
|
+
* @example
|
|
1057
|
+
* ```ts
|
|
1058
|
+
* import { Doc, Status } from "@effected/cli"
|
|
1059
|
+
*
|
|
1060
|
+
* const report = [
|
|
1061
|
+
* Doc.heading(2, "Results"),
|
|
1062
|
+
* Doc.paragraph(Doc.status(Status.core, "success"), " ", "3 checks passed"),
|
|
1063
|
+
* Doc.table([{ header: "Check" }, { header: "Time", align: "right" }], [["lint", "1.2s"]]),
|
|
1064
|
+
* ]
|
|
1065
|
+
* // Written for whoever is reading: `yield* Doc.print(report)`
|
|
1066
|
+
* ```
|
|
1067
|
+
*
|
|
1068
|
+
* @public
|
|
1069
|
+
*/
|
|
1070
|
+
export declare class Doc {
|
|
1071
|
+
private constructor();
|
|
1072
|
+
/**
|
|
1073
|
+
* A run of text.
|
|
1074
|
+
*
|
|
1075
|
+
* @param value - the text
|
|
1076
|
+
* @param token - a semantic token or a style to paint it with
|
|
1077
|
+
*/
|
|
1078
|
+
static text(value: string, token?: TokenName | Style): InlineOf<"Text">;
|
|
1079
|
+
/**
|
|
1080
|
+
* Code in a monospace span.
|
|
1081
|
+
*
|
|
1082
|
+
* @param value - the code
|
|
1083
|
+
*/
|
|
1084
|
+
static code(value: string): InlineOf<"Code">;
|
|
1085
|
+
/**
|
|
1086
|
+
* A link to a URL or a file position.
|
|
1087
|
+
*
|
|
1088
|
+
* @param target - `{ url }` or `{ file, line?, col? }`
|
|
1089
|
+
* @param label - what the link says; when omitted, the bare URL or file path, which leaves out `line` and `col`
|
|
1090
|
+
* @param options - `suffix`, whether the target follows the label where the link cannot be followed
|
|
1091
|
+
*/
|
|
1092
|
+
static link(target: LinkTarget, label?: InlineInput, options?: LinkOptions): InlineOf<"Link">;
|
|
1093
|
+
/**
|
|
1094
|
+
* A link when there is a target, and its label alone when there is none: a string label as a `Text`, any other
|
|
1095
|
+
* inline as itself.
|
|
1096
|
+
*
|
|
1097
|
+
* @param target - `{ url }`, `{ file, line?, col? }`, or `undefined` for no link
|
|
1098
|
+
* @param label - what the link says
|
|
1099
|
+
* @param options - `suffix`, whether the target follows the label where the link cannot be followed
|
|
1100
|
+
*/
|
|
1101
|
+
static link(target: LinkTarget | undefined, label: string | Inline, options?: LinkOptions): Inline;
|
|
1102
|
+
/**
|
|
1103
|
+
* A status glyph, holding the resolved definition.
|
|
1104
|
+
*
|
|
1105
|
+
* @remarks
|
|
1106
|
+
* A name the vocabulary does not have is a compile error.
|
|
1107
|
+
*
|
|
1108
|
+
* @param vocab - the vocabulary the name belongs to
|
|
1109
|
+
* @param name - a status name in it
|
|
1110
|
+
*/
|
|
1111
|
+
static status<N extends string>(vocab: Status<N>, name: NoInfer<N>): InlineOf<"StatusMark">;
|
|
1112
|
+
/**
|
|
1113
|
+
* Content in bold: markdown `**…**`, bold in `ansi`, and the content as is in plain and `githubLog`.
|
|
1114
|
+
*
|
|
1115
|
+
* @param content - any number of strings, inlines or arrays of them, in order
|
|
1116
|
+
*/
|
|
1117
|
+
static strong(...content: Array<InlineInput>): InlineOf<"Strong">;
|
|
1118
|
+
/**
|
|
1119
|
+
* Content in italic: markdown `*…*` (which GFM reads inside a word too), italic in `ansi`, and the content as is in
|
|
1120
|
+
* plain and `githubLog`.
|
|
1121
|
+
*
|
|
1122
|
+
* @param content - any number of strings, inlines or arrays of them, in order
|
|
1123
|
+
*/
|
|
1124
|
+
static em(...content: Array<InlineInput>): InlineOf<"Emphasis">;
|
|
1125
|
+
/**
|
|
1126
|
+
* A file path, shown through the context's `displayPath` and never linked.
|
|
1127
|
+
*
|
|
1128
|
+
* @param path - the path, usually absolute
|
|
1129
|
+
*/
|
|
1130
|
+
static file(path: string): InlineOf<"File">;
|
|
1131
|
+
/**
|
|
1132
|
+
* A path or breadcrumb; a renderer joins the segments with the audience's separator.
|
|
1133
|
+
*
|
|
1134
|
+
* @param segments - the segments, in order
|
|
1135
|
+
*/
|
|
1136
|
+
static path(...segments: Array<string>): InlineOf<"Path">;
|
|
1137
|
+
/**
|
|
1138
|
+
* A heading.
|
|
1139
|
+
*
|
|
1140
|
+
* @param level - 1 to 4
|
|
1141
|
+
* @param content - the heading text
|
|
1142
|
+
*/
|
|
1143
|
+
static heading(level: 1 | 2 | 3 | 4, content: InlineInput): BlockOf<"Heading">;
|
|
1144
|
+
/**
|
|
1145
|
+
* One logical line of content.
|
|
1146
|
+
*
|
|
1147
|
+
* @param content - any number of strings, inlines or arrays of them, in order
|
|
1148
|
+
*/
|
|
1149
|
+
static paragraph(...content: Array<InlineInput>): BlockOf<"Paragraph">;
|
|
1150
|
+
/**
|
|
1151
|
+
* A list of blocks.
|
|
1152
|
+
*
|
|
1153
|
+
* @param items - the items
|
|
1154
|
+
* @param options - `cap`, `overflow`, and `compact` for no blank lines inside an item
|
|
1155
|
+
*/
|
|
1156
|
+
static list(items: ReadonlyArray<Block>, options?: ListOptions): BlockOf<"List">;
|
|
1157
|
+
/**
|
|
1158
|
+
* A table.
|
|
1159
|
+
*
|
|
1160
|
+
* @param columns - the columns: a header and an optional alignment each
|
|
1161
|
+
* @param rows - the rows; each cell takes a string, an inline or an array of either
|
|
1162
|
+
* @param options - `cap`, `overflow`, and `style: "pipe"` for istanbul's shape in plain and `ansi`
|
|
1163
|
+
*/
|
|
1164
|
+
static table(columns: ReadonlyArray<{
|
|
1165
|
+
readonly header: InlineInput;
|
|
1166
|
+
readonly align?: "left" | "right" | "center";
|
|
1167
|
+
}>, rows: ReadonlyArray<ReadonlyArray<InlineInput>>, options?: TableOptions): BlockOf<"Table">;
|
|
1168
|
+
/**
|
|
1169
|
+
* A tree of labels.
|
|
1170
|
+
*
|
|
1171
|
+
* @param root - the root; a node's `children` may be left out
|
|
1172
|
+
*/
|
|
1173
|
+
static tree(root: TreeInput): BlockOf<"Tree">;
|
|
1174
|
+
/**
|
|
1175
|
+
* A titled body a renderer may fold.
|
|
1176
|
+
*
|
|
1177
|
+
* @param title - the title
|
|
1178
|
+
* @param body - the body
|
|
1179
|
+
* @param options - `open` asks for it to start unfolded
|
|
1180
|
+
*/
|
|
1181
|
+
static collapsible(title: InlineInput, body: ReadonlyArray<Block>, options?: {
|
|
1182
|
+
readonly open?: boolean;
|
|
1183
|
+
}): BlockOf<"Collapsible">;
|
|
1184
|
+
/**
|
|
1185
|
+
* A callout.
|
|
1186
|
+
*
|
|
1187
|
+
* @param kind - `note`, `tip`, `important`, `warning` or `caution`
|
|
1188
|
+
* @param body - the body
|
|
1189
|
+
*/
|
|
1190
|
+
static callout(kind: "note" | "tip" | "important" | "warning" | "caution", body: ReadonlyArray<Block>): BlockOf<"Callout">;
|
|
1191
|
+
/**
|
|
1192
|
+
* Preformatted text.
|
|
1193
|
+
*
|
|
1194
|
+
* @param text - the text
|
|
1195
|
+
* @param lang - its language, for a renderer that fences it
|
|
1196
|
+
*/
|
|
1197
|
+
static codeBlock(text: string, lang?: string): BlockOf<"CodeBlock">;
|
|
1198
|
+
/**
|
|
1199
|
+
* Expected against received text.
|
|
1200
|
+
*
|
|
1201
|
+
* @param expected - the expected text
|
|
1202
|
+
* @param received - the received text
|
|
1203
|
+
* @param options - `cap` limits the lines shown
|
|
1204
|
+
*/
|
|
1205
|
+
static diff(expected: string, received: string, options?: {
|
|
1206
|
+
readonly cap?: number;
|
|
1207
|
+
}): BlockOf<"Diff">;
|
|
1208
|
+
/**
|
|
1209
|
+
* Children under an optional title.
|
|
1210
|
+
*
|
|
1211
|
+
* @param title - the title, or `undefined` for none
|
|
1212
|
+
* @param children - the blocks
|
|
1213
|
+
*/
|
|
1214
|
+
static section(title: InlineInput | undefined, children: ReadonlyArray<Block>): BlockOf<"Section">;
|
|
1215
|
+
/**
|
|
1216
|
+
* One counter of a `Counts` block, with its status definition resolved.
|
|
1217
|
+
*
|
|
1218
|
+
* @remarks
|
|
1219
|
+
* A name the vocabulary does not have is a compile error.
|
|
1220
|
+
*
|
|
1221
|
+
* @param vocab - the vocabulary the status belongs to
|
|
1222
|
+
* @param name - a status name in it
|
|
1223
|
+
* @param options - the counter's `key`, `label` and count `n`, and `showZero` to keep it when `n` is zero
|
|
1224
|
+
*/
|
|
1225
|
+
static counter<N extends string>(vocab: Status<N>, name: NoInfer<N>, options: {
|
|
1226
|
+
readonly key: string;
|
|
1227
|
+
readonly label: string;
|
|
1228
|
+
readonly n: number;
|
|
1229
|
+
readonly showZero?: boolean;
|
|
1230
|
+
}): Counter;
|
|
1231
|
+
/**
|
|
1232
|
+
* Counters in one of three layouts.
|
|
1233
|
+
*
|
|
1234
|
+
* @param options - the counters, the layout and the optional label, total rule, qualifier and duration
|
|
1235
|
+
*/
|
|
1236
|
+
static counts(options: CountsOptions): BlockOf<"Counts">;
|
|
1237
|
+
/**
|
|
1238
|
+
* Counters as a table: a row per entry, a column per counter key (in the order the keys first appear, headed by
|
|
1239
|
+
* the counter's label), and an optional total row summing each column.
|
|
1240
|
+
*
|
|
1241
|
+
* @remarks
|
|
1242
|
+
* A row without a counter for some key leaves that cell empty, and it counts as zero in the total. A counter whose
|
|
1243
|
+
* `n` is zero shows `0`, as a `Doc.table` cell would: a counter's `showZero` has no effect in a table, only in a
|
|
1244
|
+
* `Counts` block, so there is no need to set it. `totalRow`
|
|
1245
|
+
* labels the total row with a plain `Total` when `true`, or with the content given: for a bold one, pass
|
|
1246
|
+
* `totalRow: Doc.strong("Total")`. A column is headed by its counter's `label`; a counter's status paints its cells
|
|
1247
|
+
* in `ansi` and is ignored in markdown, so a plain numbers table may pass any status. `labelHeader` heads the label column, which
|
|
1248
|
+
* is otherwise empty. When some row has a `durationMs`, a last column shows it with `Fmt.duration`, headed
|
|
1249
|
+
* `durationHeader` (`duration` by default); a row without one has an empty cell there and counts as zero in the
|
|
1250
|
+
* total row's summed duration.
|
|
1251
|
+
*
|
|
1252
|
+
* @param rows - each row's label, counters and optional duration
|
|
1253
|
+
* @param options - `totalRow`, to add the summed row; the label and duration column headers
|
|
1254
|
+
*/
|
|
1255
|
+
static countsTable(rows: ReadonlyArray<{
|
|
1256
|
+
readonly label: InlineInput;
|
|
1257
|
+
readonly counters: ReadonlyArray<Counter>;
|
|
1258
|
+
readonly durationMs?: number;
|
|
1259
|
+
}>, options?: CountsTableOptions): BlockOf<"CountsTable">;
|
|
1260
|
+
/**
|
|
1261
|
+
* Lines, one per entry, in every renderer: markdown joins them with hard breaks so they never collapse into one.
|
|
1262
|
+
*
|
|
1263
|
+
* @param lines - the entries; each takes a string, an inline or an array of either
|
|
1264
|
+
*/
|
|
1265
|
+
static lines(lines: ReadonlyArray<InlineInput>): BlockOf<"Lines">;
|
|
1266
|
+
/**
|
|
1267
|
+
* One line of content; with `truncate`, it is cut to the width with the glyph set's ellipsis instead of wrapping.
|
|
1268
|
+
*
|
|
1269
|
+
* @remarks
|
|
1270
|
+
* Without `truncate` a line longer than the width wraps. For a single line that must never wrap nor be cut, such
|
|
1271
|
+
* as a test's full name used as a title, use {@link Doc.verbatim}.
|
|
1272
|
+
*
|
|
1273
|
+
* @param content - the line
|
|
1274
|
+
* @param options - `truncate`
|
|
1275
|
+
*/
|
|
1276
|
+
static line(content: InlineInput, options?: {
|
|
1277
|
+
readonly truncate?: boolean;
|
|
1278
|
+
}): BlockOf<"Line">;
|
|
1279
|
+
/**
|
|
1280
|
+
* A unified diff as given, such as a test runner's: sanitized, its `+` and `-` lines painted `success` and
|
|
1281
|
+
* `failure` in `ansi`, and a `diff` fence in markdown.
|
|
1282
|
+
*
|
|
1283
|
+
* @remarks
|
|
1284
|
+
* With `truncate`, plain and `ansi` cut each line to the width with the glyph set's ellipsis instead of wrapping
|
|
1285
|
+
* it; an agent's or a CI's width is unbounded, so nothing is cut for them unless the context gives a finite width.
|
|
1286
|
+
* Markdown keeps every line whole. Inside a compact list item a blank line of the diff keeps the item's indent.
|
|
1287
|
+
*
|
|
1288
|
+
* A trailing line break ends the last line, as in a unified diff file, and adds no blank line after it: `"a\n"` is
|
|
1289
|
+
* one line. To end on a blank line, end the text with two line breaks.
|
|
1290
|
+
*
|
|
1291
|
+
* @param unified - the diff
|
|
1292
|
+
* @param options - `cap`, the most lines shown; `truncate`, to cut each line to the width
|
|
1293
|
+
*/
|
|
1294
|
+
static diffText(unified: string, options?: {
|
|
1295
|
+
readonly cap?: number;
|
|
1296
|
+
readonly truncate?: boolean;
|
|
1297
|
+
}): BlockOf<"DiffText">;
|
|
1298
|
+
/**
|
|
1299
|
+
* Lines kept exactly: each indented by `indent` spaces, sanitized, and never wrapped.
|
|
1300
|
+
*
|
|
1301
|
+
* @remarks
|
|
1302
|
+
* Plain, `ansi` and `githubLog` write the lines as they are; markdown fences them, so the indentation survives.
|
|
1303
|
+
*
|
|
1304
|
+
* It is the tool for a single line that must never wrap nor be cut, whatever the width: {@link Doc.line} wraps at
|
|
1305
|
+
* the width, or cuts with `truncate`, and `verbatim` does neither.
|
|
1306
|
+
*
|
|
1307
|
+
* @param text - the lines
|
|
1308
|
+
* @param options - `indent`, the spaces in front of every line; none by default
|
|
1309
|
+
*/
|
|
1310
|
+
static verbatim(text: string, options?: {
|
|
1311
|
+
readonly indent?: number;
|
|
1312
|
+
}): BlockOf<"Verbatim">;
|
|
1313
|
+
/**
|
|
1314
|
+
* A GitHub Actions annotation: `Render.githubLog` writes it as one workflow command (`::error file=…::message`),
|
|
1315
|
+
* and every other renderer writes nothing.
|
|
1316
|
+
*
|
|
1317
|
+
* @remarks
|
|
1318
|
+
* It is the kit's own command, so `githubLog` does not neutralize it; its message and properties are escaped, so
|
|
1319
|
+
* no text in them can end the command or start another. It is a command where a line starts: at the top level, as a
|
|
1320
|
+
* top-level section's child, or as a direct child of a group's body. Nested deeper, it is dropped.
|
|
1321
|
+
*
|
|
1322
|
+
* @param options - the level, and the optional file, position and title
|
|
1323
|
+
* @param message - what it says
|
|
1324
|
+
*/
|
|
1325
|
+
static annotation(options: AnnotationOptions, message: string): BlockOf<"Annotation">;
|
|
1326
|
+
/**
|
|
1327
|
+
* The total of a `Counts` block: the caller's rule when it has one, otherwise the sum of `n` over every counter.
|
|
1328
|
+
*
|
|
1329
|
+
* @remarks
|
|
1330
|
+
* The rule sees every counter, including the ones a renderer hides, so hiding never changes the total.
|
|
1331
|
+
*
|
|
1332
|
+
* @param block - the `Counts` block
|
|
1333
|
+
*/
|
|
1334
|
+
static total(block: BlockOf<"Counts">): number;
|
|
1335
|
+
/**
|
|
1336
|
+
* The counters a renderer shows: every one except a zero counter that does not ask for `showZero`.
|
|
1337
|
+
*
|
|
1338
|
+
* @param block - the `Counts` block
|
|
1339
|
+
*/
|
|
1340
|
+
static visibleCounters(block: BlockOf<"Counts">): ReadonlyArray<Counter>;
|
|
1341
|
+
/**
|
|
1342
|
+
* Render a document for whoever is running the program and write it to a stream.
|
|
1343
|
+
*
|
|
1344
|
+
* @remarks
|
|
1345
|
+
* The context is {@link Render.context} for the stream, so the width, the colour, the links and the audience
|
|
1346
|
+
* come from the services the program already has, and the text is written with `Console.log` or
|
|
1347
|
+
* `Console.error`: a test captures it by swapping the `Console`. With `format: "auto"` the renderer follows
|
|
1348
|
+
* the audience, and the width is unbounded for an agent and a CI.
|
|
1349
|
+
*
|
|
1350
|
+
* An agent is never written an escape of any kind, even with an explicit `format: "ansi"`: its context is
|
|
1351
|
+
* colourless and its links are off. A document that renders to nothing prints nothing.
|
|
1352
|
+
*
|
|
1353
|
+
* `CurrentRuntimeEnv` is read if the environment has one and is not required: a `ci` audience prints
|
|
1354
|
+
* GitHub's log format only when it says GitHub Actions, and plain text otherwise, including when it is
|
|
1355
|
+
* absent. An explicit `format` is honoured whatever the audience.
|
|
1356
|
+
*
|
|
1357
|
+
* @param doc - the document
|
|
1358
|
+
* @param options - the stream and the format
|
|
1359
|
+
*/
|
|
1360
|
+
static readonly print: (doc: Document, options?: DocPrintOptions) => Effect.Effect<void, never, CliTheme | TerminalEnv | Audience | CliLinks>;
|
|
1361
|
+
}
|
|
1362
|
+
//#endregion
|
|
1363
|
+
//#region src/CliLinks.d.ts
|
|
1364
|
+
/**
|
|
1365
|
+
* Whether file links open in an editor.
|
|
1366
|
+
*
|
|
1367
|
+
* @remarks
|
|
1368
|
+
* `vscode` writes `vscode://file/<path>:<line>:<col>`, `file` writes `file://<path>`, `off` writes no file link, and
|
|
1369
|
+
* `auto` picks `vscode` when it finds a signal of VS Code and `file` otherwise.
|
|
1370
|
+
*
|
|
1371
|
+
* @public
|
|
1372
|
+
*/
|
|
1373
|
+
type EditorLinks = "auto" | "vscode" | "file" | "off";
|
|
1374
|
+
/**
|
|
1375
|
+
* The shape of the {@link CliLinks} service: the mode decided, and the URL a link target becomes.
|
|
1376
|
+
*
|
|
1377
|
+
* @public
|
|
1378
|
+
*/
|
|
1379
|
+
interface CliLinksShape {
|
|
1380
|
+
/** The mode `auto` resolved to, or the one that was asked for. */
|
|
1381
|
+
readonly mode: "vscode" | "file" | "off";
|
|
1382
|
+
/**
|
|
1383
|
+
* The URL a target opens, or `None` when it has none.
|
|
1384
|
+
*
|
|
1385
|
+
* @remarks
|
|
1386
|
+
* A `{ url }` target is its URL, whatever the mode. A `{ file }` target is `vscode://file/<path>:<line>:<col>` or
|
|
1387
|
+
* `file://<path>`, with the path URL-encoded; `off` gives it none, and so does a relative path when the layer
|
|
1388
|
+
* has no working directory to resolve it against. A column needs a line.
|
|
1389
|
+
*/
|
|
1390
|
+
readonly target: (target: LinkTarget) => Option.Option<string>;
|
|
1391
|
+
}
|
|
1392
|
+
/**
|
|
1393
|
+
* Options for {@link CliLinks.layer}.
|
|
1394
|
+
*
|
|
1395
|
+
* @public
|
|
1396
|
+
*/
|
|
1397
|
+
interface CliLinksOptions {
|
|
1398
|
+
/** The setting, `auto` by default. An environment variable the consumer names beats it. */
|
|
1399
|
+
readonly editorLinks?: EditorLinks | undefined;
|
|
1400
|
+
/** The environment variable that overrides the setting, read through `Config`. Not read unless named. */
|
|
1401
|
+
readonly envVar?: string | undefined;
|
|
1402
|
+
/** The working directory; `PWD` through `Config`, then `Path.resolve(".")`, when omitted. */
|
|
1403
|
+
readonly cwd?: string | undefined;
|
|
1404
|
+
}
|
|
1405
|
+
/**
|
|
1406
|
+
* The options of {@link CliLinks.linker}.
|
|
1407
|
+
*
|
|
1408
|
+
* @public
|
|
1409
|
+
*/
|
|
1410
|
+
interface CliLinksLinkerOptions {
|
|
1411
|
+
/** The service that turns a target into a URL. */
|
|
1412
|
+
readonly links: CliLinksShape;
|
|
1413
|
+
/** Whether the stream's terminal renders OSC 8 hyperlinks. */
|
|
1414
|
+
readonly hyperlinks: boolean;
|
|
1415
|
+
/** Who the output is for. */
|
|
1416
|
+
readonly audience: AudienceKind;
|
|
1417
|
+
}
|
|
1418
|
+
declare const CliLinks_base: Context.ServiceClass<CliLinks, "@effected/cli/CliLinks", CliLinksShape>;
|
|
1419
|
+
/**
|
|
1420
|
+
* Editor-aware links for file targets: where a link to a file opens.
|
|
1421
|
+
*
|
|
1422
|
+
* @remarks
|
|
1423
|
+
* The mode is decided once, when the layer is built. `auto` is `vscode` when `CurrentRuntimeEnv.terminal` is
|
|
1424
|
+
* `vscode` (`TERM_PROGRAM=vscode`) or a `.vscode/` directory sits at the project root, and `file` otherwise. The
|
|
1425
|
+
* root is the nearest directory, from the working directory up, that holds `.git` or `pnpm-workspace.yaml`; the
|
|
1426
|
+
* climb is bounded, at most 64 directories above the working directory, and stops where `Path.dirname` reaches the
|
|
1427
|
+
* filesystem root. With no root, the working directory itself is checked.
|
|
1428
|
+
*
|
|
1429
|
+
* Whether a link is written at all is a separate question, answered by {@link CliLinks.linker}.
|
|
1430
|
+
*
|
|
1431
|
+
* @public
|
|
1432
|
+
*/
|
|
1433
|
+
export declare class CliLinks extends CliLinks_base {
|
|
1434
|
+
/**
|
|
1435
|
+
* The links for the working directory, reading the filesystem for a `.vscode/` directory.
|
|
1436
|
+
*
|
|
1437
|
+
* @remarks
|
|
1438
|
+
* A layer-returning function mints a fresh layer per call: call it once and bind the result to a constant.
|
|
1439
|
+
*
|
|
1440
|
+
* @param options - the setting, the environment variable that overrides it, and the working directory
|
|
1441
|
+
*/
|
|
1442
|
+
static readonly layer: (options?: CliLinksOptions) => Layer.Layer<CliLinks, never, FileSystem.FileSystem | Path.Path | CurrentRuntimeEnv>;
|
|
1443
|
+
/**
|
|
1444
|
+
* Links fixed to a mode, with no filesystem: a relative path has no link, since there is no working directory.
|
|
1445
|
+
*
|
|
1446
|
+
* @param mode - `vscode`, `file` or `off`
|
|
1447
|
+
*/
|
|
1448
|
+
static readonly layerTest: (mode: "vscode" | "file" | "off") => Layer.Layer<CliLinks>;
|
|
1449
|
+
/**
|
|
1450
|
+
* The function that writes a link: a target and a label in, the label out, wrapped in OSC 8 when it should be.
|
|
1451
|
+
*
|
|
1452
|
+
* @remarks
|
|
1453
|
+
* It writes the hyperlink `ESC ] 8 ; ; URL ESC \ label ESC ] 8 ; ; ESC \` only when the stream's terminal can
|
|
1454
|
+
* render it (`hyperlinks`) and the audience is not an agent, which never gets an escape of any kind; in every other
|
|
1455
|
+
* case, and whenever the target has no URL, it returns the label unchanged. The URL has its control characters
|
|
1456
|
+
* removed again here, so a hostile target cannot end the sequence early or start another, and a URL whose scheme is
|
|
1457
|
+
* not one a link may have (`javascript:`, `data:`, and the like; the same list markdown uses) is the label alone. It is pure and cheap,
|
|
1458
|
+
* which {@link RenderContext}'s `link` requires.
|
|
1459
|
+
*
|
|
1460
|
+
* @param options - the links, whether hyperlinks are available, and the audience
|
|
1461
|
+
*/
|
|
1462
|
+
static readonly linker: (options: CliLinksLinkerOptions) => (target: LinkTarget, label: string) => string;
|
|
1463
|
+
}
|
|
1464
|
+
//#endregion
|
|
1465
|
+
//#region src/CliLogger.d.ts
|
|
1466
|
+
/**
|
|
1467
|
+
* How a log record is turned into a line.
|
|
1468
|
+
*
|
|
1469
|
+
* @public
|
|
1470
|
+
*/
|
|
1471
|
+
interface CliLoggerOptions {
|
|
1472
|
+
/**
|
|
1473
|
+
* Render one message. Defaults to joining an array with spaces and
|
|
1474
|
+
* `String`-ing anything else.
|
|
1475
|
+
*
|
|
1476
|
+
* @remarks
|
|
1477
|
+
* An array arrives because `Effect.log("synced", 3, "repos")` is variadic.
|
|
1478
|
+
*
|
|
1479
|
+
* The text is sanitised, because it is whatever the program logged: with the default render, the line has its
|
|
1480
|
+
* escape sequences and control characters removed (a line break stays one, a tab becomes a space); with yours, you
|
|
1481
|
+
* receive the string parts already sanitised and own what you add, a colour included. Under GitHub Actions, where
|
|
1482
|
+
* `CurrentRuntimeEnv` says so, a line the runner would read as a workflow command is neutralized either way.
|
|
1483
|
+
*
|
|
1484
|
+
* The logger reads `CurrentRuntimeEnv` from the logging fiber's context, so a line logged outside its scope
|
|
1485
|
+
* (`CliLogger.layer()` provided alone, with no `CurrentRuntimeEnv`, or the warnings logged while `CliRuntime.main`
|
|
1486
|
+
* builds its environment) is sanitised but not neutralized. Provide the environment around the program, as `main`
|
|
1487
|
+
* does, for the neutralizing to apply.
|
|
1488
|
+
*/
|
|
1489
|
+
readonly render?: ((message: unknown) => string) | undefined;
|
|
1490
|
+
/**
|
|
1491
|
+
* The level at and above which output goes to stderr. Defaults to `"All"`,
|
|
1492
|
+
* so every log level is a diagnostic and stdout carries only what the
|
|
1493
|
+
* program writes with `Console.log`.
|
|
1494
|
+
*
|
|
1495
|
+
* @remarks
|
|
1496
|
+
* Pass `"Error"` to send only errors to stderr, for a tool whose output *is*
|
|
1497
|
+
* its log lines rather than a separate document written with
|
|
1498
|
+
* `Console.log`.
|
|
1499
|
+
*/
|
|
1500
|
+
readonly stderrFrom?: LogLevel.LogLevel | undefined;
|
|
1501
|
+
}
|
|
1502
|
+
/**
|
|
1503
|
+
* A `Logger` that renders CLI output rather than service logs: no timestamp, level or fiber id, with every level
|
|
1504
|
+
* going to stderr by default so stdout carries only what the program writes.
|
|
1505
|
+
*
|
|
1506
|
+
* @remarks
|
|
1507
|
+
* Effect's default logger emits `[00:33:56.619] INFO (#2): message`. That is
|
|
1508
|
+
* the right shape for a long-running service being scraped and the wrong one
|
|
1509
|
+
* for a tool a person is watching: the timestamp, level and fiber id are noise
|
|
1510
|
+
* in front of output a human is reading, and they make a formatted block — a
|
|
1511
|
+
* permissions table, a summary — unreadable.
|
|
1512
|
+
*
|
|
1513
|
+
* **A program that never installs a CLI logger looks correct in review and
|
|
1514
|
+
* ships timestamps to its users**, so install this one at the program's
|
|
1515
|
+
* boundary.
|
|
1516
|
+
*
|
|
1517
|
+
* It writes through the `Console` reference read off the logging fiber,
|
|
1518
|
+
* synchronously, as core's own default logger does: `Logger.make` takes a
|
|
1519
|
+
* synchronous callback, and a `Stdio` sink write is an `Effect` a logger cannot
|
|
1520
|
+
* `yield*`. `Console.Console` is a `Context.Reference`, so it never appears in
|
|
1521
|
+
* `R`, and a test swaps the reference rather than stubbing a global.
|
|
1522
|
+
*
|
|
1523
|
+
* @example
|
|
1524
|
+
* ```ts
|
|
1525
|
+
* import { CliLogger } from "@effected/cli"
|
|
1526
|
+
* import { Console, Effect } from "effect"
|
|
1527
|
+
*
|
|
1528
|
+
* const program = Effect.gen(function* () {
|
|
1529
|
+
* yield* Effect.log("synced 3 repos") // stderr, no timestamp — a diagnostic
|
|
1530
|
+
* yield* Console.log("3 repos synced") // stdout — the program's actual output
|
|
1531
|
+
* yield* Effect.logError("one failed") // stderr
|
|
1532
|
+
* })
|
|
1533
|
+
*
|
|
1534
|
+
* program.pipe(Effect.provide(CliLogger.layer()))
|
|
1535
|
+
* ```
|
|
1536
|
+
*
|
|
1537
|
+
* `stderrFrom` defaults to `"All"`: a CLI's stdout is its product, so every
|
|
1538
|
+
* log level is a diagnostic unless a consumer narrows the threshold. Write
|
|
1539
|
+
* program output with `Console.log`, never `Effect.log`. Pass
|
|
1540
|
+
* `stderrFrom: "Error"` for a tool whose output *is* its log lines.
|
|
1541
|
+
*
|
|
1542
|
+
* @public
|
|
1543
|
+
*/
|
|
1544
|
+
export declare class CliLogger {
|
|
1545
|
+
private constructor();
|
|
1546
|
+
/**
|
|
1547
|
+
* The logger itself, for composing into an existing `Logger.layer` set.
|
|
1548
|
+
*
|
|
1549
|
+
* @remarks
|
|
1550
|
+
* Prefer {@link CliLogger.layer}. Reach for this only when you are building
|
|
1551
|
+
* the logger set yourself and want this one among several.
|
|
1552
|
+
*/
|
|
1553
|
+
static readonly make: (options?: CliLoggerOptions) => Logger.Logger<unknown, void>;
|
|
1554
|
+
/**
|
|
1555
|
+
* Replace the default logger with this one.
|
|
1556
|
+
*
|
|
1557
|
+
* @remarks
|
|
1558
|
+
* `Logger.layer` **replaces** rather than merges, so nothing is emitted twice.
|
|
1559
|
+
*
|
|
1560
|
+
* Merge this into the layer you provide to the whole program rather than
|
|
1561
|
+
* providing it beneath: merged, it also covers lines emitted during layer
|
|
1562
|
+
* construction, which is exactly where a startup failure prints.
|
|
1563
|
+
*/
|
|
1564
|
+
static readonly layer: (options?: CliLoggerOptions) => Layer.Layer<never>;
|
|
1565
|
+
}
|
|
1566
|
+
//#endregion
|
|
1567
|
+
//#region src/CliLog.d.ts
|
|
1568
|
+
/**
|
|
1569
|
+
* Options for `CliLog.layer`.
|
|
1570
|
+
*
|
|
1571
|
+
* @public
|
|
1572
|
+
*/
|
|
1573
|
+
interface CliLogOptions {
|
|
1574
|
+
/**
|
|
1575
|
+
* The diagnostics level, for a host that has already decided it.
|
|
1576
|
+
*
|
|
1577
|
+
* @remarks
|
|
1578
|
+
* Beats `envVar`, which is then not read at all (so a bad value there neither warns nor overrides this), and
|
|
1579
|
+
* loses to core's `--log-level` flag like every diagnostics level: the sink follows the flag while it is set.
|
|
1580
|
+
*/
|
|
1581
|
+
readonly level?: LogLevel.LogLevel | undefined;
|
|
1582
|
+
/**
|
|
1583
|
+
* The environment variable that sets the diagnostics level, for example `MYTOOL_LOG_LEVEL`. Read through
|
|
1584
|
+
* `Config`, never `process`. Unset or empty means `None`. Ignored when `level` is given.
|
|
1585
|
+
*/
|
|
1586
|
+
readonly envVar?: string | undefined;
|
|
1587
|
+
/**
|
|
1588
|
+
* Whether to install the plain `CliLogger` for ordinary lines. `true` by default.
|
|
1589
|
+
*
|
|
1590
|
+
* @remarks
|
|
1591
|
+
* `false` is the diagnostics-only mode for a library host (an MCP server, a test reporter): the layer installs
|
|
1592
|
+
* only the diagnostics sink, the file sink if any, and `extraLoggers`. With no level set as well, stderr gets
|
|
1593
|
+
* no output. An invalid level in `envVar` still prints its one warning line, through a private `CliLogger`,
|
|
1594
|
+
* since that is a configuration error the host should see.
|
|
1595
|
+
*
|
|
1596
|
+
* Only `CliLog`'s own records are silenced. Under `CliRuntime.main`, what the platform logs while it builds follows
|
|
1597
|
+
* the build-time format: in NDJSON (`json`, or `auto` for an agent or a CI) it goes through this layer, so `false`
|
|
1598
|
+
* silences it there as at runtime; otherwise it goes through a plain `CliLogger`, routed by `logger.stderrFrom` as the
|
|
1599
|
+
* host set it. The audience-override warning is a
|
|
1600
|
+
* configuration error and is never silenced: it is written exactly once, as NDJSON when the build-time format is
|
|
1601
|
+
* NDJSON and as a plain line otherwise, whatever this option says, to stderr alone (never stdout, whatever
|
|
1602
|
+
* `logger.stderrFrom` says) and never to `extraLoggers` or the file sink. The failure report and the `CliMessage` lines
|
|
1603
|
+
* always go through a plain `CliLogger`.
|
|
1604
|
+
*/
|
|
1605
|
+
readonly plainLogger?: boolean | undefined;
|
|
1606
|
+
/**
|
|
1607
|
+
* `json` is NDJSON, `pretty` a human line, `auto` (the default) decides by the audience alone: NDJSON for an agent
|
|
1608
|
+
* or a CI, the pretty `CliLogger` line for a human, at build time and at runtime alike.
|
|
1609
|
+
*
|
|
1610
|
+
* @remarks
|
|
1611
|
+
* Stderr's terminal state is never consulted, so a human piping stderr to a file gets plain lines, never a mix of
|
|
1612
|
+
* plain and NDJSON; colour still follows `stderr.color`, so those lines carry no escapes when stderr is not a colour
|
|
1613
|
+
* terminal. Pass `format: "json"` for machine-readable logs whoever runs the program.
|
|
1614
|
+
*
|
|
1615
|
+
* Under `CliRuntime.main` with `env.log`, what the platform logs while it builds is written before the platform
|
|
1616
|
+
* provides the terminal or the arguments, so `auto` decides those lines from what needs no platform: an audience
|
|
1617
|
+
* flag in {@link CliLogOptions.argv}, else the audience override variable (`env.audienceEnvVar`), else agent and
|
|
1618
|
+
* CI detection from the environment. An agent or a CI gets NDJSON, as its runtime lines are; anything else gets
|
|
1619
|
+
* a plain line, the same choice the runtime lines make. `json` is NDJSON and `pretty` plain throughout.
|
|
1620
|
+
*/
|
|
1621
|
+
readonly format?: "auto" | "json" | "pretty" | undefined;
|
|
1622
|
+
/**
|
|
1623
|
+
* The program's arguments, for the format of what the platform logs while it builds under `CliRuntime.main` with
|
|
1624
|
+
* `format: "auto"`: an audience flag (`--agent`, `--ci`, `--human`, `--audience <kind>`) in them decides those
|
|
1625
|
+
* lines as it decides the run's. Only `CliRuntime.main` reads this.
|
|
1626
|
+
*
|
|
1627
|
+
* @remarks
|
|
1628
|
+
* The arguments core parses come from the platform's `Stdio`, which does not exist until the platform is built, and
|
|
1629
|
+
* this package never reads `process`. A Node host passes `process.argv.slice(2)`; without it the build-time lines
|
|
1630
|
+
* follow the environment alone, so `--agent` with no agent detected gets plain lines until the platform is built.
|
|
1631
|
+
*/
|
|
1632
|
+
readonly argv?: ReadonlyArray<string> | undefined;
|
|
1633
|
+
/** Options for the `CliLogger` this layer builds for ordinary log lines; see {@link CliLoggerOptions}. */
|
|
1634
|
+
readonly logger?: CliLoggerOptions | undefined;
|
|
1635
|
+
/**
|
|
1636
|
+
* Loggers to keep beside the `CliLogger` and the sink, for example a telemetry logger: the layer owns the
|
|
1637
|
+
* whole set, so anything not listed here is dropped.
|
|
1638
|
+
*
|
|
1639
|
+
* @remarks
|
|
1640
|
+
* Each is floored at the `MinimumLogLevel` it had, like the `CliLogger`, so lowering the level for the
|
|
1641
|
+
* diagnostics sink never makes it see records it would not have seen otherwise.
|
|
1642
|
+
*/
|
|
1643
|
+
readonly extraLoggers?: ReadonlyArray<Logger.Logger<unknown, unknown>> | undefined;
|
|
1644
|
+
/**
|
|
1645
|
+
* Whether a line the GitHub Actions runner would read as a workflow command is neutralized. `auto`, the default,
|
|
1646
|
+
* follows the `CurrentRuntimeEnv` of the fiber that logs, and where that fiber has none, `runtimeEnv`, else the one
|
|
1647
|
+
* the layer was built with: a host that builds this layer over its environment covers records logged outside it
|
|
1648
|
+
* too. `true` always neutralizes, `false` never does.
|
|
1649
|
+
*/
|
|
1650
|
+
readonly neutralize?: boolean | "auto" | undefined;
|
|
1651
|
+
/**
|
|
1652
|
+
* The runtime environment `neutralize: "auto"` falls back to for a record whose fiber has no `CurrentRuntimeEnv`.
|
|
1653
|
+
*
|
|
1654
|
+
* @remarks
|
|
1655
|
+
* Given, it is used in place of the `CurrentRuntimeEnv` the layer captured when it was built, and beats it; the
|
|
1656
|
+
* logging fiber's own `CurrentRuntimeEnv` still comes first. The capture is invisible in the layer's type (it is read
|
|
1657
|
+
* if present, never required), so a host that builds this layer outside its environment either passes the snapshot
|
|
1658
|
+
* here, for example `RuntimeEnv.fromRecord(process.env)`, or provides `CurrentRuntimeEnv` around the layer.
|
|
1659
|
+
*
|
|
1660
|
+
* Neutralization under `"auto"` reads the logging fiber's `CurrentRuntimeEnv`, then this option, then the
|
|
1661
|
+
* `CurrentRuntimeEnv` captured when the layer was built. With none of the three, a record is not neutralized: set
|
|
1662
|
+
* this option, provide `CurrentRuntimeEnv` around the layer, or pass `neutralize: true`. Every `CliLog.layer`
|
|
1663
|
+
* overload points here.
|
|
1664
|
+
*/
|
|
1665
|
+
readonly runtimeEnv?: RuntimeEnv | undefined;
|
|
1666
|
+
}
|
|
1667
|
+
/**
|
|
1668
|
+
* Where the file sink writes: a literal path, or the environment variable that holds it.
|
|
1669
|
+
*
|
|
1670
|
+
* @public
|
|
1671
|
+
*/
|
|
1672
|
+
type CliLogFile = {
|
|
1673
|
+
readonly envVar: string;
|
|
1674
|
+
} | {
|
|
1675
|
+
readonly path: string;
|
|
1676
|
+
};
|
|
1677
|
+
/**
|
|
1678
|
+
* {@link CliLogOptions} with a file sink, which is what makes the layer require `FileSystem` and `Path`.
|
|
1679
|
+
*
|
|
1680
|
+
* @public
|
|
1681
|
+
*/
|
|
1682
|
+
interface CliLogFileOptions extends CliLogOptions {
|
|
1683
|
+
/**
|
|
1684
|
+
* Also write every record the sink accepts to a file as NDJSON, asynchronously.
|
|
1685
|
+
*
|
|
1686
|
+
* @remarks
|
|
1687
|
+
* The line is identical to the stderr NDJSON line for the same log call and is filtered by the same
|
|
1688
|
+
* {@link CliLog.Level}. Lines are queued and appended by a fiber scoped to the layer, so logging never waits
|
|
1689
|
+
* on the disk, and the parent directory is created. The first write error prints exactly one stderr line,
|
|
1690
|
+
* `diagnostics log file <path> failed: <message>; further file logging disabled`, and the program keeps
|
|
1691
|
+
* running with its normal exit code: from then on lines, including any still queued, are discarded silently.
|
|
1692
|
+
* Closing the layer's scope flushes the lines queued before it, unless the sink had already disabled itself.
|
|
1693
|
+
* `{ envVar }` names the variable that holds the path; unset or empty, no file is written.
|
|
1694
|
+
*
|
|
1695
|
+
* `undefined` writes no file but keeps the requirements of a file sink (`FileSystem` and `Path`) in `R`, so a
|
|
1696
|
+
* host whose sink is optional has one stable layer type either way.
|
|
1697
|
+
*
|
|
1698
|
+
* Under `CliRuntime.main` with `env.log`, what the platform logs while it builds, before it provides
|
|
1699
|
+
* `FileSystem`, reaches stderr but not the file; the file starts with the program's own records.
|
|
1700
|
+
*/
|
|
1701
|
+
readonly file: CliLogFile | undefined;
|
|
1702
|
+
}
|
|
1703
|
+
/**
|
|
1704
|
+
* Diagnostics kept apart from a program's output: a level, a format and a place to write.
|
|
8
1705
|
*
|
|
9
1706
|
* @remarks
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* `
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
1707
|
+
* Two kinds of line must never be silenced by a diagnostics default: the failure report
|
|
1708
|
+
* `CliRuntime.reportFailures` writes through `CliLogger`, and the `CliMessage` lines. This package therefore
|
|
1709
|
+
* never makes the diagnostics level a global switch. The diagnostics logger filters on its **own** threshold,
|
|
1710
|
+
* {@link CliLog.Level}, and writes to stderr only.
|
|
1711
|
+
*
|
|
1712
|
+
* `CliLog.layer` **owns the whole logger set**. It builds a `CliLogger` for ordinary log lines and the
|
|
1713
|
+
* diagnostics sink itself and replaces whatever was installed, without reading it, so there is no order to get
|
|
1714
|
+
* wrong. Use it instead of `CliLogger.layer`, not with it: `CliLogger.layer` alone is the no-diagnostics path,
|
|
1715
|
+
* and a `CliLogger.layer` layered on top would replace this layer's set.
|
|
1716
|
+
*
|
|
1717
|
+
* Effect drops a record below `MinimumLogLevel` before any logger runs, so to let a debug record reach the
|
|
1718
|
+
* diagnostics logger `MinimumLogLevel` has to be lowered. `CliLog.layer` does that only when the
|
|
1719
|
+
* diagnostics level is below the ambient minimum, and in the same step floors the `CliLogger` it built at the
|
|
1720
|
+
* minimum it had, so it never prints a record the diagnostics level alone let through. A failure report is
|
|
1721
|
+
* written outside the scope core's `--log-level` flag sets, so `--log-level none` does not silence it either.
|
|
1722
|
+
*
|
|
1723
|
+
* `format: "auto"`, the default, decides by the audience alone, at build time and at runtime alike: NDJSON for an
|
|
1724
|
+
* agent or a CI, the pretty line for a human, whatever stderr's terminal state. A human piping stderr therefore gets
|
|
1725
|
+
* plain lines (without escapes unless stderr is a colour terminal); pass `format: "json"` for machine-readable logs.
|
|
1726
|
+
*
|
|
1727
|
+
* The text a program logs is sanitised before anything is painted in the pretty line (the message, the component and an
|
|
1728
|
+
* error's cause lose their escape sequences and control characters), and under GitHub Actions, where
|
|
1729
|
+
* `CurrentRuntimeEnv` in the logging fiber's context says so, a line the runner would read as a workflow command is
|
|
1730
|
+
* neutralized. An NDJSON record is not safe merely because `JSON.stringify` escapes control characters: the runner's
|
|
1731
|
+
* legacy parser reads `##[` anywhere in a line, so under Actions it is written as the JSON escape `#\u0023[`, which
|
|
1732
|
+
* decodes to the identical text. The file sink's lines are not read by the runner and are written as they are.
|
|
1733
|
+
*
|
|
1734
|
+
* `CurrentRuntimeEnv` is read from the logging fiber's context, and where that has none, from the `runtimeEnv` option,
|
|
1735
|
+
* else from the layer's own build context (captured if present, never required), so a host that builds the layer over
|
|
1736
|
+
* its environment, or names it with `runtimeEnv`, neutralizes every record. A record with none of the three (a program
|
|
1737
|
+
* with no `CurrentRuntimeEnv` anywhere) is sanitised but not neutralized, unless the `neutralize` option says otherwise.
|
|
1738
|
+
*
|
|
1739
|
+
* Core's `--log-level` flag sets `MinimumLogLevel` inside the command. While it is set to something other than
|
|
1740
|
+
* the value this layer installed, the diagnostics logger follows the flag instead of its own level: it writes
|
|
1741
|
+
* every record that reaches it. The `CliLogger` prints the same record too, so a record at or above the ambient
|
|
1742
|
+
* minimum is written twice, once plain and once to the diagnostics sink. Stderr is therefore not pure NDJSON while
|
|
1743
|
+
* diagnostics are on: a parser reads the lines that start with `{`.
|
|
1744
|
+
*
|
|
1745
|
+
* One edge: a `--log-level` value that EQUALS the level this layer installed cannot be told from no flag, so the
|
|
1746
|
+
* sink keeps filtering on its own level rather than following the flag. The plain `CliLogger` prints those records
|
|
1747
|
+
* regardless.
|
|
1748
|
+
*
|
|
1749
|
+
* @example
|
|
1750
|
+
* ```ts
|
|
1751
|
+
* import { CliRuntime } from "@effected/cli"
|
|
1752
|
+
* import { NodeRuntime, NodeServices } from "@effect/platform-node"
|
|
1753
|
+
*
|
|
1754
|
+
* // `env.log` makes `main` install `CliLog.layer`: set MYTOOL_LOG_LEVEL=debug to get diagnostics on stderr.
|
|
1755
|
+
* NodeRuntime.runMain(
|
|
1756
|
+
* CliRuntime.main(program, {
|
|
1757
|
+
* platform: NodeServices.layer,
|
|
1758
|
+
* env: { audienceEnvVar: "MYTOOL_AUDIENCE", log: { envVar: "MYTOOL_LOG_LEVEL" } },
|
|
1759
|
+
* }),
|
|
1760
|
+
* )
|
|
1761
|
+
* ```
|
|
19
1762
|
*
|
|
20
1763
|
* @public
|
|
21
1764
|
*/
|
|
22
|
-
export declare class
|
|
1765
|
+
export declare class CliLog {
|
|
23
1766
|
private constructor();
|
|
24
1767
|
/**
|
|
25
|
-
* The
|
|
1768
|
+
* The diagnostics threshold. Defaults to `None`, silent.
|
|
26
1769
|
*
|
|
27
|
-
* @
|
|
1770
|
+
* @remarks
|
|
1771
|
+
* `CliLog.layer` sets it from the environment variable. A scope may raise it to narrow the output; it
|
|
1772
|
+
* cannot lower it below the level the layer installed, because Effect has already dropped those records.
|
|
28
1773
|
*/
|
|
29
|
-
static readonly
|
|
1774
|
+
static readonly Level: Context.Reference<LogLevel.LogLevel>;
|
|
30
1775
|
/**
|
|
31
|
-
*
|
|
32
|
-
* {@link CliColor.enabled}, so help text, parse errors and rendered
|
|
33
|
-
* output never disagree on whether colour is on.
|
|
1776
|
+
* The whole logger set of a program: a `CliLogger` for ordinary lines plus the diagnostics sink.
|
|
34
1777
|
*
|
|
35
1778
|
* @remarks
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* result to a `const` or the decision is re-read every time it is
|
|
40
|
-
* provided.
|
|
1779
|
+
* Replaces the installed loggers without reading them. Provide it on the program you pass to
|
|
1780
|
+
* `CliRuntime.main`, or use `main`'s `env.log` option; never wrap it around `main`, whose own logger would
|
|
1781
|
+
* replace this one. Bind it to a constant.
|
|
41
1782
|
*
|
|
42
|
-
* The `
|
|
43
|
-
* `
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* formatter it sets, and without it they fall back to core's default
|
|
47
|
-
* formatter.
|
|
1783
|
+
* The requirements follow the format. `format: "json"` reads neither the audience nor the terminal, so it
|
|
1784
|
+
* requires neither; `"pretty"` requires `TerminalEnv` alone, for the stderr colour; `"auto"` and an omitted
|
|
1785
|
+
* format require both. A long-lived host that never builds a platform `Terminal` can provide
|
|
1786
|
+
* `TerminalEnv.layerStdio()` for the pretty case.
|
|
48
1787
|
*
|
|
49
|
-
*
|
|
1788
|
+
* A platform or program that installs its own `Logger.layer([...])` replaces this set: do not. The diagnostics
|
|
1789
|
+
* then go silent with no error.
|
|
1790
|
+
*
|
|
1791
|
+
* The NDJSON line is core's `Logger.formatJson`, unchanged so it stays interoperable with Effect tooling: the
|
|
1792
|
+
* `message` field is a string for one log argument and an array for several.
|
|
1793
|
+
*
|
|
1794
|
+
* Level parsing is case-insensitive and accepts `warn`, `warning`, `error`, `info`, `debug`, `trace`,
|
|
1795
|
+
* `fatal`, `all` and `none`. An invalid value warns once, through the `CliLogger`, and leaves diagnostics
|
|
1796
|
+
* off.
|
|
1797
|
+
*
|
|
1798
|
+
* With a `file` option ({@link CliLogFileOptions}) the layer also writes an async NDJSON file, and only then
|
|
1799
|
+
* does it require `FileSystem` and `Path`, and it leaves them in `R` unprovided: the platform supplies them, or
|
|
1800
|
+
* a test supplies a memory filesystem, so a host never provides Node inside its own layer.
|
|
1801
|
+
*
|
|
1802
|
+
* Without a `CurrentRuntimeEnv` around the layer, `"auto"` does not neutralize: see {@link CliLogOptions.runtimeEnv}.
|
|
1803
|
+
*
|
|
1804
|
+
* @param options - the level, the env var, the format, the `CliLogger` options and the optional file sink
|
|
50
1805
|
*/
|
|
51
|
-
static
|
|
1806
|
+
static layer(options: CliLogOptions & {
|
|
1807
|
+
readonly format: "json";
|
|
1808
|
+
readonly file?: undefined;
|
|
1809
|
+
}): Layer.Layer<never, never, never>;
|
|
1810
|
+
/**
|
|
1811
|
+
* The logger set with NDJSON diagnostics and a file sink; see the first overload.
|
|
1812
|
+
*
|
|
1813
|
+
* @remarks
|
|
1814
|
+
* Without a `CurrentRuntimeEnv` around the layer, `"auto"` does not neutralize: see {@link CliLogOptions.runtimeEnv}.
|
|
1815
|
+
*
|
|
1816
|
+
* @param options - the level, the env var, the `CliLogger` options and the file sink
|
|
1817
|
+
*/
|
|
1818
|
+
static layer(options: CliLogFileOptions & {
|
|
1819
|
+
readonly format: "json";
|
|
1820
|
+
}): Layer.Layer<never, never, FileSystem.FileSystem | Path.Path>;
|
|
1821
|
+
/**
|
|
1822
|
+
* The logger set with pretty diagnostics; see the first overload.
|
|
1823
|
+
*
|
|
1824
|
+
* @remarks
|
|
1825
|
+
* Without a `CurrentRuntimeEnv` around the layer, `"auto"` does not neutralize: see {@link CliLogOptions.runtimeEnv}.
|
|
1826
|
+
*
|
|
1827
|
+
* @param options - the level, the env var and the `CliLogger` options
|
|
1828
|
+
*/
|
|
1829
|
+
static layer(options: CliLogOptions & {
|
|
1830
|
+
readonly format: "pretty";
|
|
1831
|
+
readonly file?: undefined;
|
|
1832
|
+
}): Layer.Layer<never, never, TerminalEnv>;
|
|
1833
|
+
/**
|
|
1834
|
+
* The logger set with pretty diagnostics and a file sink; see the first overload.
|
|
1835
|
+
*
|
|
1836
|
+
* @remarks
|
|
1837
|
+
* Without a `CurrentRuntimeEnv` around the layer, `"auto"` does not neutralize: see {@link CliLogOptions.runtimeEnv}.
|
|
1838
|
+
*
|
|
1839
|
+
* @param options - the level, the env var, the `CliLogger` options and the file sink
|
|
1840
|
+
*/
|
|
1841
|
+
static layer(options: CliLogFileOptions & {
|
|
1842
|
+
readonly format: "pretty";
|
|
1843
|
+
}): Layer.Layer<never, never, TerminalEnv | FileSystem.FileSystem | Path.Path>;
|
|
1844
|
+
/**
|
|
1845
|
+
* The logger set with the format decided by the audience; see the first overload.
|
|
1846
|
+
*
|
|
1847
|
+
* @remarks
|
|
1848
|
+
* Without a `CurrentRuntimeEnv` around the layer, `"auto"` does not neutralize: see {@link CliLogOptions.runtimeEnv}.
|
|
1849
|
+
*
|
|
1850
|
+
* @param options - the level, the env var, the format and the `CliLogger` options
|
|
1851
|
+
*/
|
|
1852
|
+
static layer(options?: CliLogOptions & {
|
|
1853
|
+
readonly file?: undefined;
|
|
1854
|
+
}): Layer.Layer<never, never, Audience | TerminalEnv>;
|
|
1855
|
+
/**
|
|
1856
|
+
* The logger set with the format decided by the audience, and a file sink; see the first overload.
|
|
1857
|
+
*
|
|
1858
|
+
* @remarks
|
|
1859
|
+
* Without a `CurrentRuntimeEnv` around the layer, `"auto"` does not neutralize: see {@link CliLogOptions.runtimeEnv}.
|
|
1860
|
+
*
|
|
1861
|
+
* @param options - the level, the env var, the format, the `CliLogger` options and the file sink
|
|
1862
|
+
*/
|
|
1863
|
+
static layer(options: CliLogFileOptions): Layer.Layer<never, never, Audience | TerminalEnv | FileSystem.FileSystem | Path.Path>;
|
|
1864
|
+
/**
|
|
1865
|
+
* Mark the log records an effect emits as coming from `name`.
|
|
1866
|
+
*
|
|
1867
|
+
* @remarks
|
|
1868
|
+
* Shown as `[name]` in pretty output and as `annotations.component` in NDJSON.
|
|
1869
|
+
*
|
|
1870
|
+
* @param name - the component
|
|
1871
|
+
*/
|
|
1872
|
+
static readonly component: (name: string) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
|
|
1873
|
+
}
|
|
1874
|
+
//#endregion
|
|
1875
|
+
//#region src/CliEnv.d.ts
|
|
1876
|
+
/**
|
|
1877
|
+
* Options for {@link CliEnv.layer} and for `CliRuntime.main`'s `env` option.
|
|
1878
|
+
*
|
|
1879
|
+
* @public
|
|
1880
|
+
*/
|
|
1881
|
+
interface CliEnvOptions {
|
|
1882
|
+
/** The environment variable that overrides the audience, read through `Config`; see `Audience.layer`. */
|
|
1883
|
+
readonly audienceEnvVar?: string | undefined;
|
|
1884
|
+
/**
|
|
1885
|
+
* Overrides the stderr terminal check; `Stdio` reports only stdout, so stderr mirrors it otherwise.
|
|
1886
|
+
*
|
|
1887
|
+
* @remarks
|
|
1888
|
+
* Mirroring means a program whose stdout is a terminal but whose stderr is redirected to a file still paints
|
|
1889
|
+
* stderr (a failure report, a warning) with colour escapes. A Node host that redirects stderr passes the real
|
|
1890
|
+
* answer: `env: { stderrIsTerminal: Effect.sync(() => process.stderr.isTTY === true) }`. Core's `Stdio` has no
|
|
1891
|
+
* stderr terminal check to read instead; that gap is tracked upstream as Effect-TS/effect#8639.
|
|
1892
|
+
*/
|
|
1893
|
+
readonly stderrIsTerminal?: Effect.Effect<boolean> | undefined;
|
|
1894
|
+
/** Options for the theme; see {@link CliThemeOptions}. */
|
|
1895
|
+
readonly theme?: CliThemeOptions | undefined;
|
|
1896
|
+
/**
|
|
1897
|
+
* Diagnostics options. Only `CliRuntime.main` reads this: when given, `main` uses `CliLog.layer` with these
|
|
1898
|
+
* options as the program's logger, instead of the default `CliLogger.layer()`. The platform is built under
|
|
1899
|
+
* that logger, so a line it logs while building goes to stderr.
|
|
1900
|
+
*
|
|
1901
|
+
* @remarks
|
|
1902
|
+
* It may carry the `file` option, which also writes an async NDJSON file. The platform must then provide
|
|
1903
|
+
* `FileSystem` and `Path`, and `main`'s type says so when it does not.
|
|
1904
|
+
*
|
|
1905
|
+
* A platform or program that installs its own `Logger.layer([...])` replaces this logger set, and the
|
|
1906
|
+
* diagnostics go silent with no error: do not install one. See `CliLog.layer`. Only `CliLog`'s own records can be
|
|
1907
|
+
* silenced (`plainLogger: false`): what the platform logs while it builds goes through the full `CliLog` when its
|
|
1908
|
+
* build-time format is NDJSON (`json`, or `auto` for an agent or a CI; see `CliLogOptions.format`) and through a plain
|
|
1909
|
+
* `CliLogger` otherwise, routed by `logger.stderrFrom` as the host set it. The audience-override warning is never silenced: it is written exactly once, in NDJSON when
|
|
1910
|
+
* the build-time format is NDJSON and as a plain line otherwise, to stderr alone (never stdout, whatever
|
|
1911
|
+
* `logger.stderrFrom` says) and never to the host's `extraLoggers` or log file. The failure report and the `CliMessage` lines always
|
|
1912
|
+
* go through a plain `CliLogger`.
|
|
1913
|
+
*/
|
|
1914
|
+
readonly log?: CliLogOptions | CliLogFileOptions | undefined;
|
|
1915
|
+
/**
|
|
1916
|
+
* Methods of core's `CliOutput.Formatter` to replace in the one `CliRuntime.main` installs, for example
|
|
1917
|
+
* `formatVersion` to name the carrier a bin runs through. Only `CliRuntime.main` reads this.
|
|
1918
|
+
*
|
|
1919
|
+
* @remarks
|
|
1920
|
+
* `main` installs a coloured default formatter inside the platform, which shadows any formatter the platform
|
|
1921
|
+
* sets; this is the way to keep a method of your own. Methods you omit keep the coloured defaults.
|
|
1922
|
+
*/
|
|
1923
|
+
readonly formatter?: Partial<CliOutput.Formatter> | undefined;
|
|
1924
|
+
/**
|
|
1925
|
+
* Turns an absolute path into its display form, for example relative to the workspace: the stack frames of the
|
|
1926
|
+
* default failure report are shown through it. Only `CliRuntime.main` reads this. The identity by default.
|
|
1927
|
+
*/
|
|
1928
|
+
readonly displayPath?: ((absolute: string) => string) | undefined;
|
|
1929
|
+
/**
|
|
1930
|
+
* Which frames of a defect's stack the default failure report shows: `app`, the default, leaves out every
|
|
1931
|
+
* `node_modules` frame (Effect's and any other dependency's) and the runtime's own (every `node:` frame and every
|
|
1932
|
+
* frame with no file), and prints how many it left out after the frames it shows, as
|
|
1933
|
+
* `(+N internal frames hidden)`, or `no user frames (N internal frames hidden)` when none is left; `all` shows
|
|
1934
|
+
* every frame. Applies to the report `main` writes, `FailureDetails.defaultLines` and `FailureDetails.lines`. Only
|
|
1935
|
+
* `CliRuntime.main` reads this.
|
|
1936
|
+
*/
|
|
1937
|
+
readonly stackFrames?: "app" | "all" | undefined;
|
|
1938
|
+
/** Whether file links open in an editor; `auto` by default. See {@link CliLinks}. */
|
|
1939
|
+
readonly editorLinks?: EditorLinks | undefined;
|
|
1940
|
+
/** The environment variable that overrides `editorLinks`, read through `Config`. Not read unless named. */
|
|
1941
|
+
readonly editorLinksEnvVar?: string | undefined;
|
|
1942
|
+
}
|
|
1943
|
+
/**
|
|
1944
|
+
* The services {@link CliEnv.layer} provides.
|
|
1945
|
+
*
|
|
1946
|
+
* @public
|
|
1947
|
+
*/
|
|
1948
|
+
type CliEnvServices = CurrentRuntimeEnv | TerminalEnv | Audience | CliTheme | CliLinks | Terminal.Terminal;
|
|
1949
|
+
/**
|
|
1950
|
+
* Options for {@link CliEnv.layerTest}: the answers a test fixes. Every field has a quiet default.
|
|
1951
|
+
*
|
|
1952
|
+
* @public
|
|
1953
|
+
*/
|
|
1954
|
+
interface CliEnvTestOptions {
|
|
1955
|
+
/** Whether standard input, output and error are all terminals; `false` by default, as for a pipe. */
|
|
1956
|
+
readonly tty?: boolean | undefined;
|
|
1957
|
+
/**
|
|
1958
|
+
* The `TERM` the layer's own builds read: `dumb` makes a terminal not interactive and, with the theme's glyphs at
|
|
1959
|
+
* `auto`, draws ASCII. Unset by default, whatever the host's `TERM` is.
|
|
1960
|
+
*/
|
|
1961
|
+
readonly term?: string | undefined;
|
|
1962
|
+
/** The audience; `human` by default. */
|
|
1963
|
+
readonly audience?: AudienceKind | undefined;
|
|
1964
|
+
/** The width of the terminal, in columns; none by default, so a width falls back to the reader's (80). */
|
|
1965
|
+
readonly columns?: number | undefined;
|
|
1966
|
+
/** The colour level of both stdout and stderr; `none` by default. Fixed as given: `term` does not change it. */
|
|
1967
|
+
readonly color?: ColorLevel | undefined;
|
|
1968
|
+
/** Options for the theme, as {@link CliEnvOptions.theme}; its glyphs are `auto` by default, so `term` decides. */
|
|
1969
|
+
readonly theme?: CliThemeOptions | undefined;
|
|
1970
|
+
}
|
|
1971
|
+
/**
|
|
1972
|
+
* The services {@link CliEnv.layerTest} provides.
|
|
1973
|
+
*
|
|
1974
|
+
* @public
|
|
1975
|
+
*/
|
|
1976
|
+
type CliEnvTestServices = TerminalEnv | Audience | CliTheme;
|
|
1977
|
+
/**
|
|
1978
|
+
* The environment services a CLI reads, built once and in the right order.
|
|
1979
|
+
*
|
|
1980
|
+
* @remarks
|
|
1981
|
+
* Builds `CurrentRuntimeEnv`, `TerminalEnv`, `Audience`, `CliTheme` and `CliLinks`, and sets `CliInteractive` from them, then
|
|
1982
|
+
* installs the two gates for the program: `CliPrompt.gateTerminal`, which replaces `Terminal` with a quiet one when
|
|
1983
|
+
* the run is not interactive so no prompt runner ever attaches to stdin, and `CliPrompt.gateWizard`, which drops
|
|
1984
|
+
* `--wizard` then. `TerminalEnv` is built from the real terminal first. The layer therefore also outputs
|
|
1985
|
+
* `Terminal`, the gated one, and consumers never compose the gates themselves. A
|
|
1986
|
+
* `Context.Reference`'s key type is `never`, so the layer's output type does not list `CliInteractive`: it sets
|
|
1987
|
+
* the reference rather than providing a service. Every read of the environment goes through `Config` and
|
|
1988
|
+
* degrades to "unset" when it fails, so building the layer does not fail on a bad provider; it fails only when
|
|
1989
|
+
* `Stdio` or `Terminal` do.
|
|
1990
|
+
*
|
|
1991
|
+
* `CliLinks` reads `FileSystem` and `Path` from the surrounding context if it has them, and does not require them: a
|
|
1992
|
+
* `.vscode/` directory is looked for, and a relative path resolved, only when the platform is provided OUTSIDE this
|
|
1993
|
+
* layer, as `CliRuntime.main` does. Without them `auto` is `vscode` on the terminal signal alone.
|
|
1994
|
+
*
|
|
1995
|
+
* Not interactive, the gated `Terminal`'s `readLine` fails as a quit, its input is already ended and its `display`
|
|
1996
|
+
* writes nothing. A program that reads piped data must read `Stdio.stdin`, and one that writes output must use
|
|
1997
|
+
* `Console` or `Stdio`, never `Terminal`. It also installs `CliTheme.promptTheme`, so core's prompts follow the
|
|
1998
|
+
* theme.
|
|
1999
|
+
*
|
|
2000
|
+
* @public
|
|
2001
|
+
*/
|
|
2002
|
+
export declare class CliEnv {
|
|
2003
|
+
private constructor();
|
|
2004
|
+
/**
|
|
2005
|
+
* The environment services for the terminal `Stdio` and `Terminal` describe.
|
|
2006
|
+
*
|
|
2007
|
+
* @remarks
|
|
2008
|
+
* A layer-returning function mints a fresh layer per call: call it once and bind the result to a constant.
|
|
2009
|
+
*
|
|
2010
|
+
* @param options - the audience env var, the stderr check and the theme options
|
|
2011
|
+
*/
|
|
2012
|
+
static readonly layer: (options?: CliEnvOptions) => Layer.Layer<CliEnvServices, never, Stdio.Stdio | Terminal.Terminal>;
|
|
2013
|
+
/**
|
|
2014
|
+
* The environment services a test fixes, needing nothing and reading nothing of the host's: `TerminalEnv` and
|
|
2015
|
+
* `Audience` from the answers given, `CliTheme` built from them as {@link CliEnv.layer} builds it, and
|
|
2016
|
+
* `CliInteractive` set from them by the same rule (a human, every stream a terminal, and a `TERM` that is not
|
|
2017
|
+
* `dumb`).
|
|
2018
|
+
*
|
|
2019
|
+
* @remarks
|
|
2020
|
+
* `term` is handed to the theme and interactivity builds alone, through a `ConfigProvider` of their own: the
|
|
2021
|
+
* program under the layer keeps its own provider, and a host's `TERM` (a test runner in a dumb terminal) never
|
|
2022
|
+
* decides. A screen or a live view also needs `UiStreams` from `@effected/cli/ui`, which `CliUiTest` provides; this
|
|
2023
|
+
* layer provides no `Terminal` and installs neither of `CliEnv.layer`'s prompt gates.
|
|
2024
|
+
*
|
|
2025
|
+
* A layer-returning function mints a fresh layer per call: call it once and bind the result to a constant.
|
|
2026
|
+
*
|
|
2027
|
+
* @param options - whether the streams are terminals, the `TERM`, the audience, the width, the colour and the theme
|
|
2028
|
+
*/
|
|
2029
|
+
static readonly layerTest: (options?: CliEnvTestOptions) => Layer.Layer<CliEnvTestServices>;
|
|
52
2030
|
}
|
|
53
2031
|
//#endregion
|
|
54
2032
|
//#region src/CliExit.d.ts
|
|
@@ -71,7 +2049,7 @@ declare const CliExit_base: Context.ServiceClass<CliExit, "@effected/cli/CliExit
|
|
|
71
2049
|
* handler must return normally — yet the process must exit non-zero. Writing
|
|
72
2050
|
* `process.exitCode` works only because Node's `runMain` skips
|
|
73
2051
|
* `process.exit(0)` on success; `process.exit(n)` in a handler skips every
|
|
74
|
-
* finalizer.
|
|
2052
|
+
* finalizer. `CliRuntime.main` reads this cell after the program
|
|
75
2053
|
* succeeds and turns a non-zero code into a marked failure the runtime's
|
|
76
2054
|
* teardown honours, on any runtime, with finalizers intact.
|
|
77
2055
|
*
|
|
@@ -117,109 +2095,301 @@ export declare class CliExit extends CliExit_base {
|
|
|
117
2095
|
static readonly set: (code: number) => Effect.Effect<void, never, CliExit>;
|
|
118
2096
|
}
|
|
119
2097
|
//#endregion
|
|
120
|
-
//#region src/
|
|
2098
|
+
//#region src/CliFailure.d.ts
|
|
121
2099
|
/**
|
|
122
|
-
*
|
|
2100
|
+
* The protocol an error class implements to say how a failure is shown: a method under this key that returns the
|
|
2101
|
+
* document.
|
|
2102
|
+
*
|
|
2103
|
+
* @remarks
|
|
2104
|
+
* `CliFailure.toDoc` calls it for a typed failure that has one, so an application error draws itself (a heading, a
|
|
2105
|
+
* table of what went wrong) and the default report uses it with no registration. A `Symbol.for` key, so two copies
|
|
2106
|
+
* of this package agree on it.
|
|
123
2107
|
*
|
|
124
2108
|
* @public
|
|
125
2109
|
*/
|
|
126
|
-
|
|
2110
|
+
export declare const CliDoc: unique symbol;
|
|
2111
|
+
/**
|
|
2112
|
+
* An error that draws itself: see {@link CliDoc}.
|
|
2113
|
+
*
|
|
2114
|
+
* @public
|
|
2115
|
+
*/
|
|
2116
|
+
interface CliDocSource {
|
|
2117
|
+
readonly [CliDoc]: () => Document;
|
|
2118
|
+
}
|
|
2119
|
+
/**
|
|
2120
|
+
* Options for {@link CliFailure.toDoc}.
|
|
2121
|
+
*
|
|
2122
|
+
* @public
|
|
2123
|
+
*/
|
|
2124
|
+
interface CliFailureOptions {
|
|
127
2125
|
/**
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
* @remarks
|
|
132
|
-
* An array arrives because `Effect.log("synced", 3, "repos")` is variadic.
|
|
2126
|
+
* A document per error `_tag`, for errors that do not implement {@link CliDoc}. A tag with no entry is shown by
|
|
2127
|
+
* the default rules.
|
|
133
2128
|
*/
|
|
134
|
-
readonly render?: (
|
|
2129
|
+
readonly render?: Readonly<Record<string, (error: unknown) => Document>> | undefined;
|
|
2130
|
+
/** Turns an absolute path into its display form, for the stack frames; the identity by default. */
|
|
2131
|
+
readonly displayPath?: ((absolute: string) => string) | undefined;
|
|
135
2132
|
/**
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
* program
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
* Pass `"Error"` to restore the old split, for a tool whose output *is*
|
|
142
|
-
* its log lines rather than a separate document written with
|
|
143
|
-
* `Console.log`.
|
|
2133
|
+
* Which frames of a defect's stack are shown. `app`, the default, shows the program's own: every `node_modules`
|
|
2134
|
+
* frame (Effect's and any other dependency's), `node:internal` and the runtime's generator frames are left out and
|
|
2135
|
+
* counted. When that leaves no frame, as for a program run from its install under `node_modules` (a global
|
|
2136
|
+
* install, `npx`, a pnpm store), only the runtime's and Effect's are left out, so its own frames still show. `all`
|
|
2137
|
+
* shows every frame, unfiltered.
|
|
144
2138
|
*/
|
|
145
|
-
readonly
|
|
2139
|
+
readonly stackFrames?: "app" | "all" | undefined;
|
|
146
2140
|
}
|
|
147
2141
|
/**
|
|
148
|
-
* A
|
|
2142
|
+
* A failure as a document: what the default report prints, and a building block for a custom one.
|
|
149
2143
|
*
|
|
150
2144
|
* @remarks
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
2145
|
+
* One run of blocks per `Cause` reason. A typed failure is, in order of preference: the document of an error that
|
|
2146
|
+
* implements {@link CliDoc}; the document `options.render` holds for its `_tag`; for `Cancelled` and
|
|
2147
|
+
* `NotInteractive`, their one fixed line; a `Tree` of the rejected values, for a schema error or issue; else a failure
|
|
2148
|
+
* status line with its message. A defect is its message followed by a collapsible `stack` of the program's own frames,
|
|
2149
|
+
* each a file link (so a terminal can open it in an editor) shown through `displayPath`, with the runtime's frames (every
|
|
2150
|
+
* `node:` frame and every frame with no file) and every `node_modules` frame (Effect's and any other dependency's)
|
|
2151
|
+
* left out unless `stackFrames` is `all`. A frame is classified by its file alone, never by its function name, so a
|
|
2152
|
+
* program's own thunk that V8 names by Effect's method alias is still shown. When that would
|
|
2153
|
+
* leave no frame at all, as for a program run from its own install under `node_modules`, only the runtime's and
|
|
2154
|
+
* Effect's are left out. Then an
|
|
2155
|
+
* `Error.cause` chain as a tree. When cleaning leaves no frame the stack says
|
|
2156
|
+
* `no user frames (N internal frames hidden)`, never an empty block; when frames survive and some were left out, the
|
|
2157
|
+
* count follows them as `(+N internal frames hidden)`. A reason that ran under spans is followed by
|
|
2158
|
+
* `in: outer › inner`. Interrupts are not rendered beside a real failure, and a cause with only interrupts is the
|
|
2159
|
+
* one line `interrupted`.
|
|
2160
|
+
*
|
|
2161
|
+
* All text goes through the document, so a control character in a message or a stack frame never reaches the terminal.
|
|
2162
|
+
* Render it with `Render.context` and `Render.plain`, `ansi`, `markdown` or `githubLog`, or `Doc.print` it.
|
|
156
2163
|
*
|
|
157
|
-
*
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
2164
|
+
* @public
|
|
2165
|
+
*/
|
|
2166
|
+
export declare class CliFailure {
|
|
2167
|
+
private constructor();
|
|
2168
|
+
/**
|
|
2169
|
+
* Build the document of a cause.
|
|
2170
|
+
*
|
|
2171
|
+
* @param cause - the failure
|
|
2172
|
+
* @param options - per-tag documents and a path display function
|
|
2173
|
+
*/
|
|
2174
|
+
static readonly toDoc: (cause: Cause.Cause<unknown>, options?: CliFailureOptions) => Document;
|
|
2175
|
+
}
|
|
2176
|
+
//#endregion
|
|
2177
|
+
//#region src/CliInteractive.d.ts
|
|
2178
|
+
declare const CliInteractive_base: Context.Reference<boolean>;
|
|
2179
|
+
/**
|
|
2180
|
+
* Whether this run may prompt a person: a human audience, with a terminal on
|
|
2181
|
+
* both standard input and standard output, and a `TERM` that is not `dumb`.
|
|
161
2182
|
*
|
|
162
|
-
*
|
|
2183
|
+
* @remarks
|
|
2184
|
+
* A `Context.Reference`, not a `Context.Service`, for three reasons. It is one
|
|
2185
|
+
* boolean with a safe default, which is what a reference is for. A scoped
|
|
2186
|
+
* override, {@link CliInteractive.unless}, is a plain
|
|
2187
|
+
* `Effect.provideService`, so a command can switch prompting off for one
|
|
2188
|
+
* subtree without a layer. And forgetting to provide it is not a type error
|
|
2189
|
+
* but a harmless answer, since it reads `false` when no layer is provided: a
|
|
2190
|
+
* program that never wired it refuses to prompt rather than hanging on a
|
|
2191
|
+
* terminal that is not there. Read it with `yield* CliInteractive`.
|
|
163
2192
|
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
2193
|
+
* Because a reference's key type is `never`, {@link CliInteractive.layer} and
|
|
2194
|
+
* {@link CliInteractive.layerTest} are typed `Layer<never>`: they set the
|
|
2195
|
+
* reference rather than provide a service.
|
|
167
2196
|
*
|
|
168
|
-
*
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
2197
|
+
* @public
|
|
2198
|
+
*/
|
|
2199
|
+
export declare class CliInteractive extends CliInteractive_base {
|
|
2200
|
+
/**
|
|
2201
|
+
* Decide from the audience and the terminal: `true` only for a human audience with a terminal on both
|
|
2202
|
+
* standard input and standard output, and a `TERM` that is not `dumb`.
|
|
2203
|
+
*
|
|
2204
|
+
* @remarks
|
|
2205
|
+
* A dumb terminal is a terminal, but it cannot move the cursor or take synchronized output, which a prompt or a
|
|
2206
|
+
* screen redrawing in place needs: it gets what a pipe gets. `TERM` is read through the ambient `ConfigProvider`,
|
|
2207
|
+
* as `@effected/env` reads the environment, so it adds no requirement; a test fixes it with
|
|
2208
|
+
* `Effect.provideService(ConfigProvider.ConfigProvider, ConfigProvider.fromUnknown({ TERM: "dumb" }))`.
|
|
2209
|
+
*
|
|
2210
|
+
* Bind the layer to a constant and provide it once; `Audience` and `TerminalEnv` come from `@effected/env`.
|
|
2211
|
+
*/
|
|
2212
|
+
static readonly layer: Layer.Layer<never, never, Audience | TerminalEnv>;
|
|
2213
|
+
/**
|
|
2214
|
+
* A fixed answer that needs nothing.
|
|
2215
|
+
*
|
|
2216
|
+
* @param value - whether the run is interactive
|
|
2217
|
+
*/
|
|
2218
|
+
static readonly layerTest: (value: boolean) => Layer.Layer<never>;
|
|
2219
|
+
/**
|
|
2220
|
+
* Run `self` with interactivity switched off when `condition` holds.
|
|
2221
|
+
*
|
|
2222
|
+
* @remarks
|
|
2223
|
+
* It only narrows: `unless(false)` leaves the current value alone and never turns interactivity on, so a
|
|
2224
|
+
* non-interactive scope stays non-interactive. The outer value is restored when `self` ends, whether it
|
|
2225
|
+
* succeeds, fails or is interrupted.
|
|
2226
|
+
*
|
|
2227
|
+
* A flag that resolves the audience (`--human`, under `CliAudience.runWith` or `provide`) recomputes interactivity
|
|
2228
|
+
* from the terminal facts, so it can override an outer `unless` or a `layerTest(false)`: those narrow the
|
|
2229
|
+
* environment's answer, and the flag is a later, explicit one.
|
|
2230
|
+
*
|
|
2231
|
+
* @param condition - `true` to switch prompting off for `self`
|
|
2232
|
+
*/
|
|
2233
|
+
static readonly unless: (condition: boolean) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
|
|
2234
|
+
}
|
|
2235
|
+
//#endregion
|
|
2236
|
+
//#region src/CliMessage.d.ts
|
|
2237
|
+
/**
|
|
2238
|
+
* Options for {@link CliMessage.status}.
|
|
173
2239
|
*
|
|
174
|
-
*
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
2240
|
+
* @public
|
|
2241
|
+
*/
|
|
2242
|
+
interface CliMessageOptions {
|
|
2243
|
+
/**
|
|
2244
|
+
* Where the line goes. Defaults to stderr for a status whose rank is at or above `warning`'s in its
|
|
2245
|
+
* vocabulary, stdout otherwise.
|
|
2246
|
+
*/
|
|
2247
|
+
readonly stream?: "stdout" | "stderr" | undefined;
|
|
2248
|
+
}
|
|
2249
|
+
/**
|
|
2250
|
+
* One-line status messages: a glyph and some text, themed for a person and plain for an agent.
|
|
178
2251
|
*
|
|
179
|
-
* @
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
2252
|
+
* @remarks
|
|
2253
|
+
* Each line goes through `Console`, `log` for stdout and `error` for stderr, never through the logger, so no
|
|
2254
|
+
* log level can silence it. Only the glyph is painted; the text stays plain. An `agent` audience gets the glyph
|
|
2255
|
+
* and the text and never colour, even when the theme has colour. `success` and `info` go to stdout, `warning`
|
|
2256
|
+
* and `failure` to stderr.
|
|
183
2257
|
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
* })
|
|
2258
|
+
* The text is whatever the caller supplies, so it is sanitised: escape sequences and control characters are removed
|
|
2259
|
+
* (a line break is kept as one, a tab becomes a space), as in a document. Under GitHub Actions, where
|
|
2260
|
+
* `CurrentRuntimeEnv` says so, a line the runner would read as a workflow command is neutralized as well. The glyphs
|
|
2261
|
+
* come from the vocabulary, which is configuration, and are not.
|
|
189
2262
|
*
|
|
190
|
-
*
|
|
191
|
-
|
|
2263
|
+
* @public
|
|
2264
|
+
*/
|
|
2265
|
+
export declare class CliMessage {
|
|
2266
|
+
private constructor();
|
|
2267
|
+
/**
|
|
2268
|
+
* Print a status line from a vocabulary.
|
|
2269
|
+
*
|
|
2270
|
+
* @remarks
|
|
2271
|
+
* The stream defaults to stderr when the status ranks at or above `warning` in `vocab`, and stdout
|
|
2272
|
+
* otherwise, so a custom status follows its own rank: a `timeout` ranked 85 goes to stderr.
|
|
2273
|
+
*
|
|
2274
|
+
* @param vocab - the vocabulary the status belongs to
|
|
2275
|
+
* @param name - the status
|
|
2276
|
+
* @param text - the text after the glyph
|
|
2277
|
+
* @param options - the stream override
|
|
2278
|
+
*/
|
|
2279
|
+
static readonly status: <N extends string>(vocab: Status<N>, name: N, text: string, options?: CliMessageOptions) => Effect.Effect<void, never, CliTheme | Audience>;
|
|
2280
|
+
/**
|
|
2281
|
+
* A success line, on stdout.
|
|
2282
|
+
*
|
|
2283
|
+
* @param text - the text after the glyph
|
|
2284
|
+
*/
|
|
2285
|
+
static readonly success: (text: string) => Effect.Effect<void, never, CliTheme | Audience>;
|
|
2286
|
+
/**
|
|
2287
|
+
* An informational line, on stdout.
|
|
2288
|
+
*
|
|
2289
|
+
* @param text - the text after the glyph
|
|
2290
|
+
*/
|
|
2291
|
+
static readonly info: (text: string) => Effect.Effect<void, never, CliTheme | Audience>;
|
|
2292
|
+
/**
|
|
2293
|
+
* A warning line, on stderr.
|
|
2294
|
+
*
|
|
2295
|
+
* @param text - the text after the glyph
|
|
2296
|
+
*/
|
|
2297
|
+
static readonly warning: (text: string) => Effect.Effect<void, never, CliTheme | Audience>;
|
|
2298
|
+
/**
|
|
2299
|
+
* A failure line, on stderr.
|
|
2300
|
+
*
|
|
2301
|
+
* @param text - the text after the glyph
|
|
2302
|
+
*/
|
|
2303
|
+
static readonly failure: (text: string) => Effect.Effect<void, never, CliTheme | Audience>;
|
|
2304
|
+
}
|
|
2305
|
+
//#endregion
|
|
2306
|
+
//#region src/CliPrompt.d.ts
|
|
2307
|
+
/**
|
|
2308
|
+
* Which missing parameter a fallback stands in for, so a non-interactive run can fail with core's own error.
|
|
192
2309
|
*
|
|
193
|
-
* @
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
2310
|
+
* @public
|
|
2311
|
+
*/
|
|
2312
|
+
type CliPromptTarget = {
|
|
2313
|
+
readonly flag: string;
|
|
2314
|
+
} | {
|
|
2315
|
+
readonly argument: string;
|
|
2316
|
+
};
|
|
2317
|
+
/**
|
|
2318
|
+
* Options for {@link CliPrompt.fallback}.
|
|
199
2319
|
*
|
|
200
2320
|
* @public
|
|
201
2321
|
*/
|
|
202
|
-
|
|
2322
|
+
type CliPromptFallbackOptions<A> = CliPromptTarget & {
|
|
2323
|
+
/** The value to use when the run is not interactive. Without it a non-interactive run fails as missing. */
|
|
2324
|
+
readonly otherwise?: A;
|
|
2325
|
+
};
|
|
2326
|
+
/**
|
|
2327
|
+
* Prompts that know whether there is a person to ask.
|
|
2328
|
+
*
|
|
2329
|
+
* @public
|
|
2330
|
+
*/
|
|
2331
|
+
export declare class CliPrompt {
|
|
203
2332
|
private constructor();
|
|
204
2333
|
/**
|
|
205
|
-
*
|
|
2334
|
+
* A fallback for `Flag.withFallbackPrompt` or `Argument.withFallbackPrompt` that only prompts when the run is
|
|
2335
|
+
* interactive.
|
|
206
2336
|
*
|
|
207
2337
|
* @remarks
|
|
208
|
-
*
|
|
209
|
-
* the
|
|
2338
|
+
* Interactive (`CliInteractive`): the prompt runs and its answer is used. Not interactive: `otherwise` is used
|
|
2339
|
+
* when given, and the terminal is never read; without it the parameter fails as missing, exactly as it would
|
|
2340
|
+
* with no fallback, so core renders its own message and `CliRuntime.main` exits `64`. Name the parameter with
|
|
2341
|
+
* `flag` (the name without dashes, as given to `Flag.String`) or `argument` so that error can be built.
|
|
2342
|
+
*
|
|
2343
|
+
* Why the prompt runs inside this function rather than being handed back to core: core's
|
|
2344
|
+
* `withFallbackPrompt` turns a quit, such as Ctrl-C, into the original missing-parameter error, which would
|
|
2345
|
+
* exit `64` as if the flag had been forgotten. Here a quit is `Cancelled` with reason `interrupt`, exit `130`.
|
|
2346
|
+
* It is raised as a defect because core's parse step turns every typed failure into a usage error. Core then
|
|
2347
|
+
* runs the already-answered `Prompt.succeed` it is handed. Because it travels as a defect, a handler's
|
|
2348
|
+
* `Effect.catchTag("Cancelled", ...)` cannot see it, and only `CliRuntime.main` (or
|
|
2349
|
+
* `CliRuntime.reportFailures`) renders it as one line with exit `130`; under a bare `runMain` it prints a
|
|
2350
|
+
* stack.
|
|
2351
|
+
*
|
|
2352
|
+
* Pair it with `CliPrompt.gateTerminal`, which `CliEnv.layer` installs: core still runs `Prompt.run` on the
|
|
2353
|
+
* answered prompt it is handed, and `Prompt.run` subscribes the terminal's input, which on a real terminal
|
|
2354
|
+
* attaches a reader to stdin and drops piped input. The gate makes that subscription harmless when the run is
|
|
2355
|
+
* not interactive.
|
|
2356
|
+
*
|
|
2357
|
+
* @param prompt - the prompt to show
|
|
2358
|
+
* @param options - the parameter it stands in for, and the non-interactive default
|
|
210
2359
|
*/
|
|
211
|
-
static readonly
|
|
2360
|
+
static readonly fallback: <A>(prompt: Prompt.Prompt<A>, options: CliPromptFallbackOptions<A>) => Param.FallbackPrompt<A>;
|
|
212
2361
|
/**
|
|
213
|
-
*
|
|
2362
|
+
* Gates core's `Terminal` on `CliInteractive`, so a run that is not interactive never touches the real one.
|
|
214
2363
|
*
|
|
215
2364
|
* @remarks
|
|
216
|
-
*
|
|
2365
|
+
* Core's prompt runner subscribes the terminal's input even for a prompt that is already answered, and the
|
|
2366
|
+
* real Node terminal then attaches a readline to stdin, which drops piped input and puts a TTY stdin into raw
|
|
2367
|
+
* mode. Not interactive, this terminal's input is an already-ended queue, its `readLine` fails as quit and its
|
|
2368
|
+
* `display` writes nothing, so any prompt, the wizard included, is quit at once and the real terminal is never
|
|
2369
|
+
* read. Its `columns` and `rows` always come from the real one, so layout keeps working. Interactive, every
|
|
2370
|
+
* call passes through to the real terminal.
|
|
217
2371
|
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
2372
|
+
* The decision is made on every call, not when the layer is built, so a scope that narrows `CliInteractive`
|
|
2373
|
+
* later, such as an audience flag under `CliAudience.runWith`, gates it too.
|
|
2374
|
+
*
|
|
2375
|
+
* It requires the real `Terminal`. `CliEnv.layer` installs it, after `TerminalEnv` is built from the real
|
|
2376
|
+
* terminal, so consumers do not compose it.
|
|
221
2377
|
*/
|
|
222
|
-
static readonly
|
|
2378
|
+
static readonly gateTerminal: Layer.Layer<Terminal.Terminal, never, Terminal.Terminal>;
|
|
2379
|
+
/**
|
|
2380
|
+
* Drops core's `--wizard` built-in flag when the run is not interactive.
|
|
2381
|
+
*
|
|
2382
|
+
* @remarks
|
|
2383
|
+
* The wizard prompts, so offering it without a terminal only leads to a dead end. With the flag gone, core
|
|
2384
|
+
* treats `--wizard` as an unknown flag, a usage error that exits `64`, and lists it nowhere in `--help`.
|
|
2385
|
+
* The layer reads `CliInteractive` and the ambient `CliConfig` when it is built, so provide those first, for
|
|
2386
|
+
* example `CliPrompt.gateWizard.pipe(Layer.provide(CliInteractive.layer))`. It filters the ambient `CliConfig`,
|
|
2387
|
+
* so a consumer's own `builtIns` survive, and returns it untouched when interactive. An audience flag read
|
|
2388
|
+
* later is covered by `CliAudience.runWith`, which drops the wizard too. When this layer removes the flag it records
|
|
2389
|
+
* that it did, so `runWith` puts it back only when a flag turns interactivity on where this took it away: a
|
|
2390
|
+
* consumer who never had `Wizard` in their `builtIns` keeps it out.
|
|
2391
|
+
*/
|
|
2392
|
+
static readonly gateWizard: Layer.Layer<never>;
|
|
223
2393
|
}
|
|
224
2394
|
//#endregion
|
|
225
2395
|
//#region src/CliRuntime.d.ts
|
|
@@ -237,6 +2407,33 @@ interface FailureDetails {
|
|
|
237
2407
|
* failure from the error channel.
|
|
238
2408
|
*/
|
|
239
2409
|
readonly isDefect: boolean;
|
|
2410
|
+
/**
|
|
2411
|
+
* The report the kit writes for this failure when there is no `render`: for this run, in this audience, with its
|
|
2412
|
+
* colour, links and `displayPath`. A `render` that hands a failure back returns these lines unchanged, and the
|
|
2413
|
+
* output is then exactly the default report. It equals `lines()`; to drop the leading status and keep the run's
|
|
2414
|
+
* settings, use {@link FailureDetails.lines} with `status: false`.
|
|
2415
|
+
*/
|
|
2416
|
+
readonly defaultLines: ReadonlyArray<string>;
|
|
2417
|
+
/**
|
|
2418
|
+
* The report the kit would write for this failure, rendered for this run: its audience, colour, links and
|
|
2419
|
+
* `displayPath`.
|
|
2420
|
+
*
|
|
2421
|
+
* @remarks
|
|
2422
|
+
* `lines()` is {@link FailureDetails.defaultLines}. With `status: false` the leading status glyph, or the `[FAIL]`
|
|
2423
|
+
* tag in plain text, is left off, so a render that puts its own prefix in front (the program's name, say) reads
|
|
2424
|
+
* cleanly and still gets the run's colour and paths. `CliRuntime.defaultRender` with `status: false` drops the
|
|
2425
|
+
* status too, but it has no run to read and renders plain with absolute paths.
|
|
2426
|
+
*
|
|
2427
|
+
* ```ts
|
|
2428
|
+
* const render = (_error: unknown, details: FailureDetails) =>
|
|
2429
|
+
* details.lines({ status: false }).map((line, i) => (i === 0 ? `prog: ${line}` : line))
|
|
2430
|
+
* ```
|
|
2431
|
+
*
|
|
2432
|
+
* @param options - `status: false` leaves off the leading status
|
|
2433
|
+
*/
|
|
2434
|
+
readonly lines: (options?: {
|
|
2435
|
+
readonly status?: boolean | undefined;
|
|
2436
|
+
}) => ReadonlyArray<string>;
|
|
240
2437
|
}
|
|
241
2438
|
/**
|
|
242
2439
|
* How a failure is turned into output and an exit code.
|
|
@@ -245,7 +2442,10 @@ interface FailureDetails {
|
|
|
245
2442
|
*/
|
|
246
2443
|
interface ReportFailuresOptions {
|
|
247
2444
|
/**
|
|
248
|
-
* Render the failure. Defaults to `
|
|
2445
|
+
* Render the failure. Defaults to the failure's document, `CliFailure.toDoc(cause)`, rendered for the
|
|
2446
|
+
* audience: a failure status line, a tree for a schema failure, a defect's message with its cleaned stack, and
|
|
2447
|
+
* the one fixed line each for `Cancelled` and `NotInteractive`. Under `CliRuntime.main` with `env` it is painted for
|
|
2448
|
+
* a person and plain for an agent or a CI; elsewhere it is plain. It is still written through the logger.
|
|
249
2449
|
*
|
|
250
2450
|
* @remarks
|
|
251
2451
|
* Return several lines to print several: a config error's own message
|
|
@@ -256,6 +2456,12 @@ interface ReportFailuresOptions {
|
|
|
256
2456
|
* failure can render as one line and a defect as a full report, without
|
|
257
2457
|
* guessing from the error's shape. A renderer that takes only `error`
|
|
258
2458
|
* still fits.
|
|
2459
|
+
*
|
|
2460
|
+
* What it returns is text the kit did not build, so the report applies the output policy to it: under GitHub
|
|
2461
|
+
* Actions a line the runner would read as a workflow command is neutralized (with no environment services at all,
|
|
2462
|
+
* always), and for an agent or a CI audience escape sequences are removed (GitHub Actions detects as `ci`). For a person the escapes you return are kept,
|
|
2463
|
+
* since the kit cannot tell your own colour from an injected sequence: a `render` must sanitise the data it
|
|
2464
|
+
* interpolates (an error message, a file name) itself.
|
|
259
2465
|
*/
|
|
260
2466
|
readonly render?: ((error: unknown, details: FailureDetails) => string | ReadonlyArray<string>) | undefined;
|
|
261
2467
|
/**
|
|
@@ -285,7 +2491,7 @@ interface ReportFailuresOptions {
|
|
|
285
2491
|
readonly usageExitCode?: number | undefined;
|
|
286
2492
|
}
|
|
287
2493
|
/**
|
|
288
|
-
* Options for
|
|
2494
|
+
* Options for `CliRuntime.main`.
|
|
289
2495
|
*
|
|
290
2496
|
* @public
|
|
291
2497
|
*/
|
|
@@ -295,8 +2501,32 @@ interface MainOptions<RP, EP> extends ReportFailuresOptions {
|
|
|
295
2501
|
* on it. Passed in so this package never imports a platform.
|
|
296
2502
|
*/
|
|
297
2503
|
readonly platform: Layer.Layer<RP, EP>;
|
|
298
|
-
/**
|
|
2504
|
+
/**
|
|
2505
|
+
* The logger, provided outermost. Defaults to `CliLogger.layer()`, or to `CliLog.layer(env.log)` when
|
|
2506
|
+
* `env.log` is given. An explicit `logger` wins over both.
|
|
2507
|
+
*/
|
|
299
2508
|
readonly logger?: Layer.Layer<never> | undefined;
|
|
2509
|
+
/**
|
|
2510
|
+
* Provide the environment services, built by {@link CliEnv.layer}, inside failure reporting, where the platform
|
|
2511
|
+
* sits, together with `CliColor.formatterLayer` so help text follows the same colour decision.
|
|
2512
|
+
*
|
|
2513
|
+
* @remarks
|
|
2514
|
+
* The program may then require `CurrentRuntimeEnv`, `TerminalEnv`, `Audience` and `CliTheme` and read
|
|
2515
|
+
* `CliInteractive`. Without it `CliInteractive` keeps its non-interactive default, so forgetting this wiring
|
|
2516
|
+
* gives a CLI that never prompts. With `env.log`, `main` uses `CliLog.layer` as the logger set, and `env.log`
|
|
2517
|
+
* may carry the `file` option when the platform provides `FileSystem` and `Path`. A failure building the env
|
|
2518
|
+
* layer renders as one line and exits through `exitCode`.
|
|
2519
|
+
*
|
|
2520
|
+
* Not interactive, the `Terminal` the program sees is gated: its `readLine` fails as a quit, its input is
|
|
2521
|
+
* already ended and its `display` writes nothing. A program that reads piped data must read `Stdio.stdin`, and
|
|
2522
|
+
* one that writes output must use `Console` or `Stdio`, never `Terminal`.
|
|
2523
|
+
*
|
|
2524
|
+
* Stderr's colour mirrors stdout's terminal check unless `env.stderrIsTerminal` says otherwise, so with stderr
|
|
2525
|
+
* redirected and stdout a terminal the failure report is painted into the file. On Node, pass the real check:
|
|
2526
|
+
* `env: { stderrIsTerminal: Effect.sync(() => process.stderr.isTTY === true) }` (core's `Stdio` reports only
|
|
2527
|
+
* stdout; upstream Effect-TS/effect#8639).
|
|
2528
|
+
*/
|
|
2529
|
+
readonly env?: CliEnvOptions | undefined;
|
|
300
2530
|
/**
|
|
301
2531
|
* Where the help document goes when it is printed with a usage error:
|
|
302
2532
|
* `"stdout"` (the default, core's behaviour) or `"stderr"`, beside the
|
|
@@ -321,7 +2551,7 @@ interface MainOptions<RP, EP> extends ReportFailuresOptions {
|
|
|
321
2551
|
* Report a CLI program's failures through the program's own logger.
|
|
322
2552
|
*
|
|
323
2553
|
* @remarks
|
|
324
|
-
* ##
|
|
2554
|
+
* ## What it prevents
|
|
325
2555
|
*
|
|
326
2556
|
* A platform `runMain` reports an unhandled failure using Effect's **default**
|
|
327
2557
|
* logger. That logger sits **outside** the layers the program was provided —
|
|
@@ -338,18 +2568,7 @@ interface MainOptions<RP, EP> extends ReportFailuresOptions {
|
|
|
338
2568
|
*
|
|
339
2569
|
* The fix has to happen **inside** the effect, before any `runMain` sees it. So
|
|
340
2570
|
* this is a combinator you apply to your program, and you still call your own
|
|
341
|
-
* platform's runner
|
|
342
|
-
*
|
|
343
|
-
* @example
|
|
344
|
-
* ```ts
|
|
345
|
-
* import { CliRuntime } from "@effected/cli"
|
|
346
|
-
* import { NodeRuntime } from "@effect/platform-node"
|
|
347
|
-
* import { Effect } from "effect"
|
|
348
|
-
*
|
|
349
|
-
* NodeRuntime.runMain(program.pipe(CliRuntime.reportFailures(), Effect.provide(MainLive)))
|
|
350
|
-
* ```
|
|
351
|
-
*
|
|
352
|
-
* Wrapping `runMain` itself would drag a platform choice into a library that
|
|
2571
|
+
* platform's runner. Wrapping `runMain` itself would drag a platform choice into a library that
|
|
353
2572
|
* has no business making one, and would make this package unusable from Bun or
|
|
354
2573
|
* Deno for no gain.
|
|
355
2574
|
*
|
|
@@ -392,13 +2611,51 @@ interface MainOptions<RP, EP> extends ReportFailuresOptions {
|
|
|
392
2611
|
* raises is likewise never rendered; it only carries the exit code a
|
|
393
2612
|
* successful program recorded through `CliExit`.
|
|
394
2613
|
*
|
|
2614
|
+
* @example
|
|
2615
|
+
* ```ts
|
|
2616
|
+
* import { CliRuntime } from "@effected/cli"
|
|
2617
|
+
* import { NodeRuntime } from "@effect/platform-node"
|
|
2618
|
+
* import { Effect } from "effect"
|
|
2619
|
+
*
|
|
2620
|
+
* NodeRuntime.runMain(program.pipe(CliRuntime.reportFailures(), Effect.provide(MainLive)))
|
|
2621
|
+
* ```
|
|
2622
|
+
*
|
|
395
2623
|
* @public
|
|
396
2624
|
*/
|
|
397
2625
|
export declare class CliRuntime {
|
|
398
2626
|
private constructor();
|
|
399
2627
|
/**
|
|
400
|
-
*
|
|
401
|
-
*
|
|
2628
|
+
* What `reportFailures` and `main` render a failure as when no `render` option is given, for a consumer's own
|
|
2629
|
+
* `render` to hand a failure back to.
|
|
2630
|
+
*
|
|
2631
|
+
* @remarks
|
|
2632
|
+
* The plain lines of `CliFailure.toDoc(details.cause)`: a failure status line, a `Tree` for a schema failure, a
|
|
2633
|
+
* defect's message with its cleaned `stack`, and the one fixed line each for `Cancelled` and `NotInteractive`.
|
|
2634
|
+
* It has no terminal to ask, so it is the plain rendering for an agent, with absolute paths; the report `main` writes
|
|
2635
|
+
* with no `render` option is the same document in the renderer the audience gets (painted for a person), and that
|
|
2636
|
+
* report is `details.defaultLines`: return those to hand a failure back with the run's colour, links and path
|
|
2637
|
+
* display. With `status: false` the leading status (the glyph, or `[FAIL]` in plain text) is left off, so a prefix
|
|
2638
|
+
* such as the program's name reads cleanly; for that AND the run's settings, use `details.lines({ status: false })`.
|
|
2639
|
+
* A custom `render` that only cares about its own errors delegates the rest:
|
|
2640
|
+
*
|
|
2641
|
+
* ```ts
|
|
2642
|
+
* const render = (error: unknown, details: FailureDetails) =>
|
|
2643
|
+
* error instanceof MyError ? myLines(error) : CliRuntime.defaultRender(error, details)
|
|
2644
|
+
* ```
|
|
2645
|
+
*
|
|
2646
|
+
* @param error - the squashed failure
|
|
2647
|
+
* @param details - what `render` is told about the failure; accepted so a delegating `render` passes both
|
|
2648
|
+
* arguments through unchanged (only `cause` and `isDefect` are read)
|
|
2649
|
+
* @param options - `status: false` leaves off the leading status glyph or `[FAIL]` tag
|
|
2650
|
+
*/
|
|
2651
|
+
static readonly defaultRender: (error: unknown, details: Pick<FailureDetails, "cause" | "isDefect">, options?: {
|
|
2652
|
+
readonly status?: boolean | undefined;
|
|
2653
|
+
}) => string | ReadonlyArray<string>;
|
|
2654
|
+
/**
|
|
2655
|
+
* Catch a program's failure, render it through the ambient logger, and re-fail with the exit code and the
|
|
2656
|
+
* no-double-report mark.
|
|
2657
|
+
*
|
|
2658
|
+
* @param options - how to render the failure and which exit codes to use
|
|
402
2659
|
*/
|
|
403
2660
|
static readonly reportFailures: (options?: ReportFailuresOptions) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, Error, R>;
|
|
404
2661
|
/**
|
|
@@ -412,17 +2669,44 @@ export declare class CliRuntime {
|
|
|
412
2669
|
* fallback code rather than escaping to the runtime's stack trace.
|
|
413
2670
|
* - The logger is provided **outermost**, so it is present whichever branch
|
|
414
2671
|
* fails.
|
|
2672
|
+
* - With the `env` option, `CliEnv.layer` and `CliColor.formatterLayer` are
|
|
2673
|
+
* provided beside the platform, inside failure reporting, so the program can
|
|
2674
|
+
* read the audience, terminal, theme and `CliInteractive`.
|
|
415
2675
|
*
|
|
416
|
-
* You still call your platform's runner
|
|
2676
|
+
* You still call your platform's runner.
|
|
417
2677
|
*
|
|
418
2678
|
* @example
|
|
419
2679
|
* ```ts
|
|
2680
|
+
* import { CliRuntime } from "@effected/cli"
|
|
2681
|
+
* import { NodeRuntime, NodeServices } from "@effect/platform-node"
|
|
2682
|
+
* import { Command } from "effect/cli"
|
|
2683
|
+
*
|
|
420
2684
|
* NodeRuntime.runMain(
|
|
421
|
-
* CliRuntime.main(Command.run(root, { version }), { platform: NodeServices.layer, exitCode: 3 }),
|
|
2685
|
+
* CliRuntime.main(Command.run(root, { version: "1.0.0" }), { platform: NodeServices.layer, exitCode: 3 }),
|
|
422
2686
|
* )
|
|
423
2687
|
* ```
|
|
2688
|
+
*
|
|
2689
|
+
* @param program - the CLI program, usually `Command.run(root, { version })`
|
|
2690
|
+
* @param options - the platform layer, and optionally the logger, environment services, exit codes and rendering
|
|
424
2691
|
*/
|
|
425
|
-
static
|
|
2692
|
+
static main<A, E, R, RP, EP>(program: Effect.Effect<A, E, R>, options: MainOptions<RP, EP> & {
|
|
2693
|
+
readonly env?: undefined;
|
|
2694
|
+
}): Effect.Effect<void, Error, Exclude<Exclude<R, CliExit>, RP>>;
|
|
2695
|
+
static main<A, E, R, RP, EP>(program: Effect.Effect<A, E, R>, options: MainOptions<RP, EP> & {
|
|
2696
|
+
readonly env: CliEnvOptions & {
|
|
2697
|
+
readonly log: CliLogFileOptions;
|
|
2698
|
+
};
|
|
2699
|
+
}): Effect.Effect<void, Error, Exclude<Exclude<R, CliExit | CliEnvServices>, RP> | Exclude<Stdio.Stdio | Terminal.Terminal | FileSystem.FileSystem | Path.Path, RP>>;
|
|
2700
|
+
static main<A, E, R, RP, EP>(program: Effect.Effect<A, E, R>, options: MainOptions<RP, EP> & {
|
|
2701
|
+
readonly env: CliEnvOptions & {
|
|
2702
|
+
readonly log?: CliLogOptions & {
|
|
2703
|
+
readonly file?: undefined;
|
|
2704
|
+
};
|
|
2705
|
+
};
|
|
2706
|
+
}): Effect.Effect<void, Error, Exclude<Exclude<R, CliExit | CliEnvServices>, RP> | Exclude<Stdio.Stdio | Terminal.Terminal, RP>>;
|
|
2707
|
+
static main<A, E, R, RP, EP>(program: Effect.Effect<A, E, R>, options: MainOptions<RP, EP> & {
|
|
2708
|
+
readonly env: CliEnvOptions;
|
|
2709
|
+
}): Effect.Effect<void, Error, Exclude<Exclude<R, CliExit | CliEnvServices>, RP> | Exclude<Stdio.Stdio | Terminal.Terminal | FileSystem.FileSystem | Path.Path, RP>>;
|
|
426
2710
|
/**
|
|
427
2711
|
* Mark an error as already reported, carrying an exit code.
|
|
428
2712
|
*
|
|
@@ -431,7 +2715,7 @@ export declare class CliRuntime {
|
|
|
431
2715
|
* command that prints its own diagnostics, say — needs the same two marks
|
|
432
2716
|
* and should not have to rediscover the inverted polarity.
|
|
433
2717
|
*
|
|
434
|
-
* Under
|
|
2718
|
+
* Under `CliRuntime.main` or {@link CliRuntime.reportFailures}, do NOT
|
|
435
2719
|
* print the failure yourself before failing with it: `reportFailures`
|
|
436
2720
|
* renders every error except a `ShowHelp` and a `CliError.UserError` whose
|
|
437
2721
|
* reported mark is `false`, so it would print twice. Fail with the marked
|
|
@@ -465,35 +2749,21 @@ export declare class CliRuntime {
|
|
|
465
2749
|
//#endregion
|
|
466
2750
|
//#region src/ConfigIssueRenderer.d.ts
|
|
467
2751
|
/**
|
|
468
|
-
*
|
|
2752
|
+
* Turns a `@effected/config-file` `ConfigValidationError` into one line per rejected value.
|
|
469
2753
|
*
|
|
470
2754
|
* @remarks
|
|
471
2755
|
* `ConfigValidationError` carries the structured `issue` tree rather than a
|
|
472
|
-
* string,
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
476
|
-
*
|
|
477
|
-
*
|
|
478
|
-
*
|
|
479
|
-
*
|
|
480
|
-
*
|
|
481
|
-
*
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
* The import is additionally `import type`, so it is erased at build time and
|
|
485
|
-
* the runtime reach is **zero** — a consumer without `@effected/config-file`
|
|
486
|
-
* installed can import this module and call `render` on any value without the
|
|
487
|
-
* resolver ever being asked for the package.
|
|
488
|
-
*
|
|
489
|
-
* ## Why this and not just the error's message
|
|
490
|
-
*
|
|
491
|
-
* `ConfigValidationError.message` names the file. It does not name the value,
|
|
492
|
-
* and the difference is the whole diagnostic: a consumer that printed only the
|
|
493
|
-
* message told users "your config is invalid, run the doctor command", and the
|
|
494
|
-
* doctor command — which guessed from a hand-written list of known keys — could
|
|
495
|
-
* only ever find a *misspelling*. A wrongly **shaped** value left the two
|
|
496
|
-
* commands pointing at each other and neither saying what was wrong.
|
|
2756
|
+
* string, so a caller holds a tree it has to turn into sentences. This is that
|
|
2757
|
+
* step, the same treatment {@link SchemaIssueRenderer} gives a bare issue.
|
|
2758
|
+
*
|
|
2759
|
+
* `ConfigValidationError.message` names the file but not the value, and the
|
|
2760
|
+
* value is the diagnostic: printing only the message tells a user their config
|
|
2761
|
+
* is invalid without saying which value is wrong or how it is shaped.
|
|
2762
|
+
*
|
|
2763
|
+
* `@effected/config-file` is an optional peer, and this module only
|
|
2764
|
+
* `import type`s it, so the import is erased at build time. A consumer without
|
|
2765
|
+
* the package installed can import this module without the resolver being asked
|
|
2766
|
+
* for it.
|
|
497
2767
|
*
|
|
498
2768
|
* @example
|
|
499
2769
|
* ```ts
|
|
@@ -519,39 +2789,521 @@ export declare class ConfigIssueRenderer {
|
|
|
519
2789
|
*
|
|
520
2790
|
* @remarks
|
|
521
2791
|
* Takes the **error**, not its `issue`, because that is what a `catchTag`
|
|
522
|
-
* hands you and because `issue` is typed `Schema.Defect
|
|
523
|
-
*
|
|
524
|
-
*
|
|
525
|
-
* The parameter is the **typed** error rather than `unknown`. An earlier
|
|
526
|
-
* draft wrote `ConfigValidationError | unknown` to be accommodating, which
|
|
527
|
-
* collapses to plain `unknown` in TypeScript — so it accepted anything, said
|
|
528
|
-
* nothing, and left the type import in the `.d.ts` earning nothing. Inside
|
|
2792
|
+
* hands you and because `issue` is typed `Schema.Defect`, which every call
|
|
2793
|
+
* site would otherwise have to reach into. Inside
|
|
529
2794
|
* `Effect.catchTag("ConfigValidationError", …)` the error is already this
|
|
530
|
-
* type
|
|
2795
|
+
* type.
|
|
531
2796
|
*
|
|
532
|
-
* It
|
|
2797
|
+
* It cannot throw on a malformed value: the issue tree is validated by
|
|
533
2798
|
* a guard before it is read, so a renderer on an error path never becomes the
|
|
534
2799
|
* reason a program dies.
|
|
535
2800
|
*/
|
|
536
2801
|
static readonly render: (error: ConfigValidationError) => ReadonlyArray<string>;
|
|
537
2802
|
}
|
|
538
2803
|
//#endregion
|
|
2804
|
+
//#region src/Fmt.d.ts
|
|
2805
|
+
/**
|
|
2806
|
+
* Options for {@link Fmt.truncate}.
|
|
2807
|
+
*
|
|
2808
|
+
* @public
|
|
2809
|
+
*/
|
|
2810
|
+
interface TruncateOptions {
|
|
2811
|
+
/** Marks the cut; `…` by default. Counted by display width. */
|
|
2812
|
+
readonly ellipsis?: string | undefined;
|
|
2813
|
+
}
|
|
2814
|
+
/**
|
|
2815
|
+
* Options for {@link Fmt.percent}.
|
|
2816
|
+
*
|
|
2817
|
+
* @public
|
|
2818
|
+
*/
|
|
2819
|
+
interface PercentOptions {
|
|
2820
|
+
/** Decimal places to round to; `1` by default. A trailing zero decimal is dropped. */
|
|
2821
|
+
readonly digits?: number | undefined;
|
|
2822
|
+
/**
|
|
2823
|
+
* What the input is scaled to: `1` (the default) is a ratio from 0 to 1, `100` is already a percentage from 0
|
|
2824
|
+
* to 100, as istanbul's coverage numbers are.
|
|
2825
|
+
*/
|
|
2826
|
+
readonly scale?: 1 | 100 | undefined;
|
|
2827
|
+
}
|
|
2828
|
+
/**
|
|
2829
|
+
* Small, pure formatting primitives for terminal output.
|
|
2830
|
+
*
|
|
2831
|
+
* @public
|
|
2832
|
+
*/
|
|
2833
|
+
export declare class Fmt {
|
|
2834
|
+
private constructor();
|
|
2835
|
+
/**
|
|
2836
|
+
* Text made safe to lay out and print, exactly as the renderers make it: complete ANSI and OSC sequences removed,
|
|
2837
|
+
* every other control character removed (a stray ESC, BEL, BS, DEL, the C1 range) except line feed and carriage
|
|
2838
|
+
* return, and a tab turned into a space.
|
|
2839
|
+
*
|
|
2840
|
+
* @remarks
|
|
2841
|
+
* For a `render` or any other text a program builds by hand from data it does not control: an error message, a
|
|
2842
|
+
* file name, a value from the environment. Line breaks are kept, so split on them if the text must be one line.
|
|
2843
|
+
*
|
|
2844
|
+
* @param text - the text
|
|
2845
|
+
*/
|
|
2846
|
+
static readonly sanitize: (text: string) => string;
|
|
2847
|
+
/**
|
|
2848
|
+
* The display width of `text` in terminal columns: wide East Asian characters and emoji count two,
|
|
2849
|
+
* combining marks and ANSI escapes count none.
|
|
2850
|
+
*
|
|
2851
|
+
* @param text - the text to measure
|
|
2852
|
+
*/
|
|
2853
|
+
static readonly width: (text: string) => number;
|
|
2854
|
+
/**
|
|
2855
|
+
* Cut `text` to at most `width` columns, ending in `ellipsis` when it was cut.
|
|
2856
|
+
*
|
|
2857
|
+
* @remarks
|
|
2858
|
+
* Grapheme-safe: a grapheme, such as a wide character or an emoji ZWJ family, is kept whole or dropped
|
|
2859
|
+
* whole, so the result is never wider than `width`. Text that already fits is returned unchanged, colour
|
|
2860
|
+
* escapes included. Text that must be cut is cut as plain text: its ANSI escapes are dropped rather than cut
|
|
2861
|
+
* in half. When the ellipsis cannot fit, it is omitted and the text is cut to `width`; a `width` of 0 or
|
|
2862
|
+
* less gives `""`.
|
|
2863
|
+
*
|
|
2864
|
+
* @param text - the text to truncate
|
|
2865
|
+
* @param width - the most columns the result may take
|
|
2866
|
+
* @param options - the ellipsis
|
|
2867
|
+
*/
|
|
2868
|
+
static readonly truncate: (text: string, width: number, options?: TruncateOptions) => string;
|
|
2869
|
+
/**
|
|
2870
|
+
* A duration in milliseconds as short human text: `250ms`, `1.2s`, `2s`, `1m 3s`, `2m`, `1h 2m`, `2h`.
|
|
2871
|
+
*
|
|
2872
|
+
* @remarks
|
|
2873
|
+
* Under a second it is whole milliseconds; under a minute, seconds to one decimal with a trailing `.0`
|
|
2874
|
+
* dropped; under an hour, minutes and whole seconds, with the seconds dropped when zero; from an hour, hours and
|
|
2875
|
+
* whole minutes, the seconds dropped. A value that rounds up to the next unit (`999.6` to a second, `59999` to a
|
|
2876
|
+
* minute, `3599999` to an hour) is written in that unit, so `1000ms`, `60s` and `60m` never appear. There is no
|
|
2877
|
+
* days unit. A negative or non-finite input is `0ms`.
|
|
2878
|
+
*
|
|
2879
|
+
* @param ms - the duration in milliseconds
|
|
2880
|
+
*/
|
|
2881
|
+
static readonly duration: (ms: number) => string;
|
|
2882
|
+
/**
|
|
2883
|
+
* A ratio from 0 to 1 as a percentage, or a number already from 0 to 100 with `scale: 100`: `83.3%`, `50%`,
|
|
2884
|
+
* `100%`.
|
|
2885
|
+
*
|
|
2886
|
+
* @remarks
|
|
2887
|
+
* Rounded to `digits` decimal places (one by default) with trailing zeros dropped, so whole values print
|
|
2888
|
+
* without a decimal. A value that rounds to zero prints `0%`, never `-0%`. The input is not validated.
|
|
2889
|
+
*
|
|
2890
|
+
* @param n - the ratio, 0 to 1 (0 to 100 with `scale: 100`)
|
|
2891
|
+
* @param options - the decimal places and the scale
|
|
2892
|
+
*/
|
|
2893
|
+
static readonly percent: (n: number, options?: PercentOptions) => string;
|
|
2894
|
+
/**
|
|
2895
|
+
* A count with its noun: `1 test`, `2 tests`, `0 tests`.
|
|
2896
|
+
*
|
|
2897
|
+
* @param n - the count
|
|
2898
|
+
* @param singular - the noun for exactly one
|
|
2899
|
+
* @param plural - the noun otherwise; `singular` with an `s` appended by default
|
|
2900
|
+
*/
|
|
2901
|
+
static readonly plural: (n: number, singular: string, plural?: string) => string;
|
|
2902
|
+
}
|
|
2903
|
+
//#endregion
|
|
2904
|
+
//#region src/GithubAnnotation.d.ts
|
|
2905
|
+
/**
|
|
2906
|
+
* The severity of a GitHub annotation.
|
|
2907
|
+
*
|
|
2908
|
+
* @public
|
|
2909
|
+
*/
|
|
2910
|
+
type AnnotationLevel = "error" | "warning" | "notice";
|
|
2911
|
+
/**
|
|
2912
|
+
* What an annotation says about where it points and what it is called.
|
|
2913
|
+
*
|
|
2914
|
+
* @public
|
|
2915
|
+
*/
|
|
2916
|
+
interface GithubAnnotationProperties {
|
|
2917
|
+
/** `error`, `warning` or `notice`. */
|
|
2918
|
+
readonly level: AnnotationLevel;
|
|
2919
|
+
/** The repository-relative path of the annotated file. */
|
|
2920
|
+
readonly file?: string;
|
|
2921
|
+
/** The first annotated line, 1-based. */
|
|
2922
|
+
readonly line?: number;
|
|
2923
|
+
/** The first annotated column, 1-based. */
|
|
2924
|
+
readonly col?: number;
|
|
2925
|
+
/** The last annotated line. */
|
|
2926
|
+
readonly endLine?: number;
|
|
2927
|
+
/** The last annotated column. */
|
|
2928
|
+
readonly endColumn?: number;
|
|
2929
|
+
/** A short title shown above the annotation. */
|
|
2930
|
+
readonly title?: string;
|
|
2931
|
+
}
|
|
2932
|
+
/**
|
|
2933
|
+
* GitHub Actions annotations, as workflow commands.
|
|
2934
|
+
*
|
|
2935
|
+
* @public
|
|
2936
|
+
*/
|
|
2937
|
+
export declare class GithubAnnotation {
|
|
2938
|
+
private constructor();
|
|
2939
|
+
/**
|
|
2940
|
+
* Format an annotation as a workflow command: `::error title=T,file=F,line=1,endLine=2,col=3,endColumn=4::message`.
|
|
2941
|
+
*
|
|
2942
|
+
* @remarks
|
|
2943
|
+
* The message escapes `%`, CR and LF; a property value escapes those and `:` and `,`, per GitHub's
|
|
2944
|
+
* [workflow-command documentation](https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions).
|
|
2945
|
+
* The percent sign is escaped first, so an escape that was just written is never escaped again. An unescaped line
|
|
2946
|
+
* break in a message would let the text after it be read as a new command, which is why the escaping is not optional.
|
|
2947
|
+
*
|
|
2948
|
+
* A property that is not given is left out, and the properties are written in the order `title`, `file`, `line`,
|
|
2949
|
+
* `endLine`, `col`, `endColumn`, the same as `@effected/github-commands`' `WorkflowCommand`, which this renders
|
|
2950
|
+
* through.
|
|
2951
|
+
*
|
|
2952
|
+
* @param annotation - the level and the optional file, position and title
|
|
2953
|
+
* @param message - the annotation's text
|
|
2954
|
+
*/
|
|
2955
|
+
static readonly format: (annotation: GithubAnnotationProperties, message: string) => string;
|
|
2956
|
+
}
|
|
2957
|
+
//#endregion
|
|
2958
|
+
//#region src/NotInteractive.d.ts
|
|
2959
|
+
declare const NotInteractive_base: Schema.Class<NotInteractive, Schema.TaggedStruct<"NotInteractive", {}>, import("effect/Cause").YieldableError>;
|
|
2960
|
+
/**
|
|
2961
|
+
* A command needed to prompt, but there is no terminal to prompt on.
|
|
2962
|
+
*
|
|
2963
|
+
* @remarks
|
|
2964
|
+
* Exits `64` (BSD `EX_USAGE`) through core's `Runtime.errorExitCode` marker:
|
|
2965
|
+
* the caller invoked the command the wrong way, so the fix is to run it in a
|
|
2966
|
+
* terminal or pass the flag that supplies the answer. Its default rendering is
|
|
2967
|
+
* one line, `not interactive: run in a terminal or pass the flag`, which is the error's `message`, so a consumer
|
|
2968
|
+
* `render` can print `error.message` and keep it.
|
|
2969
|
+
*
|
|
2970
|
+
* @public
|
|
2971
|
+
*/
|
|
2972
|
+
export declare class NotInteractive extends NotInteractive_base {
|
|
2973
|
+
/**
|
|
2974
|
+
* The one line, `not interactive: run in a terminal or pass the flag`.
|
|
2975
|
+
*
|
|
2976
|
+
* @remarks
|
|
2977
|
+
* A prototype getter, not a field, so it is not part of the encoded form, equality or a JSON dump. Assigning to
|
|
2978
|
+
* it is ignored: a library that rewrites `error.message` must not make this error throw, which a getter-only
|
|
2979
|
+
* property does in strict mode. The line is fixed.
|
|
2980
|
+
*/
|
|
2981
|
+
get message(): string;
|
|
2982
|
+
set message(_value: string);
|
|
2983
|
+
/**
|
|
2984
|
+
* The process exit code: `64`.
|
|
2985
|
+
*
|
|
2986
|
+
* @remarks
|
|
2987
|
+
* A prototype getter rather than an own field, so a JSON or logger dump of the error does not carry the
|
|
2988
|
+
* runtime marker. It is the error's own code, so `CliRuntime`'s `usageExitCode` option does not change it.
|
|
2989
|
+
*/
|
|
2990
|
+
get [Runtime.errorExitCode](): number;
|
|
2991
|
+
}
|
|
2992
|
+
//#endregion
|
|
2993
|
+
//#region src/Render.d.ts
|
|
2994
|
+
/**
|
|
2995
|
+
* Everything a renderer needs to know about where its output is going.
|
|
2996
|
+
*
|
|
2997
|
+
* @remarks
|
|
2998
|
+
* A renderer is a pure function of a document and one of these, so two contexts give two renderings of the
|
|
2999
|
+
* same document. `paint` and `link` are plain functions: a context for a stream with no colour passes the
|
|
3000
|
+
* identity, and one whose hyperlinks are off passes a `link` that returns its label unchanged.
|
|
3001
|
+
*
|
|
3002
|
+
* @public
|
|
3003
|
+
*/
|
|
3004
|
+
interface RenderContext {
|
|
3005
|
+
/**
|
|
3006
|
+
* The display columns available.
|
|
3007
|
+
*
|
|
3008
|
+
* @remarks
|
|
3009
|
+
* `Infinity` is no limit. A renderer clamps what it is given: zero or a negative width is 1, and `NaN` is 80.
|
|
3010
|
+
* `Render.context` gives a human `TerminalEnv.width()`, which is the terminal's columns as stdout reports them, even
|
|
3011
|
+
* for a context built for `"stderr"` (core's `Terminal` has one width); pass `width` to override it.
|
|
3012
|
+
*/
|
|
3013
|
+
readonly width: number;
|
|
3014
|
+
/** Who the output is for. */
|
|
3015
|
+
readonly audience: AudienceKind;
|
|
3016
|
+
/** The colour level of the stream being written. */
|
|
3017
|
+
readonly color: ColorLevel;
|
|
3018
|
+
/** Paints text in a token or a style; the identity at colour `none`. */
|
|
3019
|
+
readonly paint: (token: TokenName | Style, text: string) => string;
|
|
3020
|
+
/** The glyph set: status glyphs, separators, the ellipsis. */
|
|
3021
|
+
readonly glyphs: GlyphSet;
|
|
3022
|
+
/**
|
|
3023
|
+
* Wraps a label as a link to a target; returns the label unchanged when links are off.
|
|
3024
|
+
*
|
|
3025
|
+
* @remarks
|
|
3026
|
+
* It must be pure and cheap: a renderer may call it more than once for one link. `Render.ansi` calls it once with
|
|
3027
|
+
* the plain label to learn whether links are on (an unchanged label means off, and the target is then written
|
|
3028
|
+
* after the label), and again when it paints, with the painted label. So it must decide on whether links are
|
|
3029
|
+
* allowed, not on the label's content, and it must not count or record its calls.
|
|
3030
|
+
*/
|
|
3031
|
+
readonly link: (target: LinkTarget, label: string) => string;
|
|
3032
|
+
/** Turns an absolute path into its display form; the identity by default. */
|
|
3033
|
+
readonly displayPath: (absolute: string) => string;
|
|
3034
|
+
/**
|
|
3035
|
+
* Whether the output will be read by the GitHub Actions runner, which has two command parsers: a line is a command
|
|
3036
|
+
* if, after .NET whitespace, it starts with `::`, or if `##[` occurs ANYWHERE in it (a bare `##` is not one). When
|
|
3037
|
+
* `true`, `plain`, `ansi` and `markdown` put a zero-width space in front of such a `::` line and between `##` and
|
|
3038
|
+
* `[` at each `##[`, so a document's text, an error message, say, can never inject a command. Unset or `false`
|
|
3039
|
+
* leaves their text alone. `Render.githubLog` ignores it and always neutralizes: its output is for the runner by
|
|
3040
|
+
* definition.
|
|
3041
|
+
*
|
|
3042
|
+
* @remarks
|
|
3043
|
+
* The trigger is the runner, not the audience: a person or an agent whose output lands in an Actions log is read
|
|
3044
|
+
* by it just the same. `Render.context` sets it when `CurrentRuntimeEnv` says GitHub Actions.
|
|
3045
|
+
*/
|
|
3046
|
+
readonly neutralizeWorkflowCommands?: boolean | undefined;
|
|
3047
|
+
/**
|
|
3048
|
+
* A base URL for file links in markdown, such as `https://github.com/<owner>/<repo>/blob/<sha>/`. When set,
|
|
3049
|
+
* `Render.markdown` links a `{ file }` target to the base followed by its display path (`displayPath`, URL-encoded,
|
|
3050
|
+
* without a leading `/`) and `#L<line>` when it has a line, in place of a `file://` URL a step summary's reader
|
|
3051
|
+
* cannot open. The other renderers do not read it.
|
|
3052
|
+
*/
|
|
3053
|
+
readonly linkBase?: string | undefined;
|
|
3054
|
+
}
|
|
3055
|
+
/**
|
|
3056
|
+
* Options for {@link Render.contextOf}.
|
|
3057
|
+
*
|
|
3058
|
+
* @public
|
|
3059
|
+
*/
|
|
3060
|
+
interface RenderContextOfOptions {
|
|
3061
|
+
/** Who the output is for. An `agent` gets no escape of any kind, whatever the other options say. */
|
|
3062
|
+
readonly audience: AudienceKind;
|
|
3063
|
+
/** The colour level; `none` by default, which paints nothing. */
|
|
3064
|
+
readonly color?: ColorLevel | undefined;
|
|
3065
|
+
/** The glyph set; Unicode by default. */
|
|
3066
|
+
readonly glyphs?: GlyphSet | undefined;
|
|
3067
|
+
/** The display columns; unbounded (`Infinity`) by default. */
|
|
3068
|
+
readonly width?: number | undefined;
|
|
3069
|
+
/** Turns an absolute path into its display form; the identity by default. */
|
|
3070
|
+
readonly displayPath?: ((absolute: string) => string) | undefined;
|
|
3071
|
+
/**
|
|
3072
|
+
* Hyperlinks: `off` (the default) leaves every label unlinked; a `CliLinksShape`, such as a `CliLinks` service's
|
|
3073
|
+
* value, makes OSC 8 hyperlinks through {@link CliLinks.linker}, for any audience but an agent.
|
|
3074
|
+
*/
|
|
3075
|
+
readonly links?: "off" | CliLinksShape | undefined;
|
|
3076
|
+
/**
|
|
3077
|
+
* See {@link RenderContext.neutralizeWorkflowCommands}. `true` by default for a `ci` audience, whose output the
|
|
3078
|
+
* Actions runner may read (it is harmless elsewhere), and unset for the others; an explicit `false` always wins.
|
|
3079
|
+
*/
|
|
3080
|
+
readonly neutralizeWorkflowCommands?: boolean | undefined;
|
|
3081
|
+
/** See {@link RenderContext.linkBase}; unset by default. */
|
|
3082
|
+
readonly linkBase?: string | undefined;
|
|
3083
|
+
}
|
|
3084
|
+
/**
|
|
3085
|
+
* Options for {@link Render.context}.
|
|
3086
|
+
*
|
|
3087
|
+
* @public
|
|
3088
|
+
*/
|
|
3089
|
+
interface RenderContextOptions {
|
|
3090
|
+
/**
|
|
3091
|
+
* The display columns to lay out at. By default a human gets `TerminalEnv.width()`, the terminal's columns as
|
|
3092
|
+
* stdout reports them even when the stream is `"stderr"`, and an agent or a CI gets no limit at all.
|
|
3093
|
+
*/
|
|
3094
|
+
readonly width?: number | undefined;
|
|
3095
|
+
/** Turns an absolute path into its display form, for example relative to the working directory; the identity by default. */
|
|
3096
|
+
readonly displayPath?: ((absolute: string) => string) | undefined;
|
|
3097
|
+
}
|
|
3098
|
+
/**
|
|
3099
|
+
* Pure renderers of a document: `(doc, context) => string`.
|
|
3100
|
+
*
|
|
3101
|
+
* @remarks
|
|
3102
|
+
* A renderer has no environment and no effects, so the same document and context always give the same string.
|
|
3103
|
+
* {@link Render.plain} is for agents; the rest of the set follows.
|
|
3104
|
+
*
|
|
3105
|
+
* @example
|
|
3106
|
+
* ```ts
|
|
3107
|
+
* import { Doc, Render } from "@effected/cli"
|
|
3108
|
+
*
|
|
3109
|
+
* const doc = [Doc.heading(2, "Results"), Doc.paragraph("3 checks passed")]
|
|
3110
|
+
* const ctx = Render.contextOf({ audience: "agent" })
|
|
3111
|
+
*
|
|
3112
|
+
* Render.plain(doc, ctx)
|
|
3113
|
+
* // => "Results\n3 checks passed"
|
|
3114
|
+
* ```
|
|
3115
|
+
*
|
|
3116
|
+
* @public
|
|
3117
|
+
*/
|
|
3118
|
+
export declare class Render {
|
|
3119
|
+
private constructor();
|
|
3120
|
+
/**
|
|
3121
|
+
* The {@link RenderContext} for a stream, from the services a CLI already has.
|
|
3122
|
+
*
|
|
3123
|
+
* @remarks
|
|
3124
|
+
* Everything is read once, here, so the renderers stay pure:
|
|
3125
|
+
*
|
|
3126
|
+
* - `audience` is the `Audience` in force, so an audience flag is honoured;
|
|
3127
|
+
* - `color`, `paint` and `glyphs` are the `CliTheme`'s for THAT stream, so redirecting stdout does not quiet
|
|
3128
|
+
* stderr; except that an agent's `color` is `none` and its `paint` the identity, so no renderer, `ansi` included,
|
|
3129
|
+
* writes an escape for an agent whatever the terminal could do;
|
|
3130
|
+
* - `link` is `CliLinks.linker` over that stream's hyperlink support and the audience, so an agent never
|
|
3131
|
+
* gets an escape and a terminal without OSC 8 gets the label;
|
|
3132
|
+
* - `neutralizeWorkflowCommands` is set when `CurrentRuntimeEnv` says GitHub Actions (read if present, not
|
|
3133
|
+
* required), for every audience, since the runner reads whatever is written there;
|
|
3134
|
+
* - `width` is the option, else `TerminalEnv.width()` for a human, and **unbounded** (`Infinity`) for an agent
|
|
3135
|
+
* or a CI, so nothing a reader needs is truncated or wrapped for a terminal that is not there.
|
|
3136
|
+
*
|
|
3137
|
+
* @param stream - the stream the output is for
|
|
3138
|
+
* @param options - an explicit width and a path display function
|
|
3139
|
+
*/
|
|
3140
|
+
static readonly context: (stream: "stdout" | "stderr", options?: RenderContextOptions) => Effect.Effect<RenderContext, never, CliTheme | TerminalEnv | Audience | CliLinks>;
|
|
3141
|
+
/**
|
|
3142
|
+
* A {@link RenderContext} from plain options, for a caller outside Effect, such as a test reporter or an Ink tree.
|
|
3143
|
+
*
|
|
3144
|
+
* @remarks
|
|
3145
|
+
* Pure: nothing is read from the environment. The defaults are colour `none`, the identity paint, no links,
|
|
3146
|
+
* Unicode glyphs, unbounded width and the identity `displayPath`, so a context built from an audience alone renders
|
|
3147
|
+
* with no escape of any kind. A colour level paints with the default token styles. An `agent` is colourless and
|
|
3148
|
+
* unlinked whatever `color` and `links` say, as in {@link Render.context}.
|
|
3149
|
+
*
|
|
3150
|
+
* @param options - the audience, and the colour, glyphs, width, path display, links, neutralizing and link base
|
|
3151
|
+
*/
|
|
3152
|
+
static readonly contextOf: (options: RenderContextOfOptions) => RenderContext;
|
|
3153
|
+
/**
|
|
3154
|
+
* Render a document as plain text for an agent.
|
|
3155
|
+
*
|
|
3156
|
+
* @remarks
|
|
3157
|
+
* There are no escape sequences of any kind, whatever the context's colour or hyperlinks allow: `paint` and
|
|
3158
|
+
* `link` are never called, and a control character in a document's text is removed. The audience is treated as
|
|
3159
|
+
* `agent`, so a path joins with ` > `.
|
|
3160
|
+
*
|
|
3161
|
+
* - A heading is its text alone, code is in backticks, and a link is its label followed by the target in
|
|
3162
|
+
* parentheses, as `path:line:col` through `displayPath` for a file, unless the label already is the target.
|
|
3163
|
+
* - A paragraph wraps to the width and is never truncated; a word longer than the width, such as a URL, stays
|
|
3164
|
+
* whole on its own line.
|
|
3165
|
+
* - A list uses `- ` items, and past its cap the overflow row. A table is aligned text columns with a rule under
|
|
3166
|
+
* the header; a short row is padded with empty cells, a cell holding line breaks shows its first line and an
|
|
3167
|
+
* ellipsis, and cells are truncated only when the table is wider than the context, widest column first. A tree uses the glyph set's tree segments.
|
|
3168
|
+
* - A collapsible is its title and the indented body, a callout its upper-case kind and the body, a code block
|
|
3169
|
+
* four-space indented, and a diff `- expected` lines then `+ received` lines, the cap limiting each side.
|
|
3170
|
+
* - Counts take their total and their visible counters from {@link Doc.total} and {@link Doc.visibleCounters}.
|
|
3171
|
+
* Inline gives `3/5 passed, 1 failed (1.2s)`: the first counter is the headline and shows its share of the
|
|
3172
|
+
* total, unless `share` is `false`. Columns gives aligned label and number pairs, and row one line of cells.
|
|
3173
|
+
* - A link with `suffix: false` never has its target after the label, and one with `suffix: true` always does.
|
|
3174
|
+
* - Verbatim text is its lines exactly, each indented by `indent` spaces, never wrapped; an annotation is nothing.
|
|
3175
|
+
* - Strong and emphasised content is its text; a file is its display path, unlinked. `Lines` are one line per entry,
|
|
3176
|
+
* a `Line` with `truncate` is cut to the width with the ellipsis, and diff text is its lines as given, the cap
|
|
3177
|
+
* followed by `… N more lines`. A counts table is a table with a column per counter key and the total row last,
|
|
3178
|
+
* and a counts `suffix` follows the duration.
|
|
3179
|
+
* - A compact list has no blank lines inside an item. A `style: "pipe"` table is istanbul's shape: a rule of dashes
|
|
3180
|
+
* meeting at `|` above and below the header and at the end, and cells joined with ` | `.
|
|
3181
|
+
* - Top-level blocks are consecutive lines; a section separates its title and children with blank lines.
|
|
3182
|
+
*
|
|
3183
|
+
* @param doc - the document
|
|
3184
|
+
* @param ctx - where the output is going
|
|
3185
|
+
*/
|
|
3186
|
+
static readonly plain: (doc: Document, ctx: RenderContext) => string;
|
|
3187
|
+
/**
|
|
3188
|
+
* Render a document for a person: the same layout as {@link Render.plain}, painted and linked.
|
|
3189
|
+
*
|
|
3190
|
+
* @remarks
|
|
3191
|
+
* The context's `paint` and `link` do the styling, so a context at colour `none` with links off gives exactly
|
|
3192
|
+
* what `plain` gives, apart from two things: code has no backticks (it is painted `accent` instead), and a path
|
|
3193
|
+
* joins with the audience's separator (`›` for a person) rather than ` > `. Tokens:
|
|
3194
|
+
*
|
|
3195
|
+
* - headings, section and collapsible titles, and table headers are `emphasis`; the rule under a header, tree
|
|
3196
|
+
* lines and overflow rows are `muted`;
|
|
3197
|
+
* - a status glyph takes its definition's token, and a diff's `-` lines are `failure` and `+` lines `success`;
|
|
3198
|
+
* - a callout's label takes its kind's token (`note` info, `tip` success, `important` accent, `warning` warning,
|
|
3199
|
+
* `caution` error), and a counter the token of its status, with the qualifier, the duration and the suffix `muted`.
|
|
3200
|
+
* A `Counts` with `paint: "none"` paints none of it, and with `paint: "glyph"` only a status glyph.
|
|
3201
|
+
* - strong content is bold and emphasised content italic, over any token it has; in diff text a `+` line is
|
|
3202
|
+
* `success` and a `-` line `failure`; a counts table's counts take their status's token.
|
|
3203
|
+
*
|
|
3204
|
+
* A link goes through `ctx.link`, which makes an OSC 8 hyperlink only when the policy allows it. When it does
|
|
3205
|
+
* not (it returns the label unchanged), the target follows the label in parentheses, muted, as in plain text.
|
|
3206
|
+
*
|
|
3207
|
+
* Text is cut and wrapped before it is painted, so a colour or a hyperlink is never cut in half, and a table
|
|
3208
|
+
* cut to the width keeps the colour of what remains. Tables are plain aligned columns, never box drawing:
|
|
3209
|
+
* box drawing costs two columns of every row for nothing a rule and the padding do not already say, and it
|
|
3210
|
+
* cannot be matched to plain text.
|
|
3211
|
+
*
|
|
3212
|
+
* @param doc - the document
|
|
3213
|
+
* @param ctx - where the output is going
|
|
3214
|
+
*/
|
|
3215
|
+
static readonly ansi: (doc: Document, ctx: RenderContext) => string;
|
|
3216
|
+
/**
|
|
3217
|
+
* Render a document as GitHub-flavoured markdown, for a step summary or a file.
|
|
3218
|
+
*
|
|
3219
|
+
* @remarks
|
|
3220
|
+
* There is no ANSI and no OSC 8 (`paint` and `link` are never called), and the width does not apply: a reader
|
|
3221
|
+
* wraps. Everything a document carries as text is escaped so that it cannot become markdown: the characters
|
|
3222
|
+
* that mean something, `|` everywhere so text can never form a table, the marker at the start of a line (a
|
|
3223
|
+
* heading, bullet, setext underline or ordered item) and the start of an autolink (a URL scheme or `www.`). An
|
|
3224
|
+
* email address is not escaped: a reader may make a `mailto:` link of it, which is harmless. A leading indent is
|
|
3225
|
+
* dropped, since markdown would read it as code.
|
|
3226
|
+
*
|
|
3227
|
+
* Under GitHub Actions (`neutralizeWorkflowCommands`) the same neutralizing applies, since markdown can be printed
|
|
3228
|
+
* to the log. Markdown escapes `[` in text, so `##[` cannot appear outside code and the headings are untouched
|
|
3229
|
+
* (a bare `##` is not a command); code spans and blocks, which are not escaped, get the zero-width space, which can
|
|
3230
|
+
* also land inside code or table text where it would otherwise have formed a command.
|
|
3231
|
+
*
|
|
3232
|
+
* GitHub also turns `@user`, `@org/team`, `#123` and commit SHAs in rendered markdown into mentions and references.
|
|
3233
|
+
* Nothing here escapes them: in a step summary they do not notify, but markdown posted as a comment could ping
|
|
3234
|
+
* whoever the text names.
|
|
3235
|
+
*
|
|
3236
|
+
* - A heading is `#` repeated by its level. A section's title is a heading of level 2 for a section at the top,
|
|
3237
|
+
* one deeper for each section nested inside it, to level 6.
|
|
3238
|
+
* - A table is a GFM pipe table: `|` is `\|` in a cell and a line break in a cell is `<br>`. A short row is
|
|
3239
|
+
* padded and a long one widens the table. With no header, the header row is empty.
|
|
3240
|
+
* - A collapsible is `<details><summary>title</summary>`, a blank line, the body as markdown, a blank line and
|
|
3241
|
+
* `</details>`. The title is HTML, so it is HTML-escaped and plain.
|
|
3242
|
+
* - A callout is a quoted `[!KIND]` followed by its body. A code block is a fence longer than any backtick run it
|
|
3243
|
+
* holds, and a diff a `diff` fence of `-` and `+` lines.
|
|
3244
|
+
* - A link is `[label](url)` when it has a URL a reader can follow: an `http`, `https`, `mailto`, `file` or
|
|
3245
|
+
* `vscode` URL, or a relative one. A file link has one when its path is absolute (`file://`). Otherwise, such as
|
|
3246
|
+
* for a `javascript:` URL or a relative file path, it is the label followed by the target in inline code, as
|
|
3247
|
+
* `path:line:col` for a file.
|
|
3248
|
+
* - A list is bullets, a tree a nested bullet list under its root label, and overflow rows paragraphs after what
|
|
3249
|
+
* they cap. Counts inline is a paragraph, columns a list of `label: n` and row a one-row table of the counter
|
|
3250
|
+
* labels over their numbers, every header named (the duration as `duration`), with the label above the table and
|
|
3251
|
+
* the qualifier and suffix below it.
|
|
3252
|
+
* - Verbatim text is a fenced code block, so its indentation survives; an annotation is nothing.
|
|
3253
|
+
* - Strong content is `**…**` and emphasised `*…*`, which GFM reads inside a word too, with the spaces at a run's
|
|
3254
|
+
* edges kept outside the markers. `Lines` are one paragraph with a hard break between entries, an empty entry
|
|
3255
|
+
* between two others an empty line (one at either end is dropped); a `Line` is one
|
|
3256
|
+
* paragraph; diff text a `diff` fence; a counts table a pipe table; a file is its display path as text.
|
|
3257
|
+
* - With `linkBase`, a file link goes to the base and the display path, plus `#L<line>`, in place of `file://`. A
|
|
3258
|
+
* display path that is absolute or climbs out with `..` is not under the base, so its link has no URL form.
|
|
3259
|
+
* - A compact list item joins its parts with no blank line, putting a hard break where two paragraphs would merge.
|
|
3260
|
+
* A row of counts names its duration column `duration`.
|
|
3261
|
+
*
|
|
3262
|
+
* @param doc - the document
|
|
3263
|
+
* @param ctx - where the output is going; its glyph set, audience and `displayPath` are used
|
|
3264
|
+
*/
|
|
3265
|
+
static readonly markdown: (doc: Document, ctx: RenderContext) => string;
|
|
3266
|
+
/**
|
|
3267
|
+
* Render a document for a GitHub Actions log.
|
|
3268
|
+
*
|
|
3269
|
+
* @remarks
|
|
3270
|
+
* Everything is what {@link Render.plain} renders, except an annotation, which is one workflow command
|
|
3271
|
+
* (`::error file=…,line=…::message`), and a collapsible that starts a line, which is a group: `::group::title`, its
|
|
3272
|
+
* body, `::endgroup::`. An annotation is a command at the top level, as a top-level section's child, and as a direct
|
|
3273
|
+
* child of a group's body; anywhere deeper (inside a list, a callout, or a section within a group) it is nothing,
|
|
3274
|
+
* as in plain. Its message and properties are escaped, so no text can end
|
|
3275
|
+
* the command or start another, and the kit's own command is never neutralized. That is a top-level collapsible, or one that is a direct child of a
|
|
3276
|
+
* top-level section. GitHub does not nest groups, so a collapsible inside a group, or inside a list or callout
|
|
3277
|
+
* (where it would not start a line), keeps plain's rendering: its title on a line and its body indented.
|
|
3278
|
+
*
|
|
3279
|
+
* The runner has two command parsers, and a line is a command if either accepts it: after its leading whitespace it
|
|
3280
|
+
* starts with `::`, or `##[` occurs ANYWHERE in it (a bare `##` is not one). A document's text must not be able to
|
|
3281
|
+
* do that (`::add-mask::`, `::error::`, `##[error]`), so such a `::` line gets a zero-width space in front, which
|
|
3282
|
+
* the runner does not treat as whitespace, and every `##[` gets one between the `##` and the `[`. The text is
|
|
3283
|
+
* otherwise unchanged. A
|
|
3284
|
+
* group's title is a command's data, so its `%`, CR and LF are escaped. Lines are split at CR, LF and CRLF before
|
|
3285
|
+
* that check, as the runner splits them. There is no ANSI and `paint` and `link` are never called, and the audience
|
|
3286
|
+
* is treated as `agent`, as `plain` does.
|
|
3287
|
+
*
|
|
3288
|
+
* @param doc - the document
|
|
3289
|
+
* @param ctx - where the output is going; the width, glyph set and `displayPath` are used as plain uses them
|
|
3290
|
+
*/
|
|
3291
|
+
static readonly githubLog: (doc: Document, ctx: RenderContext) => string;
|
|
3292
|
+
}
|
|
3293
|
+
//#endregion
|
|
539
3294
|
//#region src/SchemaIssueRenderer.d.ts
|
|
540
3295
|
/**
|
|
541
|
-
*
|
|
3296
|
+
* Turns a `SchemaIssue` tree into lines a user can act on.
|
|
542
3297
|
*
|
|
543
3298
|
* @remarks
|
|
544
3299
|
* A decode failure arrives as a structured tree; a person needs
|
|
545
|
-
* `unknown key at groups.g.cleanup.rulesetz`.
|
|
3300
|
+
* `unknown key at groups.g.cleanup.rulesetz`. The formatters core ships for
|
|
3301
|
+
* this live on `SchemaIssue` rather than on `SchemaError` or `Schema`, and
|
|
3302
|
+
* `SchemaError.message` does not use them, so printing the error alone does not
|
|
3303
|
+
* give these lines.
|
|
546
3304
|
*
|
|
547
|
-
*
|
|
548
|
-
*
|
|
549
|
-
* `Schema`, they are named `makeFormatter*` rather than anything containing
|
|
550
|
-
* "render" or "format issue", and `SchemaError.message` does not use them — so
|
|
551
|
-
* the obvious probe, printing the error, hints at nothing. Two engineers
|
|
552
|
-
* searched for two rounds and concluded core had none. This export exists to
|
|
553
|
-
* end that search, and the one phrasing override is a bonus rather than the
|
|
554
|
-
* point.
|
|
3305
|
+
* The lines and `CliFailure`'s tree are two views of the same rejected values (`internal/format`), so a schema
|
|
3306
|
+
* failure in the default report and these lines never disagree.
|
|
555
3307
|
*
|
|
556
3308
|
* @example
|
|
557
3309
|
* ```ts
|
|
@@ -583,5 +3335,5 @@ export declare class SchemaIssueRenderer {
|
|
|
583
3335
|
static readonly render: (issue: unknown) => ReadonlyArray<string>;
|
|
584
3336
|
}
|
|
585
3337
|
//#endregion
|
|
586
|
-
export type { CliExitShape, CliLoggerOptions, FailureDetails, MainOptions, ReportFailuresOptions };
|
|
3338
|
+
export type { AnnotationLevel, AnnotationOptions, AudienceFlagInput, Block, BlockOf, CliAudienceFlagsOptions, CliDocSource, CliEnvOptions, CliEnvServices, CliEnvTestOptions, CliEnvTestServices, CliExitShape, CliFailureOptions, CliLinksLinkerOptions, CliLinksOptions, CliLinksShape, CliLogFile, CliLogFileOptions, CliLogOptions, CliLoggerOptions, CliMessageOptions, CliPromptFallbackOptions, CliPromptTarget, CliThemeOptions, CliThemeShape, CliThemeTestOptions, Column, CoreStatusName, Counter, CountsOptions, CountsRow, CountsTableOptions, DocPrintOptions, Document, EditorLinks, FailureDetails, GithubAnnotationProperties, GlyphSelectOptions, GlyphSet, Inline, InlineInput, InlineOf, LinkOptions, LinkTarget, ListOptions, MainOptions, NamedColor, OverflowOptions, PercentOptions, RenderContext, RenderContextOfOptions, RenderContextOptions, ReportFailuresOptions, RequiresAudienceFlags, StatusDef, StatusRef, StreamTheme, Style, TableOptions, TokenName, TreeInput, TreeNode, TruncateOptions };
|
|
587
3339
|
//# sourceMappingURL=index.d.ts.map
|