@promptctl/rich-js 0.17.0 → 0.18.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/README.md +13 -26
- package/package.json +7 -3
- package/dist/core/box.d.ts +0 -144
- package/dist/core/box.js +0 -391
- package/dist/core/cells.d.ts +0 -148
- package/dist/core/cells.js +0 -266
- package/dist/core/color.d.ts +0 -250
- package/dist/core/color.js +0 -1029
- package/dist/core/console.d.ts +0 -156
- package/dist/core/console.js +0 -472
- package/dist/core/emoji.d.ts +0 -24
- package/dist/core/emoji.js +0 -391
- package/dist/core/export-html.d.ts +0 -24
- package/dist/core/export-html.js +0 -106
- package/dist/core/export-lines.d.ts +0 -121
- package/dist/core/export-lines.js +0 -141
- package/dist/core/highlighter.d.ts +0 -33
- package/dist/core/highlighter.js +0 -124
- package/dist/core/json.d.ts +0 -27
- package/dist/core/json.js +0 -53
- package/dist/core/markup.d.ts +0 -97
- package/dist/core/markup.js +0 -619
- package/dist/core/measure.d.ts +0 -27
- package/dist/core/measure.js +0 -61
- package/dist/core/oklch.d.ts +0 -161
- package/dist/core/oklch.js +0 -312
- package/dist/core/osc8.d.ts +0 -68
- package/dist/core/osc8.js +0 -90
- package/dist/core/pretty.d.ts +0 -141
- package/dist/core/pretty.js +0 -472
- package/dist/core/protocol.d.ts +0 -137
- package/dist/core/protocol.js +0 -101
- package/dist/core/render.d.ts +0 -84
- package/dist/core/render.js +0 -145
- package/dist/core/segment.d.ts +0 -142
- package/dist/core/segment.js +0 -433
- package/dist/core/spinnerData.d.ts +0 -10
- package/dist/core/spinnerData.js +0 -115
- package/dist/core/strip.d.ts +0 -145
- package/dist/core/strip.js +0 -308
- package/dist/core/style.d.ts +0 -144
- package/dist/core/style.js +0 -723
- package/dist/core/subscription.d.ts +0 -12
- package/dist/core/subscription.js +0 -12
- package/dist/core/text.d.ts +0 -255
- package/dist/core/text.js +0 -990
- package/dist/core/wrap.d.ts +0 -41
- package/dist/core/wrap.js +0 -127
- package/dist/host/host-stream.d.ts +0 -30
- package/dist/host/host-stream.js +0 -35
- package/dist/host/index.d.ts +0 -3
- package/dist/host/index.js +0 -2
- package/dist/host/terminal-host.d.ts +0 -143
- package/dist/host/terminal-host.js +0 -132
- package/dist/index.d.ts +0 -87
- package/dist/index.js +0 -104
- package/dist/node/prompt.d.ts +0 -21
- package/dist/node/prompt.js +0 -30
- package/dist/node/save.d.ts +0 -17
- package/dist/node/save.js +0 -21
- package/dist/node/terminal-host.d.ts +0 -84
- package/dist/node/terminal-host.js +0 -160
- package/dist/node/traceback.d.ts +0 -27
- package/dist/node/traceback.js +0 -112
- package/dist/renderables/align.d.ts +0 -16
- package/dist/renderables/align.js +0 -46
- package/dist/renderables/columns.d.ts +0 -61
- package/dist/renderables/columns.js +0 -168
- package/dist/renderables/constrain.d.ts +0 -15
- package/dist/renderables/constrain.js +0 -37
- package/dist/renderables/flexStrip.d.ts +0 -41
- package/dist/renderables/flexStrip.js +0 -200
- package/dist/renderables/group.d.ts +0 -11
- package/dist/renderables/group.js +0 -15
- package/dist/renderables/layout.d.ts +0 -92
- package/dist/renderables/layout.js +0 -315
- package/dist/renderables/live.d.ts +0 -47
- package/dist/renderables/live.js +0 -131
- package/dist/renderables/markdown.d.ts +0 -24
- package/dist/renderables/markdown.js +0 -182
- package/dist/renderables/padding.d.ts +0 -38
- package/dist/renderables/padding.js +0 -140
- package/dist/renderables/panel.d.ts +0 -116
- package/dist/renderables/panel.js +0 -322
- package/dist/renderables/progress.d.ts +0 -90
- package/dist/renderables/progress.js +0 -241
- package/dist/renderables/progressBar.d.ts +0 -31
- package/dist/renderables/progressBar.js +0 -52
- package/dist/renderables/prompt.d.ts +0 -49
- package/dist/renderables/prompt.js +0 -125
- package/dist/renderables/rule.d.ts +0 -24
- package/dist/renderables/rule.js +0 -90
- package/dist/renderables/spinner.d.ts +0 -29
- package/dist/renderables/spinner.js +0 -64
- package/dist/renderables/status.d.ts +0 -23
- package/dist/renderables/status.js +0 -60
- package/dist/renderables/syntax.d.ts +0 -35
- package/dist/renderables/syntax.js +0 -114
- package/dist/renderables/table.d.ts +0 -182
- package/dist/renderables/table.js +0 -697
- package/dist/renderables/traceback.d.ts +0 -31
- package/dist/renderables/traceback.js +0 -109
- package/dist/renderables/tree.d.ts +0 -54
- package/dist/renderables/tree.js +0 -159
- package/dist/template-bindings/color-funcs.d.ts +0 -87
- package/dist/template-bindings/color-funcs.js +0 -219
- package/dist/template-bindings/helpers.d.ts +0 -24
- package/dist/template-bindings/helpers.js +0 -48
- package/dist/template-bindings/index.d.ts +0 -107
- package/dist/template-bindings/index.js +0 -144
- package/dist/template-bindings/palette-funcs.d.ts +0 -94
- package/dist/template-bindings/palette-funcs.js +0 -151
- package/dist/template-bindings/style-funcs.d.ts +0 -28
- package/dist/template-bindings/style-funcs.js +0 -151
- package/dist/themes/buildPalette.d.ts +0 -36
- package/dist/themes/buildPalette.js +0 -56
- package/dist/themes/colorMath.d.ts +0 -82
- package/dist/themes/colorMath.js +0 -254
- package/dist/themes/colorRef.d.ts +0 -51
- package/dist/themes/colorRef.js +0 -96
- package/dist/themes/data/atom-one-dark.d.ts +0 -3
- package/dist/themes/data/atom-one-dark.js +0 -158
- package/dist/themes/data/atom-one-light.d.ts +0 -3
- package/dist/themes/data/atom-one-light.js +0 -158
- package/dist/themes/data/catppuccin-frappe.d.ts +0 -3
- package/dist/themes/data/catppuccin-frappe.js +0 -158
- package/dist/themes/data/catppuccin-latte.d.ts +0 -3
- package/dist/themes/data/catppuccin-latte.js +0 -158
- package/dist/themes/data/catppuccin-macchiato.d.ts +0 -3
- package/dist/themes/data/catppuccin-macchiato.js +0 -158
- package/dist/themes/data/catppuccin-mocha.d.ts +0 -3
- package/dist/themes/data/catppuccin-mocha.js +0 -158
- package/dist/themes/data/cyberpunk.d.ts +0 -17
- package/dist/themes/data/cyberpunk.js +0 -191
- package/dist/themes/data/default.d.ts +0 -3
- package/dist/themes/data/default.js +0 -158
- package/dist/themes/data/dracula.d.ts +0 -3
- package/dist/themes/data/dracula.js +0 -158
- package/dist/themes/data/flexoki.d.ts +0 -3
- package/dist/themes/data/flexoki.js +0 -158
- package/dist/themes/data/gruvbox.d.ts +0 -3
- package/dist/themes/data/gruvbox.js +0 -158
- package/dist/themes/data/index.d.ts +0 -35
- package/dist/themes/data/index.js +0 -64
- package/dist/themes/data/monokai.d.ts +0 -3
- package/dist/themes/data/monokai.js +0 -158
- package/dist/themes/data/nord.d.ts +0 -3
- package/dist/themes/data/nord.js +0 -158
- package/dist/themes/data/rose-pine-dawn.d.ts +0 -3
- package/dist/themes/data/rose-pine-dawn.js +0 -158
- package/dist/themes/data/rose-pine-moon.d.ts +0 -3
- package/dist/themes/data/rose-pine-moon.js +0 -158
- package/dist/themes/data/rose-pine.d.ts +0 -3
- package/dist/themes/data/rose-pine.js +0 -158
- package/dist/themes/data/solarized-dark.d.ts +0 -3
- package/dist/themes/data/solarized-dark.js +0 -158
- package/dist/themes/data/solarized-light.d.ts +0 -3
- package/dist/themes/data/solarized-light.js +0 -158
- package/dist/themes/data/svg-export.d.ts +0 -3
- package/dist/themes/data/svg-export.js +0 -158
- package/dist/themes/data/textual-ansi.d.ts +0 -3
- package/dist/themes/data/textual-ansi.js +0 -158
- package/dist/themes/data/textual-dark.d.ts +0 -3
- package/dist/themes/data/textual-dark.js +0 -158
- package/dist/themes/data/textual-light.d.ts +0 -3
- package/dist/themes/data/textual-light.js +0 -158
- package/dist/themes/data/tokyo-night.d.ts +0 -3
- package/dist/themes/data/tokyo-night.js +0 -158
- package/dist/themes/data/types.d.ts +0 -15
- package/dist/themes/data/types.js +0 -1
- package/dist/themes/palette.d.ts +0 -21
- package/dist/themes/palette.js +0 -28
- package/dist/themes/ramp.d.ts +0 -83
- package/dist/themes/ramp.js +0 -122
- package/dist/themes/registry.d.ts +0 -43
- package/dist/themes/registry.js +0 -82
- package/dist/themes/terminalThemes.d.ts +0 -54
- package/dist/themes/terminalThemes.js +0 -68
- package/dist/themes/transpose.d.ts +0 -87
- package/dist/themes/transpose.js +0 -138
- package/dist/widgets/button.d.ts +0 -49
- package/dist/widgets/button.js +0 -206
- package/dist/widgets/checkbox.d.ts +0 -41
- package/dist/widgets/checkbox.js +0 -155
- package/dist/widgets/dropdown.d.ts +0 -67
- package/dist/widgets/dropdown.js +0 -453
- package/dist/widgets/event-router.d.ts +0 -78
- package/dist/widgets/event-router.js +0 -622
- package/dist/widgets/focus-manager.d.ts +0 -26
- package/dist/widgets/focus-manager.js +0 -193
- package/dist/widgets/index.d.ts +0 -22
- package/dist/widgets/index.js +0 -15
- package/dist/widgets/screen.d.ts +0 -98
- package/dist/widgets/screen.js +0 -530
- package/dist/widgets/slider.d.ts +0 -57
- package/dist/widgets/slider.js +0 -270
- package/dist/widgets/static-item.d.ts +0 -40
- package/dist/widgets/static-item.js +0 -60
- package/dist/widgets/text-input.d.ts +0 -274
- package/dist/widgets/text-input.js +0 -1162
- package/dist/widgets/toggle.d.ts +0 -44
- package/dist/widgets/toggle.js +0 -179
- package/dist/widgets/types.d.ts +0 -108
- package/dist/widgets/types.js +0 -31
- package/dist/widgets/widget-base.d.ts +0 -42
- package/dist/widgets/widget-base.js +0 -173
package/dist/core/console.d.ts
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Console — the central orchestrator for rendering styled output to the terminal.
|
|
3
|
-
*/
|
|
4
|
-
import { Style, Theme } from "./style.js";
|
|
5
|
-
import { ColorDepth } from "./color.js";
|
|
6
|
-
import type { Destination } from "./color.js";
|
|
7
|
-
import type { TerminalTheme } from "./color.js";
|
|
8
|
-
import { type JSONOptions } from "./json.js";
|
|
9
|
-
import type { Highlighter } from "./highlighter.js";
|
|
10
|
-
import { type RuleOptions } from "../renderables/rule.js";
|
|
11
|
-
import type { RenderOptions, StyleErrorHandler } from "./protocol.js";
|
|
12
|
-
export interface ConsoleSink {
|
|
13
|
-
write(chunk: string | Uint8Array): unknown;
|
|
14
|
-
}
|
|
15
|
-
export interface ConsoleStream extends ConsoleSink {
|
|
16
|
-
readonly isTTY?: boolean;
|
|
17
|
-
readonly columns?: number;
|
|
18
|
-
readonly rows?: number;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* The host facilities a `Console` consults: an environment map and the two
|
|
22
|
-
* standard streams. Node's `process` satisfies this shape as-is, which is the
|
|
23
|
-
* point — injecting a fake terminal needs no adapter at either end.
|
|
24
|
-
*/
|
|
25
|
-
export interface ConsoleEnvironment {
|
|
26
|
-
readonly env: NodeJS.ProcessEnv;
|
|
27
|
-
readonly stdout?: ConsoleStream;
|
|
28
|
-
readonly stderr?: ConsoleStream;
|
|
29
|
-
}
|
|
30
|
-
export interface ConsoleOptions {
|
|
31
|
-
/**
|
|
32
|
-
* Color encoding. Accepts a string spec (`"auto"`, `"truecolor"`, `"256"`,
|
|
33
|
-
* `"ansi"`, `"none"`), a `ColorDepth` enum value (use this for `WINDOWS`,
|
|
34
|
-
* which has no string spec), or `null` for no color. Default `"auto"`.
|
|
35
|
-
* Colour only: an explicit depth, `null` included, keeps hyperlinks.
|
|
36
|
-
*/
|
|
37
|
-
colorSystem?: string | ColorDepth | null;
|
|
38
|
-
/**
|
|
39
|
-
* Whether OSC 8 hyperlinks are emitted. Default: what the destination takes
|
|
40
|
-
* — true for an explicit `colorSystem`, detected under `"auto"` (no TTY or
|
|
41
|
-
* TERM=dumb: false). `false` with `colorSystem: null` writes plain text.
|
|
42
|
-
*/
|
|
43
|
-
hyperlinks?: boolean;
|
|
44
|
-
/**
|
|
45
|
-
* Static width (cells). Ignored when `getSize` is provided. Falls back to
|
|
46
|
-
* the `COLUMNS` env var / the bound stream's `columns` / 80.
|
|
47
|
-
*/
|
|
48
|
-
width?: number;
|
|
49
|
-
/**
|
|
50
|
-
* Static height (lines). Ignored when `getSize` is provided. Falls back to
|
|
51
|
-
* the `LINES` env var / the bound stream's `rows` / 24.
|
|
52
|
-
*/
|
|
53
|
-
height?: number;
|
|
54
|
-
/**
|
|
55
|
-
* Live size source. When provided, the console reads its width/height from
|
|
56
|
-
* this function on every access, overriding any static `width`/`height` and
|
|
57
|
-
* the bound stream's dimensions. Pass this when the output target's
|
|
58
|
-
* dimensions can change at runtime (e.g. xterm.js in a browser).
|
|
59
|
-
*
|
|
60
|
-
* [LAW:dataflow-not-control-flow] Live size is a function value the
|
|
61
|
-
* console reads, not a branch the call site has to install via
|
|
62
|
-
* `Object.defineProperty`.
|
|
63
|
-
*/
|
|
64
|
-
getSize?: () => {
|
|
65
|
-
width: number;
|
|
66
|
-
height: number;
|
|
67
|
-
};
|
|
68
|
-
style?: string | Style;
|
|
69
|
-
forceTerminal?: boolean;
|
|
70
|
-
forceInteractive?: boolean;
|
|
71
|
-
stderr?: boolean;
|
|
72
|
-
file?: ConsoleSink;
|
|
73
|
-
/**
|
|
74
|
-
* Host facilities to consult for colour detection, size detection, and the
|
|
75
|
-
* default output sink. Defaults to the ambient `process`, or — where there
|
|
76
|
-
* is no `process` — an empty environment with no streams. Pass this to drive
|
|
77
|
-
* a `Console` deterministically, or to run one against a simulated terminal.
|
|
78
|
-
*/
|
|
79
|
-
environment?: ConsoleEnvironment;
|
|
80
|
-
record?: boolean;
|
|
81
|
-
markup?: boolean;
|
|
82
|
-
highlight?: boolean;
|
|
83
|
-
theme?: Theme;
|
|
84
|
-
highlighter?: Highlighter;
|
|
85
|
-
/**
|
|
86
|
-
* Called each time a render resolves a style string it cannot parse — a
|
|
87
|
-
* misspelled name, a key the theme lacks — and degrades it to unstyled.
|
|
88
|
-
* Calls are per resolution, not per distinct string: a style read twice, or
|
|
89
|
-
* redrawn by a refresh, is reported again. Throw from it to make rendering
|
|
90
|
-
* strict.
|
|
91
|
-
*/
|
|
92
|
-
onStyleError?: StyleErrorHandler;
|
|
93
|
-
}
|
|
94
|
-
export interface PrintOptions {
|
|
95
|
-
style?: string | Style;
|
|
96
|
-
justify?: "default" | "left" | "center" | "right" | "full";
|
|
97
|
-
overflow?: "fold" | "crop" | "ellipsis" | "ignore";
|
|
98
|
-
highlight?: boolean;
|
|
99
|
-
markup?: boolean;
|
|
100
|
-
softWrap?: boolean;
|
|
101
|
-
crop?: boolean;
|
|
102
|
-
end?: string;
|
|
103
|
-
sep?: string;
|
|
104
|
-
}
|
|
105
|
-
export declare class Console {
|
|
106
|
-
private readonly _destination;
|
|
107
|
-
private _getSize;
|
|
108
|
-
private _style;
|
|
109
|
-
private _isTerminal;
|
|
110
|
-
private _forceInteractive;
|
|
111
|
-
private _file;
|
|
112
|
-
private _stream;
|
|
113
|
-
private _record;
|
|
114
|
-
private _markup;
|
|
115
|
-
private _highlight;
|
|
116
|
-
private _theme;
|
|
117
|
-
private _onStyleError;
|
|
118
|
-
private _highlighter;
|
|
119
|
-
private _recorded;
|
|
120
|
-
private _capture;
|
|
121
|
-
constructor(options?: ConsoleOptions);
|
|
122
|
-
get size(): {
|
|
123
|
-
width: number;
|
|
124
|
-
height: number;
|
|
125
|
-
};
|
|
126
|
-
get width(): number;
|
|
127
|
-
get height(): number;
|
|
128
|
-
get encoding(): string;
|
|
129
|
-
get isTerminal(): boolean;
|
|
130
|
-
get isInteractive(): boolean;
|
|
131
|
-
get colorSystem(): ColorDepth | null;
|
|
132
|
-
/**
|
|
133
|
-
* Where this console writes: the colour depth it draws at and whether it
|
|
134
|
-
* emits OSC 8 hyperlinks, overrides applied — the value its output is
|
|
135
|
-
* encoded for, for anything that encodes on its behalf (`Live`).
|
|
136
|
-
*/
|
|
137
|
-
get destination(): Destination;
|
|
138
|
-
get file(): ConsoleSink;
|
|
139
|
-
get theme(): Theme;
|
|
140
|
-
get options(): RenderOptions;
|
|
141
|
-
print(...args: unknown[]): void;
|
|
142
|
-
log(...args: unknown[]): void;
|
|
143
|
-
rule(title?: string, options?: RuleOptions): void;
|
|
144
|
-
printJson(json: string | object, options?: JSONOptions): void;
|
|
145
|
-
beginCapture(): void;
|
|
146
|
-
endCapture(): string;
|
|
147
|
-
exportText({ clear }?: {
|
|
148
|
-
clear?: boolean;
|
|
149
|
-
}): string;
|
|
150
|
-
exportHtml({ theme, clear }?: {
|
|
151
|
-
theme?: TerminalTheme;
|
|
152
|
-
clear?: boolean;
|
|
153
|
-
}): string;
|
|
154
|
-
private _writeSegments;
|
|
155
|
-
private _write;
|
|
156
|
-
}
|
package/dist/core/console.js
DELETED
|
@@ -1,472 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Console — the central orchestrator for rendering styled output to the terminal.
|
|
3
|
-
*/
|
|
4
|
-
import { Segment } from "./segment.js";
|
|
5
|
-
import { NULL_STYLE, DEFAULT_THEME } from "./style.js";
|
|
6
|
-
import { resolveDestination } from "./color.js";
|
|
7
|
-
import { encodeHtml } from "./export-html.js";
|
|
8
|
-
import { RichText } from "./text.js";
|
|
9
|
-
import { renderMarkup } from "./markup.js";
|
|
10
|
-
import { Pretty } from "./pretty.js";
|
|
11
|
-
import { JSONRenderable } from "./json.js";
|
|
12
|
-
import { ReprHighlighter, NullHighlighter } from "./highlighter.js";
|
|
13
|
-
// [LAW:one-way-deps] exception: one of the two sanctioned upward edges out of
|
|
14
|
-
// `core/`, named in CLAUDE.md and pinned by `test/seam/layering.test.ts` — the
|
|
15
|
-
// orchestrator reaching down for `Rule`. `RuleOptions` rides the same edge
|
|
16
|
-
// rather than being restated here; see `rule()`.
|
|
17
|
-
import { Rule } from "../renderables/rule.js";
|
|
18
|
-
import { segmentsToString } from "./render.js";
|
|
19
|
-
import { isRenderable } from "./protocol.js";
|
|
20
|
-
// A host with an environment but no streams — what a browser looks like from
|
|
21
|
-
// here. Frozen so the shared instance cannot be mutated into a fake terminal.
|
|
22
|
-
const DETACHED_ENVIRONMENT = Object.freeze({
|
|
23
|
-
env: Object.freeze({}),
|
|
24
|
-
});
|
|
25
|
-
// [LAW:single-enforcer] The only read of the ambient `process` global in this
|
|
26
|
-
// module, and the reason every other function below takes its environment as
|
|
27
|
-
// an argument. `process` satisfies `ConsoleEnvironment` structurally, so the
|
|
28
|
-
// node path needs no adapter; the browser path degrades to a host that answers
|
|
29
|
-
// "no streams" rather than throwing at the reference.
|
|
30
|
-
function ambientEnvironment() {
|
|
31
|
-
return typeof process === "undefined" ? DETACHED_ENVIRONMENT : process;
|
|
32
|
-
}
|
|
33
|
-
// [LAW:one-source-of-truth] A console talks to exactly one stream, and every
|
|
34
|
-
// question it asks the host — are you a terminal, how wide are you, where do
|
|
35
|
-
// bytes go — is a question about *that* stream. Selecting it once, here, is
|
|
36
|
-
// what makes the three answers agree. When each site re-selected for itself,
|
|
37
|
-
// one of them (size) silently didn't, and a `Console({ stderr: true })` keyed
|
|
38
|
-
// its colour to stderr and its width to stdout.
|
|
39
|
-
function boundStream(environment, useStderr) {
|
|
40
|
-
return useStderr ? environment.stderr : environment.stdout;
|
|
41
|
-
}
|
|
42
|
-
// [LAW:single-enforcer] Effective TTY status of the console's output target is
|
|
43
|
-
// computed once, at construction, and cached — an explicit `file` is not a
|
|
44
|
-
// terminal, `forceTerminal` says it is regardless, and otherwise the bound
|
|
45
|
-
// stream answers. Every input is fixed at construction, so recomputing per
|
|
46
|
-
// read could only ever return the same answer twice.
|
|
47
|
-
function effectiveIsTTY(options, stream) {
|
|
48
|
-
if (options?.forceTerminal)
|
|
49
|
-
return true;
|
|
50
|
-
if (options?.file)
|
|
51
|
-
return false;
|
|
52
|
-
return stream?.isTTY ?? false;
|
|
53
|
-
}
|
|
54
|
-
function terminalSize(environment, stream) {
|
|
55
|
-
const cols = environment.env["COLUMNS"];
|
|
56
|
-
const lines = environment.env["LINES"];
|
|
57
|
-
const w = cols ? parseInt(cols, 10) : (stream?.columns ?? 80);
|
|
58
|
-
const h = lines ? parseInt(lines, 10) : (stream?.rows ?? 24);
|
|
59
|
-
return { width: w || 80, height: h || 24 };
|
|
60
|
-
}
|
|
61
|
-
// [LAW:single-enforcer] One trust-boundary check: when no `file:` was
|
|
62
|
-
// provided, the console writes to the stream it is bound to — which a browser
|
|
63
|
-
// host does not have. Without this, the absence would surface as a `TypeError`
|
|
64
|
-
// deep inside `_write`. Centralizing it here keeps both consumers (`file`
|
|
65
|
-
// getter, `_write`) behaving identically — no second copy of the check to
|
|
66
|
-
// drift.
|
|
67
|
-
function defaultSink(stream) {
|
|
68
|
-
if (stream === undefined) {
|
|
69
|
-
throw new Error("Console: no `file` provided and the environment has no stream to " +
|
|
70
|
-
"write to (e.g. running in a browser). Pass `file: hostStream(host)` " +
|
|
71
|
-
"or any other ConsoleSink so output has somewhere to go.");
|
|
72
|
-
}
|
|
73
|
-
return stream;
|
|
74
|
-
}
|
|
75
|
-
// [LAW:dataflow-not-control-flow] Build one size-reading function at
|
|
76
|
-
// construction time from whichever options the caller supplied. The width
|
|
77
|
-
// getter is then unconditional — it always calls `_getSize()`. Variability
|
|
78
|
-
// lives in the captured closure (which source it consults), not in branches
|
|
79
|
-
// the getter has to evaluate on every read.
|
|
80
|
-
//
|
|
81
|
-
// The all-static and mixed cases get *different* closures: when both
|
|
82
|
-
// dimensions are fixed, the returned function is a constant — no
|
|
83
|
-
// `terminalSize` call on every read, since neither value can change.
|
|
84
|
-
// When at least one dimension is dynamic, the closure consults
|
|
85
|
-
// `terminalSize` to fill in the missing side.
|
|
86
|
-
function resolveGetSize(options, environment, stream) {
|
|
87
|
-
if (options?.getSize)
|
|
88
|
-
return options.getSize;
|
|
89
|
-
const staticWidth = options?.width;
|
|
90
|
-
const staticHeight = options?.height;
|
|
91
|
-
if (staticWidth !== undefined && staticHeight !== undefined) {
|
|
92
|
-
// [LAW:one-source-of-truth] Freeze the captured object so consumers can't
|
|
93
|
-
// mutate `console.size` and silently change every subsequent read.
|
|
94
|
-
// Matches the dynamic-closure path (which builds a fresh object per call
|
|
95
|
-
// and is therefore implicitly immutable from a sharing standpoint).
|
|
96
|
-
const fixed = Object.freeze({ width: staticWidth, height: staticHeight });
|
|
97
|
-
return () => fixed;
|
|
98
|
-
}
|
|
99
|
-
return () => {
|
|
100
|
-
const term = terminalSize(environment, stream);
|
|
101
|
-
return {
|
|
102
|
-
width: staticWidth ?? term.width,
|
|
103
|
-
height: staticHeight ?? term.height,
|
|
104
|
-
};
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
// --- Console ---
|
|
108
|
-
/** Shared because it is stateless: highlighting nothing has nothing to own. */
|
|
109
|
-
const NO_HIGHLIGHT = new NullHighlighter();
|
|
110
|
-
/**
|
|
111
|
-
* What `print` bounds a data argument by when the caller said nothing.
|
|
112
|
-
*
|
|
113
|
-
* `print` formats whatever it is handed, so it is the one place that has to
|
|
114
|
-
* assume nothing about the value's size, in any of the three ways a value can
|
|
115
|
-
* be large. Unbounded, `print(buffer)` emits a line per byte,
|
|
116
|
-
* `print(deeplyNested)` descends until the stack gives out, and a single
|
|
117
|
-
* response body assigned to a field arrives in full — each of them a debug line
|
|
118
|
-
* that costs megabytes or hangs the terminal. All three bounds announce
|
|
119
|
-
* themselves in the output (`... +N`, `{...}`, `+N` after the closing quote),
|
|
120
|
-
* so this truncates visibly and never silently. [LAW:no-silent-failure]
|
|
121
|
-
*
|
|
122
|
-
* `maxString` reaches only strings nested inside data; a string argument is
|
|
123
|
-
* printed by the arm above, where the caller asked for that string by name.
|
|
124
|
-
*
|
|
125
|
-
* A caller constructing a `Pretty` has seen their data and gets no defaults;
|
|
126
|
-
* these belong to the convenience path, not to the formatter.
|
|
127
|
-
*/
|
|
128
|
-
const PRINT_DATA_BOUNDS = { maxLength: 100, maxDepth: 16, maxString: 1000 };
|
|
129
|
-
export class Console {
|
|
130
|
-
_destination;
|
|
131
|
-
// [LAW:one-source-of-truth] Size flows through a single function. Static
|
|
132
|
-
// `width`/`height` options collapse into a closure that returns them; a
|
|
133
|
-
// caller-supplied `getSize` overrides. Every size read in this class goes
|
|
134
|
-
// through `_getSize()` — no second path, no second source to drift.
|
|
135
|
-
_getSize;
|
|
136
|
-
_style;
|
|
137
|
-
_isTerminal;
|
|
138
|
-
_forceInteractive;
|
|
139
|
-
_file;
|
|
140
|
-
// [LAW:one-source-of-truth] The resolved output stream, not the `stderr`
|
|
141
|
-
// flag that selected it. Storing the answer instead of the question is what
|
|
142
|
-
// stops `isTerminal`, `size`, and `file` from re-deriving it three ways.
|
|
143
|
-
_stream;
|
|
144
|
-
_record;
|
|
145
|
-
_markup;
|
|
146
|
-
_highlight;
|
|
147
|
-
_theme;
|
|
148
|
-
_onStyleError;
|
|
149
|
-
_highlighter;
|
|
150
|
-
_recorded;
|
|
151
|
-
// [LAW:types-are-the-program] The capture state is carried in the *type*
|
|
152
|
-
// of this field, not in a sentinel value. `null` = not capturing; any
|
|
153
|
-
// string (including "") = capturing, this is the buffer. A paired
|
|
154
|
-
// boolean+string would admit the impossible state "not capturing, buffer
|
|
155
|
-
// non-empty" — `string | null` makes that unrepresentable.
|
|
156
|
-
_capture;
|
|
157
|
-
constructor(options) {
|
|
158
|
-
const environment = options?.environment ?? ambientEnvironment();
|
|
159
|
-
const stream = boundStream(environment, options?.stderr ?? false);
|
|
160
|
-
this._stream = stream;
|
|
161
|
-
this._isTerminal = effectiveIsTTY(options, stream);
|
|
162
|
-
// [LAW:dataflow-not-control-flow] `isTTY` and `env` are forwarded
|
|
163
|
-
// unconditionally, so detection stays inside the console's injected
|
|
164
|
-
// environment rather than the ambient process's.
|
|
165
|
-
const resolved = resolveDestination(options?.colorSystem === undefined ? "auto" : options.colorSystem, { isTTY: this._isTerminal, env: environment.env });
|
|
166
|
-
// [LAW:single-enforcer] The console's one override, an explicit
|
|
167
|
-
// `hyperlinks`, is applied here and nowhere else; every write encodes for
|
|
168
|
-
// this value whole.
|
|
169
|
-
this._destination = {
|
|
170
|
-
colorSystem: resolved.colorSystem,
|
|
171
|
-
hyperlinks: options?.hyperlinks ?? resolved.hyperlinks,
|
|
172
|
-
};
|
|
173
|
-
this._getSize = resolveGetSize(options, environment, stream);
|
|
174
|
-
// [LAW:no-ambient-temporal-coupling] The theme is assigned before the
|
|
175
|
-
// style, because the console's own style may be one of the theme's names.
|
|
176
|
-
this._theme = options?.theme ?? DEFAULT_THEME;
|
|
177
|
-
this._style = this._theme.resolve(options?.style ?? NULL_STYLE);
|
|
178
|
-
this._forceInteractive = options?.forceInteractive;
|
|
179
|
-
this._file = options?.file;
|
|
180
|
-
this._record = options?.record ?? false;
|
|
181
|
-
this._markup = options?.markup !== false;
|
|
182
|
-
this._highlight = options?.highlight !== false;
|
|
183
|
-
this._highlighter = options?.highlighter ?? new ReprHighlighter();
|
|
184
|
-
this._onStyleError = options?.onStyleError;
|
|
185
|
-
this._recorded = [];
|
|
186
|
-
this._capture = null;
|
|
187
|
-
}
|
|
188
|
-
// --- Properties ---
|
|
189
|
-
get size() {
|
|
190
|
-
return this._getSize();
|
|
191
|
-
}
|
|
192
|
-
get width() {
|
|
193
|
-
return this._getSize().width;
|
|
194
|
-
}
|
|
195
|
-
get height() {
|
|
196
|
-
return this._getSize().height;
|
|
197
|
-
}
|
|
198
|
-
get encoding() {
|
|
199
|
-
return "utf-8";
|
|
200
|
-
}
|
|
201
|
-
get isTerminal() {
|
|
202
|
-
return this._isTerminal;
|
|
203
|
-
}
|
|
204
|
-
get isInteractive() {
|
|
205
|
-
if (this._forceInteractive !== undefined)
|
|
206
|
-
return this._forceInteractive;
|
|
207
|
-
return this.isTerminal;
|
|
208
|
-
}
|
|
209
|
-
get colorSystem() {
|
|
210
|
-
return this._destination.colorSystem;
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* Where this console writes: the colour depth it draws at and whether it
|
|
214
|
-
* emits OSC 8 hyperlinks, overrides applied — the value its output is
|
|
215
|
-
* encoded for, for anything that encodes on its behalf (`Live`).
|
|
216
|
-
*/
|
|
217
|
-
get destination() {
|
|
218
|
-
return this._destination;
|
|
219
|
-
}
|
|
220
|
-
// [LAW:one-source-of-truth] Output target lookup matches `_write`'s:
|
|
221
|
-
// explicit `file` wins, otherwise `defaultSink` returns the bound stream
|
|
222
|
-
// (or throws clearly when the environment has none). Exposed
|
|
223
|
-
// so renderables that bypass the segment pipeline (e.g. Live's raw control
|
|
224
|
-
// sequences) still write to the caller's configured stream. Return type is
|
|
225
|
-
// the narrow `ConsoleSink` — Live (and any external consumer) only needs
|
|
226
|
-
// `.write()`, so the type tells the truth about what the surface guarantees.
|
|
227
|
-
get file() {
|
|
228
|
-
return this._file ?? defaultSink(this._stream);
|
|
229
|
-
}
|
|
230
|
-
get theme() {
|
|
231
|
-
return this._theme;
|
|
232
|
-
}
|
|
233
|
-
get options() {
|
|
234
|
-
return {
|
|
235
|
-
maxWidth: this.width,
|
|
236
|
-
isTerminal: this.isTerminal,
|
|
237
|
-
encoding: this.encoding,
|
|
238
|
-
asciiOnly: false,
|
|
239
|
-
theme: this._theme,
|
|
240
|
-
onStyleError: this._onStyleError,
|
|
241
|
-
colorSystem: this._destination.colorSystem,
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
// --- Print ---
|
|
245
|
-
print(...args) {
|
|
246
|
-
// Extract options from last arg if it's a PrintOptions
|
|
247
|
-
let opts = {};
|
|
248
|
-
let items;
|
|
249
|
-
// The trailing options object is only recognised when something precedes
|
|
250
|
-
// it. A lone object is data — `print({ style: "..." })` reads as a value to
|
|
251
|
-
// format, and treating it as options would emit an empty line, which is the
|
|
252
|
-
// one outcome this method must never produce. Nothing is given up: options
|
|
253
|
-
// configure the rendering of content, so a call carrying options and no
|
|
254
|
-
// content had nothing to render either way. [LAW:no-silent-failure]
|
|
255
|
-
const lastArg = args[args.length - 1];
|
|
256
|
-
if (args.length > 1 &&
|
|
257
|
-
typeof lastArg === "object" &&
|
|
258
|
-
lastArg !== null &&
|
|
259
|
-
!isRenderable(lastArg) &&
|
|
260
|
-
("style" in lastArg || "justify" in lastArg || "markup" in lastArg ||
|
|
261
|
-
"highlight" in lastArg || "overflow" in lastArg || "end" in lastArg ||
|
|
262
|
-
"softWrap" in lastArg || "crop" in lastArg || "sep" in lastArg)) {
|
|
263
|
-
opts = lastArg;
|
|
264
|
-
items = args.slice(0, -1);
|
|
265
|
-
}
|
|
266
|
-
else {
|
|
267
|
-
items = args;
|
|
268
|
-
}
|
|
269
|
-
const doMarkup = opts.markup ?? this._markup;
|
|
270
|
-
const doHighlight = opts.highlight ?? this._highlight;
|
|
271
|
-
const sep = opts.sep ?? " ";
|
|
272
|
-
const end = opts.end ?? "\n";
|
|
273
|
-
const softWrap = opts.softWrap ?? false;
|
|
274
|
-
const printStyle = this._theme.resolve(opts.style ?? NULL_STYLE);
|
|
275
|
-
// A print is a column of blocks, and every argument joins one of two kinds.
|
|
276
|
-
// Text — a string, a `RichText`, or data — runs together: adjacent text
|
|
277
|
-
// items are one block, joined by `sep` and ended by `end`. Any other
|
|
278
|
-
// renderable is a block of its own that occupies whole lines, so neither
|
|
279
|
-
// `sep` nor `end` ever touches it. That is the reference's split — `end`
|
|
280
|
-
// belongs to text, not to the print — and it is what lets two printed panels
|
|
281
|
-
// stack with no blank line between them. The one place the reference cuts
|
|
282
|
-
// differently is data: it gives a container lines of its own, and here all
|
|
283
|
-
// data is text. The line is not closed by asking where the cursor sits:
|
|
284
|
-
// `print("a\n")` is a line and an empty one, here as in the reference and
|
|
285
|
-
// in every other `print`, and only the kind of the item can tell that
|
|
286
|
-
// trailing break from a `Panel`'s. A call with nothing to print is one
|
|
287
|
-
// empty text run, so it still ends the line.
|
|
288
|
-
const blocks = items.length === 0 ? [{ kind: "text", items: [] }] : [];
|
|
289
|
-
for (const item of items) {
|
|
290
|
-
// Four arms, and they are the whole domain. A `RichText` is already text;
|
|
291
|
-
// it runs as a copy with its own `end` cleared, as a string's is, because
|
|
292
|
-
// the line end of a run is the print's. Any other renderable draws itself,
|
|
293
|
-
// as a block. A string is the only kind of argument that can *contain*
|
|
294
|
-
// markup, so it is the only kind the markup dialect is applied to.
|
|
295
|
-
// Everything else is data, and `Pretty` is the single authority on how a
|
|
296
|
-
// JavaScript value displays — `String(value)` was a second, weaker one
|
|
297
|
-
// that answered `[object Object]` for every object and let the markup
|
|
298
|
-
// parser eat it. [LAW:one-source-of-truth]
|
|
299
|
-
let text;
|
|
300
|
-
if (item instanceof RichText) {
|
|
301
|
-
const richText = item.copy();
|
|
302
|
-
richText.end = "";
|
|
303
|
-
text = richText;
|
|
304
|
-
}
|
|
305
|
-
else if (isRenderable(item)) {
|
|
306
|
-
blocks.push({ kind: "lines", renderable: item });
|
|
307
|
-
continue;
|
|
308
|
-
}
|
|
309
|
-
else if (typeof item === "string") {
|
|
310
|
-
const richText = doMarkup ? renderMarkup(item) : new RichText(item);
|
|
311
|
-
richText.end = "";
|
|
312
|
-
if (doHighlight) {
|
|
313
|
-
this._highlighter.highlight(richText);
|
|
314
|
-
}
|
|
315
|
-
text = richText;
|
|
316
|
-
}
|
|
317
|
-
else {
|
|
318
|
-
// The highlighter travels with the value. `highlight` and a custom
|
|
319
|
-
// `highlighter` are console-wide settings, so they have to reach a
|
|
320
|
-
// formatted object the same way they reach a printed string; a `Pretty`
|
|
321
|
-
// left to its own default would outrank both. [LAW:dataflow-not-control-flow]
|
|
322
|
-
// the disabled case is an identity highlighter, not a skipped call.
|
|
323
|
-
// Indent guides are styling too, and travel with the same decision —
|
|
324
|
-
// the console owns what `highlight` means for everything it emits,
|
|
325
|
-
// rather than `Pretty` inferring it back out of the highlighter.
|
|
326
|
-
text = new Pretty(item, {
|
|
327
|
-
...PRINT_DATA_BOUNDS,
|
|
328
|
-
highlighter: doHighlight ? this._highlighter : NO_HIGHLIGHT,
|
|
329
|
-
indentGuides: doHighlight,
|
|
330
|
-
});
|
|
331
|
-
}
|
|
332
|
-
const run = blocks.at(-1);
|
|
333
|
-
if (run?.kind === "text")
|
|
334
|
-
run.items.push(new RichText(sep, { end: "" }), text);
|
|
335
|
-
else
|
|
336
|
-
blocks.push({ kind: "text", items: [text] });
|
|
337
|
-
}
|
|
338
|
-
// [LAW:parse-dont-validate] `"ignore"` is not a way of cutting a line but
|
|
339
|
-
// the absence of an edge to cut at: no break, and nothing cut at the width.
|
|
340
|
-
// That is what `noWrap` already means to `RichText`, so it crosses into the
|
|
341
|
-
// render as `noWrap`, and `overflow` carries only the methods a renderable
|
|
342
|
-
// applies. Soft wrap is the same request — the reference defaults it to
|
|
343
|
-
// `"ignore"` — which is why the two arrive at one field.
|
|
344
|
-
const renderOpts = {
|
|
345
|
-
...this.options,
|
|
346
|
-
justify: opts.justify === "default" ? undefined : opts.justify,
|
|
347
|
-
overflow: opts.overflow === "ignore" ? undefined : opts.overflow,
|
|
348
|
-
noWrap: softWrap || opts.overflow === "ignore",
|
|
349
|
-
};
|
|
350
|
-
// The print style, then the console's base style, over what each block drew
|
|
351
|
-
// and not over the line ends added below: a styled break carries SGR codes
|
|
352
|
-
// across the newline.
|
|
353
|
-
// [LAW:dataflow-not-control-flow] no style to apply is an empty list, not
|
|
354
|
-
// a skipped step.
|
|
355
|
-
const styles = [printStyle, this._style].filter((style) => !style.isNull);
|
|
356
|
-
const styleContent = (segments) => styles.reduce((styled, style) => Segment.applyStyle(styled, style), segments);
|
|
357
|
-
// Every line end goes through the same writeSegments funnel as the text it
|
|
358
|
-
// ends, so it survives recording — otherwise `exportText` and `exportHtml`
|
|
359
|
-
// would join consecutive prints onto a single line. [LAW:single-enforcer]
|
|
360
|
-
// The common default end is "\n" — reuse Segment's cached newline rather
|
|
361
|
-
// than allocating one per print; only a non-default end needs a fresh one.
|
|
362
|
-
const terminator = end === "\n" ? Segment.line() : new Segment(end);
|
|
363
|
-
const output = [];
|
|
364
|
-
for (const block of blocks) {
|
|
365
|
-
if (block.kind === "text") {
|
|
366
|
-
output.push(...styleContent(block.items.flatMap((item) => [...item.render(renderOpts)])), terminator);
|
|
367
|
-
}
|
|
368
|
-
else {
|
|
369
|
-
// A block's lines are closed whether or not it closed them itself: a
|
|
370
|
-
// `Panel` ends in a line break and a bare `Spinner` or `ProgressBar`
|
|
371
|
-
// does not (they're line fragments, meant to be composed within a
|
|
372
|
-
// line — rich-flexstrip-5kf.4cq), and both leave the next print at
|
|
373
|
-
// the start of a line.
|
|
374
|
-
for (const line of Segment.splitLines(block.renderable.render(renderOpts))) {
|
|
375
|
-
output.push(...styleContent(line), Segment.line());
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
// Crop last, and crop the line-end with the rest: in the reference `end` is
|
|
380
|
-
// the tail of the printed line, so a line cut at the edge loses it too.
|
|
381
|
-
// Soft wrap turns cropping off whatever `crop` says, because a line it left
|
|
382
|
-
// whole is meant to reach the terminal whole. [LAW:dataflow-not-control-flow]
|
|
383
|
-
// Not cropping is an unbounded width rather than a skipped step — the same
|
|
384
|
-
// spelling `RichText` uses for `noWrap`.
|
|
385
|
-
const cropWidth = !softWrap && (opts.crop ?? true) ? this.width : Infinity;
|
|
386
|
-
this._writeSegments([...Segment.cropLines(output, cropWidth)]);
|
|
387
|
-
}
|
|
388
|
-
log(...args) {
|
|
389
|
-
// Simple log implementation — adds timestamp
|
|
390
|
-
const now = new Date();
|
|
391
|
-
const time = now.toLocaleTimeString();
|
|
392
|
-
const timeText = new RichText(`[${time}] `, { end: "" });
|
|
393
|
-
timeText.stylize("log.time");
|
|
394
|
-
this.print(timeText, ...args);
|
|
395
|
-
}
|
|
396
|
-
// [LAW:one-source-of-truth] `RuleOptions` is `Rule`'s, not a restatement of
|
|
397
|
-
// it. `console.ts` used to declare its own copy and field-by-field forward
|
|
398
|
-
// into this constructor, which made a second map of one shape — identical
|
|
399
|
-
// then, free to drift the moment `Rule` grew an option.
|
|
400
|
-
rule(title, options) {
|
|
401
|
-
const segments = [...new Rule(title, options).render(this.options)];
|
|
402
|
-
this._writeSegments(segments);
|
|
403
|
-
}
|
|
404
|
-
// [LAW:one-source-of-truth] `JSONRenderable` is the one formatter for JSON and
|
|
405
|
-
// `JSONOptions` is its option set; this method only picks the constructor. It
|
|
406
|
-
// prints with soft wrap, as the reference does, so a line wider than the
|
|
407
|
-
// console reaches the terminal whole and the output stays valid JSON.
|
|
408
|
-
printJson(json, options) {
|
|
409
|
-
const renderable = typeof json === "string"
|
|
410
|
-
? JSONRenderable.fromString(json, options)
|
|
411
|
-
: JSONRenderable.fromData(json, options);
|
|
412
|
-
this.print(renderable, { softWrap: true });
|
|
413
|
-
}
|
|
414
|
-
// --- Capture ---
|
|
415
|
-
// [LAW:one-source-of-truth] Redirect semantics match Python Rich's
|
|
416
|
-
// `Console.capture()`: while a capture is active the underlying target
|
|
417
|
-
// (file / stdout / stderr) receives nothing, and `endCapture()` returns
|
|
418
|
-
// the full text that would otherwise have been written. This is not a
|
|
419
|
-
// tee — callers wanting both must compose explicitly.
|
|
420
|
-
beginCapture() {
|
|
421
|
-
this._capture = "";
|
|
422
|
-
}
|
|
423
|
-
endCapture() {
|
|
424
|
-
const result = this._capture ?? "";
|
|
425
|
-
this._capture = null;
|
|
426
|
-
return result;
|
|
427
|
-
}
|
|
428
|
-
// --- Export (when record:true) ---
|
|
429
|
-
exportText({ clear = true } = {}) {
|
|
430
|
-
const text = this._recorded.map((s) => s.text).join("");
|
|
431
|
-
if (clear)
|
|
432
|
-
this._recorded = [];
|
|
433
|
-
return text;
|
|
434
|
-
}
|
|
435
|
-
// [LAW:single-enforcer] `encodeHtml` draws the picture `exportLines`
|
|
436
|
-
// resolves; nothing here interprets a `Style`.
|
|
437
|
-
exportHtml({ theme, clear = true } = {}) {
|
|
438
|
-
const html = encodeHtml(this._recorded, theme);
|
|
439
|
-
if (clear)
|
|
440
|
-
this._recorded = [];
|
|
441
|
-
return html;
|
|
442
|
-
}
|
|
443
|
-
// --- Internal ---
|
|
444
|
-
// [LAW:single-enforcer] One encode call per write batch routes through the
|
|
445
|
-
// same `segmentsToString` tree-coalescer used by `renderToString`. Adjacent
|
|
446
|
-
// same-style segments share one SGR open/close pair on the wire instead of
|
|
447
|
-
// one pair per segment. Recording captures every non-control segment for
|
|
448
|
-
// replay regardless of how the bytes coalesce.
|
|
449
|
-
_writeSegments(segments) {
|
|
450
|
-
if (this._record) {
|
|
451
|
-
for (const segment of segments) {
|
|
452
|
-
if (!segment.isControl)
|
|
453
|
-
this._recorded.push(segment);
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
const encoded = segmentsToString(segments, this._destination);
|
|
457
|
-
if (encoded.length > 0)
|
|
458
|
-
this._write(encoded);
|
|
459
|
-
}
|
|
460
|
-
_write(text) {
|
|
461
|
-
// [LAW:types-are-the-program] `_capture !== null` is a discriminator
|
|
462
|
-
// narrow on `string | null`, not a sentinel comparison — the type
|
|
463
|
-
// carries the active/inactive state. The early return is what makes
|
|
464
|
-
// this a redirect (not a tee); see beginCapture for semantics.
|
|
465
|
-
if (this._capture !== null) {
|
|
466
|
-
this._capture += text;
|
|
467
|
-
return;
|
|
468
|
-
}
|
|
469
|
-
const target = this._file ?? defaultSink(this._stream);
|
|
470
|
-
target.write(text);
|
|
471
|
-
}
|
|
472
|
-
}
|
package/dist/core/emoji.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Emoji shortcode support — dictionary, replacement, and renderable.
|
|
3
|
-
*/
|
|
4
|
-
import { Segment } from "./segment.js";
|
|
5
|
-
import type { Style } from "./style.js";
|
|
6
|
-
import type { Renderable, RenderOptions } from "./protocol.js";
|
|
7
|
-
export declare const EMOJI: Record<string, string>;
|
|
8
|
-
/**
|
|
9
|
-
* Replaces :shortcode: patterns in text with emoji characters.
|
|
10
|
-
*/
|
|
11
|
-
export declare function emojiReplace(text: string, defaultVariant?: "emoji" | "text"): string;
|
|
12
|
-
export declare class NoEmoji extends Error {
|
|
13
|
-
constructor(name: string);
|
|
14
|
-
}
|
|
15
|
-
export declare class Emoji implements Renderable {
|
|
16
|
-
readonly name: string;
|
|
17
|
-
private readonly _char;
|
|
18
|
-
private readonly _style;
|
|
19
|
-
private readonly _variant;
|
|
20
|
-
constructor(name: string, style?: Style, variant?: "emoji" | "text");
|
|
21
|
-
toString(): string;
|
|
22
|
-
render(_options: RenderOptions): Iterable<Segment>;
|
|
23
|
-
static replace(text: string): string;
|
|
24
|
-
}
|