@orkestrel/terminal 0.0.8 → 0.0.10
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/README.md +51 -33
- package/dist/src/core/index.cjs +611 -943
- package/dist/src/core/index.d.cts +522 -963
- package/dist/src/core/index.d.ts +522 -963
- package/dist/src/core/index.js +610 -916
- package/dist/src/server/index.cjs +556 -203
- package/dist/src/server/index.d.cts +232 -129
- package/dist/src/server/index.d.ts +232 -129
- package/dist/src/server/index.js +541 -204
- package/package.json +10 -8
- package/dist/src/core/index.cjs.map +0 -1
- package/dist/src/core/index.js.map +0 -1
- package/dist/src/server/index.cjs.map +0 -1
- package/dist/src/server/index.js.map +0 -1
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
1
|
+
import { FieldChoice } from '@orkestrel/form';
|
|
2
|
+
import { FieldControl } from '@orkestrel/form';
|
|
3
|
+
import { FieldValue } from '@orkestrel/form';
|
|
4
|
+
import { FormField } from '@orkestrel/form';
|
|
5
|
+
import { FormInterface } from '@orkestrel/form';
|
|
6
|
+
import { FormValues } from '@orkestrel/form';
|
|
7
|
+
import { PromptTheme } from '@orkestrel/terminal';
|
|
8
|
+
import { PromptThemeOptions } from '@orkestrel/terminal';
|
|
9
|
+
import { StylerInterface } from '@orkestrel/console';
|
|
10
|
+
import { TerminalInterface } from '@orkestrel/terminal';
|
|
11
|
+
import { TextField } from '@orkestrel/form';
|
|
8
12
|
|
|
9
13
|
/** A carriage return (`\r`, U+000D) — returns the cursor to column 0 so a redraw starts at the line's left edge. */
|
|
10
14
|
export declare const CARRIAGE_RETURN: string;
|
|
@@ -17,39 +21,55 @@ export declare const CARRIAGE_RETURN: string;
|
|
|
17
21
|
export declare const CLEAR_DOWN: string;
|
|
18
22
|
|
|
19
23
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
|
|
24
|
+
* The format cue appended to a field's label for each control the walk reads as a line of text —
|
|
25
|
+
* the terminal has no date picker, no color well, and no file chooser, so the accepted shape is
|
|
26
|
+
* stated instead. A control with no entry needs none: `text` and `editor` accept any line,
|
|
27
|
+
* `password` masks one, and `confirm`, `select`, and `checkbox` are answered by key rather than by
|
|
28
|
+
* format. The form's own rules still decide whether the typed value is acceptable.
|
|
29
|
+
*/
|
|
30
|
+
export declare const CONTROL_HINTS: Readonly<Partial<Record<FieldControl, string>>>;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Create the interactive terminal form driver — the local-keyboard arm of the terminal trio, beside
|
|
34
|
+
* the core headless `createPrompt` broker and the SSE `createPromptClient` bridge. Where the broker
|
|
35
|
+
* PARKS a live form until somebody elsewhere answers it, a `Terminal` answers one HERE: it walks the
|
|
36
|
+
* form's fields in schema order, drives each control's pure reducer over raw-mode stdin, binds every
|
|
37
|
+
* answer through the form's own `fill`, and submits. It is the only impure part of the terminal
|
|
38
|
+
* stack.
|
|
26
39
|
*
|
|
27
40
|
* @param options - See {@link TerminalOptions}
|
|
28
|
-
* @returns A {@link TerminalInterface}
|
|
29
|
-
* / `select` / `checkbox` / `editor`) driven over the resolved streams
|
|
41
|
+
* @returns A {@link TerminalInterface} whose `ask` drives one whole form over the resolved streams
|
|
30
42
|
*
|
|
31
43
|
* @remarks
|
|
32
|
-
* - **
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* - **
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* `
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
44
|
+
* - **The form is the unit.** `ask` takes the caller's live form and returns its settled values. The
|
|
45
|
+
* returned promise is that form's own `answer`, so a caller holding the form can await either one.
|
|
46
|
+
* - **Every control renders.** Seven controls are read as a line of text with their format cue,
|
|
47
|
+
* `password` masks, `confirm` takes a key, `editor` takes a block, `select` and `checkbox` drive a
|
|
48
|
+
* list, and an open `select` accepts a value its list does not offer.
|
|
49
|
+
* - **The form decides.** A blank answer binds as absence, the form evaluates, and a refusal
|
|
50
|
+
* re-walks only the fields the walk can still edit.
|
|
51
|
+
* - **Injectable and guard-narrowed.** `input` and `output` default to `process.stdin` and
|
|
52
|
+
* `process.stdout` but accept any stream of the declared minimal shape, resolved through their
|
|
53
|
+
* guards rather than an assertion, so a test drives a whole form with a fake TTY that emits
|
|
54
|
+
* scripted key chunks and records every rendered byte.
|
|
55
|
+
* - **Non-TTY fallback.** A piped stream cannot enter raw mode, so the same walk runs over
|
|
56
|
+
* `node:readline` line input.
|
|
45
57
|
*
|
|
46
58
|
* @example
|
|
47
59
|
* ```ts
|
|
48
|
-
* import {
|
|
60
|
+
* import { createForm } from '@orkestrel/form'
|
|
61
|
+
* import { createTerminal } from '@orkestrel/terminal/server'
|
|
49
62
|
*
|
|
50
63
|
* const terminal = createTerminal()
|
|
51
|
-
* const
|
|
52
|
-
*
|
|
64
|
+
* const values = await terminal.ask(
|
|
65
|
+
* createForm({
|
|
66
|
+
* label: 'Sign up',
|
|
67
|
+
* fields: [
|
|
68
|
+
* { control: 'text', name: 'email', label: 'Email', rule: { required: true, email: true } },
|
|
69
|
+
* { control: 'confirm', name: 'terms', label: 'I accept the terms' },
|
|
70
|
+
* ],
|
|
71
|
+
* }),
|
|
72
|
+
* )
|
|
53
73
|
* ```
|
|
54
74
|
*/
|
|
55
75
|
export declare function createTerminal(options?: TerminalOptions): TerminalInterface;
|
|
@@ -59,8 +79,8 @@ export declare const CSI: string;
|
|
|
59
79
|
|
|
60
80
|
/**
|
|
61
81
|
* The cursor-UP sequence TEMPLATE (`ESC[{count}A`) — {@link import('./helpers.js').moveUp}
|
|
62
|
-
* interpolates `{count}` with the number of lines to climb
|
|
63
|
-
*
|
|
82
|
+
* interpolates the `{count}` placeholder with the number of lines to climb. Kept as a template so
|
|
83
|
+
* the count stays out of the constant.
|
|
64
84
|
*/
|
|
65
85
|
export declare const CSI_UP: string;
|
|
66
86
|
|
|
@@ -73,42 +93,88 @@ export declare const CURSOR_HIDE: string;
|
|
|
73
93
|
/** Show the cursor (`ESC[?25h`) — restores the cursor after a prompt resolves / cancels (the {@link CURSOR_HIDE} pair). */
|
|
74
94
|
export declare const CURSOR_SHOW: string;
|
|
75
95
|
|
|
96
|
+
/**
|
|
97
|
+
* The choices a `select` or `checkbox` field SHOWS but refuses — the complement of
|
|
98
|
+
* {@link enabledChoices}, rendered by {@link unavailableLine} above the list so a reader sees why a
|
|
99
|
+
* declared choice is missing from it.
|
|
100
|
+
*
|
|
101
|
+
* @param choices - The field's declared choices
|
|
102
|
+
* @returns The refused choices, in declared order
|
|
103
|
+
*/
|
|
104
|
+
export declare function disabledChoices(choices: readonly FieldChoice[]): readonly FieldChoice[];
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* The choices a `select` or `checkbox` field actually OFFERS — the form refuses a disabled choice's
|
|
108
|
+
* value at every door, including a fill, so the walk never puts one in front of the cursor. Pair
|
|
109
|
+
* with {@link disabledChoices} to tell the reader what was withheld.
|
|
110
|
+
*
|
|
111
|
+
* @param choices - The field's declared choices
|
|
112
|
+
* @returns The choices the walk offers, in declared order
|
|
113
|
+
*/
|
|
114
|
+
export declare function enabledChoices(choices: readonly FieldChoice[]): readonly FieldChoice[];
|
|
115
|
+
|
|
76
116
|
/** The Escape byte (ESC, U+001B) — the lead byte of every CSI cursor-control sequence below. */
|
|
77
117
|
export declare const ESCAPE: string;
|
|
78
118
|
|
|
79
119
|
/** The comma-separated multi-select hint the non-TTY `checkbox` fallback shows (the user types one or more numbers). */
|
|
80
120
|
export declare const FALLBACK_CHECKBOX_HINT = "Enter numbers separated by commas";
|
|
81
121
|
|
|
122
|
+
/** The hint the non-TTY `confirm` fallback shows — a piped stream sends a whole line, so the answer is typed rather than pressed. */
|
|
123
|
+
export declare const FALLBACK_CONFIRM_HINT = "(y/n)";
|
|
124
|
+
|
|
125
|
+
/** The hint the non-TTY `editor` fallback shows — a piped stream has no ctrl-d, so end of input finishes the block. */
|
|
126
|
+
export declare const FALLBACK_EDITOR_HINT = "(end of input finishes)";
|
|
127
|
+
|
|
82
128
|
/**
|
|
83
|
-
* The numbered-list prompt the non-TTY {@link import('./Terminal.js').Terminal} `select`
|
|
84
|
-
*
|
|
85
|
-
* printed numbered and the user types
|
|
129
|
+
* The numbered-list prompt the non-TTY {@link import('./Terminal.js').Terminal} `select` fallback
|
|
130
|
+
* appends — a piped (non-terminal) stream cannot navigate with arrow keys, so the choices are
|
|
131
|
+
* printed numbered and the user types one number on a single readline line.
|
|
86
132
|
*/
|
|
87
133
|
export declare const FALLBACK_SELECT_HINT = "Enter a number";
|
|
88
134
|
|
|
89
135
|
/**
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* {@link
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
136
|
+
* Project any field the walk reads as a LINE OF TEXT into the {@link TextField} the text reducer
|
|
137
|
+
* takes — `text` itself, and the six controls a terminal has no widget for: `number`, `date`,
|
|
138
|
+
* `time`, `datetime`, `color`, and one `file` entry. The label carries that control's format cue
|
|
139
|
+
* from {@link CONTROL_HINTS}, and a declared `default` becomes the line a bare return submits. The
|
|
140
|
+
* projection carries no rule, because the AUTHORITATIVE form still evaluates the answer this line
|
|
141
|
+
* binds; it exists only so one reducer can render seven controls.
|
|
142
|
+
*
|
|
143
|
+
* @param field - The field being read
|
|
144
|
+
* @returns The text field the reducer renders for it
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```ts
|
|
148
|
+
* fieldToText({ control: 'date', name: 'born', label: 'Birthday' })
|
|
149
|
+
* // { control: 'text', name: 'born', label: 'Birthday (YYYY-MM-DD)' }
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
export declare function fieldToText(field: FormField): TextField;
|
|
153
|
+
|
|
154
|
+
/** The instruction a `file` field with `multiple` shows before its entries — one path per line, and a blank line ends the list. */
|
|
155
|
+
export declare const FILE_HINT = "One path per line, blank to finish";
|
|
156
|
+
|
|
157
|
+
/** The section header the walk writes when it enters a new field group, painted by the `message` role. */
|
|
158
|
+
export declare function groupHeader(styler: StylerInterface, theme: PromptTheme, label: string): string;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* The minimal input-stream shape the driver reads — exactly the slice of a Node `tty.ReadStream` /
|
|
162
|
+
* `process.stdin` it touches, and no more. A {@link TerminalOptions} `input` is narrowed to this
|
|
163
|
+
* through {@link import('./helpers.js').isInputStream}, never an assertion, so a test drives a whole
|
|
164
|
+
* form with a hand-built fake stream that emits scripted key chunks, never touches the real
|
|
165
|
+
* `process.stdin`, and asserts that raw mode is entered once and always cleaned up.
|
|
97
166
|
*
|
|
98
167
|
* @remarks
|
|
99
168
|
* - `on(event, listener)` / `off(event, listener)` — subscribe / unsubscribe a `'data'` chunk
|
|
100
|
-
* listener (the irreducible event seam; a `Buffer
|
|
101
|
-
* required methods.
|
|
102
|
-
* - `setRawMode(mode)` — switch the TTY in
|
|
103
|
-
* no line buffering, no echo). Present on a real `tty.ReadStream`; ABSENT on a
|
|
104
|
-
* stream
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* - `isTTY` — `true` on a real terminal, absent / `false` when piped to a file or another process.
|
|
110
|
-
* The driver reads it to choose the raw-mode path (interactive arrow-key prompts) vs. the readline
|
|
111
|
-
* fallback (numbered / line input).
|
|
169
|
+
* listener (the irreducible event seam; a `Buffer`, string, or `Uint8Array` chunk arrives). The
|
|
170
|
+
* two required methods.
|
|
171
|
+
* - `setRawMode(mode)` — switch the TTY in and out of raw mode (each keypress delivered
|
|
172
|
+
* immediately, no line buffering, no echo). Present on a real `tty.ReadStream`; ABSENT on a
|
|
173
|
+
* piped, non-TTY stream, and its absence (or `isTTY !== true`) selects the
|
|
174
|
+
* {@link import('node:readline').Interface} line-input fallback.
|
|
175
|
+
* - `resume()` / `pause()` — start / stop the flow of `'data'` events. Raw mode `resume()`s on
|
|
176
|
+
* enter and `pause()`s on cleanup; both are optional, so a fake may omit them.
|
|
177
|
+
* - `isTTY` — `true` on a real terminal, absent or `false` when piped to a file or another process.
|
|
112
178
|
*/
|
|
113
179
|
export declare interface InputStreamInterface {
|
|
114
180
|
on(event: 'data', listener: (chunk: string | Uint8Array) => void): void;
|
|
@@ -160,17 +226,6 @@ export declare function isOutputStream(value: unknown): value is OutputStreamInt
|
|
|
160
226
|
*/
|
|
161
227
|
export declare function isReadable(value: unknown): value is NodeJS.ReadableStream;
|
|
162
228
|
|
|
163
|
-
/**
|
|
164
|
-
* Whether `value` is a Node {@link NodeJS.WritableStream} — a total structural guard (AGENTS §14)
|
|
165
|
-
* checking for the callable `write` / `end` that `node:readline`'s `createInterface` accepts as its
|
|
166
|
-
* `output`. Paired with {@link isReadable} so the non-TTY fallback narrows BOTH streams to the
|
|
167
|
-
* readline boundary without an `as`. Never throws.
|
|
168
|
-
*
|
|
169
|
-
* @param value - The resolved output stream (or any value crossing the boundary)
|
|
170
|
-
* @returns `true` when `value` has the writable methods readline needs
|
|
171
|
-
*/
|
|
172
|
-
export declare function isWritable(value: unknown): value is NodeJS.WritableStream;
|
|
173
|
-
|
|
174
229
|
/** A line feed (`\n`, U+000A) — the line terminator the driver writes after the final committed prompt view. */
|
|
175
230
|
export declare const LINE_FEED: string;
|
|
176
231
|
|
|
@@ -185,6 +240,22 @@ export declare const LINE_FEED: string;
|
|
|
185
240
|
*/
|
|
186
241
|
export declare function lineCount(view: string): number;
|
|
187
242
|
|
|
243
|
+
/** The mark on a locked field's line — the walk renders its value and moves on, because the form refuses an edit there. */
|
|
244
|
+
export declare const LOCKED_MARK = "(locked)";
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* The read-only line a LOCKED field renders — its label, the {@link LOCKED_MARK}, and the answer the
|
|
248
|
+
* form already holds. The walk writes this instead of a prompt, because the field is still
|
|
249
|
+
* validated and still submitted but must not be edited here.
|
|
250
|
+
*
|
|
251
|
+
* @param styler - The console styler that renders each role
|
|
252
|
+
* @param theme - The resolved prompt theme
|
|
253
|
+
* @param label - The field's label
|
|
254
|
+
* @param value - The held answer, from {@link valueToText}
|
|
255
|
+
* @returns The rendered line, with no trailing space when there is nothing to show
|
|
256
|
+
*/
|
|
257
|
+
export declare function lockedLine(styler: StylerInterface, theme: PromptTheme, label: string, value: string): string;
|
|
258
|
+
|
|
188
259
|
/**
|
|
189
260
|
* The cursor-UP control sequence that moves the cursor up `count` lines (`ESC[{count}A`) — or the
|
|
190
261
|
* empty string when `count` is zero or negative (no movement needed, and `ESC[0A` is a wasted write).
|
|
@@ -197,19 +268,29 @@ export declare function lineCount(view: string): number;
|
|
|
197
268
|
export declare function moveUp(count: number): string;
|
|
198
269
|
|
|
199
270
|
/**
|
|
200
|
-
* The
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
271
|
+
* The numbered choice list the non-TTY fallback prints — a piped stream cannot navigate with arrow
|
|
272
|
+
* keys, so each offered choice is printed with the number the reader types back. One line per
|
|
273
|
+
* choice, with no trailing newline.
|
|
274
|
+
*
|
|
275
|
+
* @param styler - The console styler that renders each role
|
|
276
|
+
* @param theme - The resolved prompt theme
|
|
277
|
+
* @param choices - The choices the walk offers, from {@link enabledChoices}
|
|
278
|
+
* @returns The rendered list
|
|
279
|
+
*/
|
|
280
|
+
export declare function numberedList(styler: StylerInterface, theme: PromptTheme, choices: readonly FieldChoice[]): string;
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* The minimal output-stream shape the driver writes — exactly the slice of a Node `tty.WriteStream`
|
|
284
|
+
* / `process.stdout` it touches. A {@link TerminalOptions} `output` is narrowed to this through
|
|
285
|
+
* {@link import('./helpers.js').isOutputStream}, never an assertion, so a test records every byte
|
|
286
|
+
* the walk renders and asserts the rendered content with the ANSI stripped.
|
|
205
287
|
*
|
|
206
288
|
* @remarks
|
|
207
|
-
* - `write(text)` — the one required method: push a chunk (a rendered
|
|
208
|
-
*
|
|
209
|
-
* the return
|
|
210
|
-
* - `isTTY` — present and `true` on a real terminal. The driver does not branch its rendering on
|
|
211
|
-
*
|
|
212
|
-
* stream and so a consumer may inspect it.
|
|
289
|
+
* - `write(text)` — the one required method: push a chunk (a rendered field view, a group header, a
|
|
290
|
+
* cursor or clear sequence) to the stream. A real stream returns a backpressure boolean; the
|
|
291
|
+
* driver ignores the return, because a prompt is human-paced, so a fake may return `void`.
|
|
292
|
+
* - `isTTY` — present and `true` on a real terminal. The driver does not branch its rendering on
|
|
293
|
+
* it; the styler already decided color.
|
|
213
294
|
*/
|
|
214
295
|
export declare interface OutputStreamInterface {
|
|
215
296
|
write(text: string): boolean | void;
|
|
@@ -248,74 +329,96 @@ export declare function rawCapable(input: InputStreamInterface): boolean;
|
|
|
248
329
|
export declare function redrawPrefix(previousLines: number): string;
|
|
249
330
|
|
|
250
331
|
/**
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
255
|
-
* resolves on a `submit` step / rejects with a {@link TerminalError} (`CANCEL`) on ctrl-c. It owns no
|
|
256
|
-
* prompt logic of its own — state, view, validation, and the cancel signal all come from the pure
|
|
257
|
-
* core; this class owns ONLY the cursor + raw-mode + in-place re-render mechanics.
|
|
258
|
-
*
|
|
259
|
-
* @remarks
|
|
260
|
-
* See {@link TerminalInterface} for the behavioral contract (raw-mode leak-freedom, the in-place
|
|
261
|
-
* re-render, the non-TTY readline fallback, event-free).
|
|
332
|
+
* What a field is told when the walk read an answer the control cannot hold — a word typed into a
|
|
333
|
+
* `number`, an off-list value typed into an open `select` whose choice is refused. The value binds
|
|
334
|
+
* as absence and this message is invalidated onto the field, so the walk re-asks it with the reason
|
|
335
|
+
* on screen.
|
|
262
336
|
*/
|
|
263
|
-
export declare
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
checkbox(options: CheckboxOptions): Promise<readonly string[]>;
|
|
271
|
-
editor(options: EditorOptions): Promise<string>;
|
|
272
|
-
}
|
|
337
|
+
export declare const REFUSAL_MESSAGE = "Enter a value this field accepts";
|
|
338
|
+
|
|
339
|
+
/** The lead on the line listing an open `select`'s offered values, which a typed answer may ignore. */
|
|
340
|
+
export declare const SUGGESTION_LEAD = "Suggestions";
|
|
341
|
+
|
|
342
|
+
/** The line listing an OPEN select's offered values above its text prompt — a suggestion list, because an open select admits an answer the list does not offer. */
|
|
343
|
+
export declare function suggestionLine(styler: StylerInterface, theme: PromptTheme, choices: readonly FieldChoice[]): string;
|
|
273
344
|
|
|
274
345
|
/**
|
|
275
|
-
* The interactive terminal
|
|
276
|
-
*
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
* {@link import('@src/core').TerminalError} (`CANCEL`) on ctrl-c.
|
|
346
|
+
* The interactive terminal form DRIVER — the {@link TerminalInterface} implementation for a human at
|
|
347
|
+
* this machine's keyboard, and the only impure part of the terminal stack. {@link ask} walks one
|
|
348
|
+
* form's fields in schema order, feeds raw-mode stdin bytes through `parseKey` into the matching
|
|
349
|
+
* pure reducer, renders each returned view in place, and binds every answer through the form's own
|
|
350
|
+
* `fill`. It owns no form logic: the schema, the rules, the values, and the settlement all belong to
|
|
351
|
+
* the form it is given, and this class owns only raw mode, the cursor, and the re-render.
|
|
282
352
|
*
|
|
283
353
|
* @remarks
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
*
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
* - **
|
|
297
|
-
*
|
|
354
|
+
* See {@link TerminalInterface} for the driving contract. The walk itself:
|
|
355
|
+
*
|
|
356
|
+
* - **Twelve controls, seven reducers.** `text`, `number`, `date`, `time`, `datetime`, `color`, and
|
|
357
|
+
* each `file` entry are read as one line of text through {@link fieldToText}, which appends that
|
|
358
|
+
* control's format cue to the label. `password`, `confirm`, `editor`, `select`, and `checkbox`
|
|
359
|
+
* each drive their own reducer. An open `select` is a suggestion list plus a typed line, because
|
|
360
|
+
* `open` means the answer need not come from the list.
|
|
361
|
+
* - **The binding projects through `matchesAnswer`.** Every answer is filled as
|
|
362
|
+
* `fill(name, matchesAnswer(value) ? value : undefined)` after `parseValue` has coerced it to the
|
|
363
|
+
* control's own shape, so a bare return on a field with no default binds as ABSENCE and the
|
|
364
|
+
* form's `required` rule refuses it. A typed answer the control cannot hold binds as absence and
|
|
365
|
+
* invalidates the field, so the walk asks again with the reason on screen.
|
|
366
|
+
* - **Visibility is honored.** A `hidden` field and a field currently in `form.disabled` are
|
|
367
|
+
* skipped; a `locked` field renders read-only; entering a new group writes its label as a section
|
|
368
|
+
* header.
|
|
369
|
+
* - **Refusal re-asks.** After the walk the form is submitted. A refusal re-walks only the erroring
|
|
370
|
+
* fields the walk can edit and submits again. When every erroring field is one the walk cannot
|
|
371
|
+
* edit — hidden, locked, or disabled — the form is abandoned instead, because asking again could
|
|
372
|
+
* not change the answer.
|
|
373
|
+
* - **Raw-mode leak-free.** Raw mode is entered once per field and always cleaned up: on submit, on
|
|
374
|
+
* cancel, on a throw, and when the form is abandoned under an active read.
|
|
375
|
+
* - **Non-TTY fallback.** When `input` is not a TTY, the same walk runs over `node:readline` line
|
|
376
|
+
* input: `select` and `checkbox` print a numbered list, and `editor` reads to end of input.
|
|
298
377
|
*/
|
|
299
|
-
export declare
|
|
378
|
+
export declare class Terminal implements TerminalInterface {
|
|
379
|
+
#private;
|
|
380
|
+
constructor(options?: TerminalOptions);
|
|
381
|
+
ask(form: FormInterface): Promise<FormValues>;
|
|
300
382
|
}
|
|
301
383
|
|
|
302
384
|
/**
|
|
303
|
-
* Options for {@link import('./factories.js').createTerminal} —
|
|
304
|
-
* `createTerminal()`
|
|
385
|
+
* Options for {@link import('./factories.js').createTerminal} — every member optional, so a bare
|
|
386
|
+
* `createTerminal()` walks a form over the real `process.stdin` / `process.stdout` with the default
|
|
387
|
+
* theme.
|
|
305
388
|
*
|
|
306
389
|
* @remarks
|
|
307
390
|
* - `input` — the stream keystrokes are read from; defaults to `process.stdin`. Any
|
|
308
|
-
* {@link InputStreamInterface}-shaped stream is accepted
|
|
309
|
-
* {@link import('./helpers.js').isInputStream},
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
* -
|
|
313
|
-
* {@link
|
|
314
|
-
*
|
|
391
|
+
* {@link InputStreamInterface}-shaped stream is accepted, resolved through
|
|
392
|
+
* {@link import('./helpers.js').isInputStream}, so a test injects a fake TTY that emits scripted
|
|
393
|
+
* `'data'` chunks. A stream that is not a TTY falls back to `node:readline` line input.
|
|
394
|
+
* - `output` — the stream each view is rendered to; defaults to `process.stdout`. Any
|
|
395
|
+
* {@link OutputStreamInterface}-shaped stream is accepted, resolved through
|
|
396
|
+
* {@link import('./helpers.js').isOutputStream}, so a test records the rendered output.
|
|
397
|
+
* - `theme` — the glyphs and role styles every rendered line is painted with, merged over
|
|
398
|
+
* {@link import('@src/core').DEFAULT_PROMPT_THEME} leaf by leaf by
|
|
399
|
+
* {@link import('@src/core').createPromptTheme}. Supplying one icon or one role leaves every
|
|
400
|
+
* other slot at its default.
|
|
315
401
|
*/
|
|
316
402
|
export declare interface TerminalOptions {
|
|
317
403
|
readonly input?: InputStreamInterface;
|
|
318
404
|
readonly output?: OutputStreamInterface;
|
|
405
|
+
readonly theme?: PromptThemeOptions;
|
|
319
406
|
}
|
|
320
407
|
|
|
408
|
+
/** The lead on the line listing the choices a `select` or `checkbox` shows but refuses, so a reader sees why one is missing from the list below. */
|
|
409
|
+
export declare const UNAVAILABLE_LEAD = "Unavailable";
|
|
410
|
+
|
|
411
|
+
/** The line naming the choices a field shows but refuses, written above the list the walk drives. */
|
|
412
|
+
export declare function unavailableLine(styler: StylerInterface, theme: PromptTheme, choices: readonly FieldChoice[]): string;
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Project one held answer into the text a read-only line shows — a scalar as itself, a boolean as
|
|
416
|
+
* `yes` / `no` (the word the confirm reducer commits), and a list joined by commas. Absence renders
|
|
417
|
+
* as nothing, because a locked field nobody has answered has nothing to show.
|
|
418
|
+
*
|
|
419
|
+
* @param value - The answer the form holds for a field, or absence
|
|
420
|
+
* @returns The text to render for it
|
|
421
|
+
*/
|
|
422
|
+
export declare function valueToText(value: FieldValue | undefined): string;
|
|
423
|
+
|
|
321
424
|
export { }
|