paratext
Every export of paratext, with its signature and doc comment: _default, ansiEscapesFor, beep, beginSynchronizedOutput, clearScreen, clearTerminal and 54 more, plus 7 types.
paratext — everything around your terminal output that is not the output.
Paratext is the literary term for what surrounds a text without being it: the title, the
cover, the margins, the notes. This package owns the terminal equivalent — OSC, the
escape class (ESC ]) that addresses the terminal program rather than the character
grid. Hyperlinks, inline images, the window title, the clipboard, desktop notifications,
the working directory, and the bell.
The boundary is the terminal standard's, not ours, which is why it decides cases nobody has raised yet:
SGR ESC [ … m how text looks roundel
CSI ESC [ … the grid flagstaff
CSI (to undo) cursor, alternate screen closeout
OSC ESC ] … the terminal program here
Nothing in this layer is detectable. No terminal answers "do you do OSC 1337", so
every capability carries a static projection and emit returns it whenever support is
absent or unknown (PRINCIPLES rule 6). Emitting the bytes and hoping is what puts
]1337;File=inline=1;… across a user's screen, and it is what every incumbent does.
Terminals invent OSC codes faster than packages ship releases. So the surface is a
registry rather than a fixed list: register adds or replaces a capability, the built-ins
use that same call, and a caller whose terminal we mis-detect can correct us without
forking. See capability.ts.
import _default from 'paratext';
import { ansiEscapesFor, beep, beginSynchronizedOutput, … } from 'paratext';Functions
ansiEscapesFor
The surface bound to a runtime you supply.
The exported functions are this over {@link processRuntime }. A caller that has its own
Runtime — a test, a host that knows better than our guesses, a server rendering for
somebody else's terminal — calls this instead and nothing reads process.
function ansiEscapesFor(runtime: Runtime): AnsiEscapes;| Parameter | Type |
|---|---|
runtime | Runtime |
Returns AnsiEscapes
check
Everything wrong with a plugin document — the check rule 7 asks for, usable before
registering and by a command that validates a file.
Two shapes are accepted, which is $defs/capabilityDocument's oneOf in the schema:
- the family shape, capabilities by name under
capabilities, the key every other host reads its own section from; - one capability written as the whole document — what paratext's own schema was before the family schema absorbed it.
(2) still validates, because a document that was correct yesterday is not made wrong by our
housekeeping, and it comes back with a deprecated: line saying it goes at 1.0. A caller
that wants only the blocking lines filters with refusals().
function check(candidate: object): string[];| Parameter | Type |
|---|---|
candidate | object |
Returns string[]
emit
Emit name for fields: the sequence when the terminal understands it, the static
projection when it does not, and for an unknown name whatever text the caller supplied —
never a throw, because output is not the place to discover a typo at three in the morning.
function emit(runtime: Runtime, name: string, fields?: Fields): string;| Parameter | Type |
|---|---|
runtime | Runtime |
name | string |
fields (optional) | Fields |
Returns string
fieldsUsed
Every field a template reads, so check can say what a capability needs.
function fieldsUsed(template: string): string[];| Parameter | Type |
|---|---|
template | string |
Returns string[]
register
Add a capability, or replace one by name — replacing is deliberate, so a caller whose terminal we mis-detect can correct the guess without patching the package.
This is the only way into the registry, which is what makes one validator enough:
emit() reads nothing else, the built-ins come through here, and attach() in
plugin.ts hands its contributions to this same call. A capability whose when is not an
object is refused here, and that refusal — not a guard further down — is the reason
supports() is never asked about it.
function register(capability: Capability): void;| Parameter | Type |
|---|---|
capability | Capability |
Returns void
registerBuiltins
Registered through the public call, so the built-ins prove the extension surface works.
function registerBuiltins(): void;Returns void
render
Render a template against a caller's fields.
Optional groups resolve first, and a group survives only if every field inside it has a
value — an empty string counts as absent, because Done: with nothing after the colon is
worse output than Done.
function render(template: string, fields: Fields): string;| Parameter | Type |
|---|---|
template | string |
fields | Fields |
Returns string
supports
Whether this runtime is believed to understand capability.
Takes the when clause structurally rather than a whole Capability, so this module owes
capability.ts nothing at all and the subpath graph stays a leaf. A Capability satisfies
the parameter, which is every existing caller.
function supports(runtime: Runtime, capability: {
readonly when: Support;
}): boolean;| Parameter | Type |
|---|---|
runtime | Runtime |
capability | { readonly when: Support; } |
Returns boolean
Classes
CapabilityError
Thrown rather than returned: a malformed capability is a programming error at start-up.
It carries a code from the family's one vocabulary, so that the same defect reported
through register() and through plugin.validate() reads the same. See
{@link CapabilityErrorCode} for where that vocabulary lives and why this file spells its
two members out rather than importing them.
class CapabilityError extends Error {
readonly code: CapabilityErrorCode;
constructor(code: CapabilityErrorCode, message: string);
}Constants
default
The default export, declared as _default.
The default export, carrying what this package implements: the CSI half and the four OSC
members. iTerm and ConEmu stay off it — a key present with an undefined value would
read as a claim made and not kept. Frozen, because the incumbent's own suite asserts
that a named export and the member are the same object and a caller reassigning one would
make that quietly untrue.
const _default: Readonly<{
beep: "\u0007";
image: (data: Uint8Array | string, options?: ImageOptions) => string;
link: (text: string, url: string) => string;
setCwd: (cwd?: string) => string;
cursorTo: (x: number, y?: number) => string;
cursorMove: (x: number, y?: number) => string;
cursorUp: (count?: number) => string;
cursorDown: (count?: number) => string;
cursorForward: (count?: number) => string;
cursorBackward: (count?: number) => string;
cursorLeft: "\u001B[G";
cursorSavePosition: "\u001B7" | "\u001B[s";
cursorRestorePosition: "\u001B8" | "\u001B[u";
cursorGetPosition: "\u001B[6n";
cursorNextLine: "\u001B[E";
cursorPrevLine: "\u001B[F";
cursorHide: "\u001B[?25l";
cursorShow: "\u001B[?25h";
eraseEndLine: "\u001B[K";
eraseStartLine: "\u001B[1K";
eraseLine: "\u001B[2K";
eraseDown: "\u001B[J";
eraseUp: "\u001B[1J";
eraseScreen: "\u001B[2J";
scrollUp: "\u001B[S";
scrollDown: "\u001B[T";
eraseLines: (count: number) => string;
clearScreen: "\u001Bc";
clearViewport: "\u001B[2J\u001B[H";
clearTerminal: "\u001B[2J\u001B[3J\u001B[H";
enterAlternativeScreen: "\u001B[?1049h";
exitAlternativeScreen: "\u001B[?1049l";
beginSynchronizedOutput: "\u001B[?2026h";
endSynchronizedOutput: "\u001B[?2026l";
synchronizedOutput: (text: string) => string;
}>;beep
The bell, byte-identical to ansi-escapes' beep.
The one member of this surface that does not degrade, because it is a value and not a
call: there is no runtime to consult at the moment a constant is read. It is also one
byte rather than a sequence, so a pipe that receives it gets a byte, not a smear of
unreadable escape text. emit(runtime, 'bell') is the form that degrades.
const beep = "\u0007";bell
BEL — the oldest one, and the only member of this layer that is not an OSC sequence.
const bell: Capability;builtins
Every capability this package ships, in one list a reader can check against the registry.
const builtins: readonly Capability[];capabilities
Every registered name, sorted — so --json and a check command can enumerate them.
const capabilities: () => string[];capability
One capability by name, for callers that want to inspect before they emit.
const capability: (name: string) => Capability | undefined;clipboard
OSC 52 — put text on the user's clipboard through the terminal, which is the only way
that works over ssh. clipboardy shells out to pbcopy and cannot.
const clipboard: Capability;ConEmu
const ConEmu: NotImplemented;cwd
OSC 50 and 9;9 — tell the emulator where we are, so a new tab opens here.
const cwd: Capability;DEPRECATED
The prefix on a line check returns that does not refuse the document.
A capability written as the whole document is the shape paratext had before the family
schema absorbed it. It still validates for one minor release (PLAN D2) and 1.0 removes it,
so the two kinds of line travel back together and this is how a caller tells them apart:
refusals() is what blocks, everything else is what to fix before 1.0.
const DEPRECATED = "deprecated: ";image
OSC 1337 — image(data, options), projecting to options.caption.
const image: (data: Uint8Array | string, options?: ImageOptions) => string;isDeprecation
Whether a line check produced is a warning rather than a refusal.
const isDeprecation: (line: string) => boolean;iTerm
const iTerm: NotImplemented;link
OSC 8 — link(text, url), projecting to text (url) where hyperlinks are not understood.
const link: (text: string, url: string) => string;notify
OSC 9 — a desktop notification, without node-notifier's native binaries.
const notify: Capability;processRuntime
What a real process looks like. Callers that have not got one pass their own.
const processRuntime: () => Runtime;refusals
The lines that refuse the document — what register throws on, and what a CLI exits on.
const refusals: (lines: readonly string[]) => string[];reset
Registration is global, so tests and hosts need a way back.
const reset: () => void;setCwd
OSC 50 + OSC 9;9 — setCwd(cwd), defaulting to the runtime's own, projecting to nothing.
const setCwd: (cwd?: string) => string;title
OSC 0 — the window and tab title.
const title: Capability;Interfaces
AnsiEscapes
The members of ansi-escapes paratext implements, bound to one runtime.
interface AnsiEscapes {
/** The bell, as a string — the incumbent's `beep`. */
beep: string;
/** OSC 8. Projects to `text (url)`. */
link: (text: string, url: string) => string;
/** OSC 1337. Projects to `options.caption`. */
image: (data: Uint8Array | string, options?: ImageOptions) => string;
/** OSC 50 + OSC 9;9, the two halves upstream concatenates. Projects to nothing. */
setCwd: (cwd?: string) => string;
}Capability
interface Capability {
/** How callers name it: `link`, `image`, `clipboard`, or anything a third party invents. */
readonly name: string;
/** The OSC code, or `BEL`. Documentation for a reader, and a key for `check`. */
readonly osc: number | 'BEL';
readonly when: Support;
/** The bytes, as a template, for a terminal that does understand. */
readonly encode: string;
/**
* What to print when it does not — PRINCIPLES rule 6, and the reason this package exists.
* An image becomes its caption, a notification a printed line, a hyperlink `text (url)`.
* A capability without one is refused at `register`, because a sequence a terminal cannot
* read is not a feature, it is `]1337;File=inline=1;…` across a user's screen. An empty
* string is a legitimate projection — a window title has nothing to say in a log — but it
* has to be written down rather than left out.
*/
readonly fallback: string;
}ImageOptions
ansi-escapes' image() options, plus the field a projection needs.
interface ImageOptions {
/** Cells, pixels (`20px`) or percent (`50%`) — passed through as the incumbent passes it. */
width?: number | string;
height?: number | string;
/** `false` writes `preserveAspectRatio=0`, exactly as upstream does. */
preserveAspectRatio?: boolean;
/**
* What a terminal that cannot draw the image prints instead. paratext's addition, and not
* optional in spirit: an image with no caption projects to nothing, which is silence where
* the incumbent would have written bytes nobody can read.
*/
caption?: string;
}Runtime
The slice of a runtime this package needs — the same seam roundel/policy.ts declares,
for the same reason: nothing here reads process directly, so a test is a two-line
literal and a host can lie about the terminal on purpose.
interface Runtime {
env: Record<string, string | undefined>;
/**
* `stderr` is optional and falls back to `stdout` when absent.
*
* Only `paratext/terminal-link` reads it — its whole surface is a pair, `terminalLink`
* against stdout and `terminalLink.stderr` against stderr, and a façade that decided both
* from one stream would answer the wrong question for half of its API. Optional because a
* two-line test literal should not have to carry a stream it is not asking about, and
* because every existing caller of this type predates the field.
*/
isTTY: {
stdout: boolean;
stderr?: boolean;
};
/**
* The working directory, for the one capability that has to name it.
*
* Optional, because nothing that decides *support* reads it and a two-line test literal
* should not have to carry it. `setCwd()` with no argument is the only caller, and it is
* the reason this is here at all: `ansi-escapes`' `setCwd` defaults to `process.cwd()`
* (R8), and a compatible default that read `process` itself would put a second process
* reference in the package and break R5.
*/
cwd?: string;
/**
* The command line and the OS, for `paratext/terminal-link` alone: `supports-hyperlinks`
* reads `--no-hyperlink` / `--color` flags and refuses win32 outside Windows Terminal, and
* a drop-in that ignored them would link where the incumbent did not. Optional for the
* reason `cwd` is.
*/
argv?: readonly string[];
platform?: string;
}Support
When a terminal is believed to understand a sequence. Every clause is optional and all of
them must hold; termProgram and envAny are ORs within themselves.
interface Support {
/** Refuse a pipe. Almost always true: a file that receives OSC gets control bytes in it. */
readonly tty?: boolean;
/** Any one of these `TERM_PROGRAM` values. */
readonly termProgram?: readonly string[];
/** Any one of these environment variables merely being set, as VTE announces itself. */
readonly envAny?: readonly string[];
/** An exact `TERM`, for the terminals that identify that way. */
readonly term?: string;
}Types
Fields
What a caller hands a capability. Flat and string-valued, and therefore describable.
type Fields = Readonly<Record<string, string | undefined>>;NotImplemented
The type of a name that is declared and not implemented.
Reading one gets undefined; calling one does not type-check, which is the point. A
compile error that lands on this type is a sentence telling you which package owns the
thing you asked for, and it arrives before you ship rather than after.
type NotImplemented = undefined;Re-exported
Documented on the page of the entry point that declares them.
| Export | Kind | Documented in |
|---|---|---|
beginSynchronizedOutput | const | paratext/csi |
clearScreen | const | paratext/csi |
clearTerminal | const | paratext/csi |
clearViewport | const | paratext/csi |
cursorBackward | const | paratext/csi |
cursorDown | const | paratext/csi |
cursorForward | const | paratext/csi |
cursorGetPosition | const | paratext/csi |
cursorHide | const | paratext/csi |
cursorLeft | const | paratext/csi |
cursorMove | const | paratext/csi |
cursorNextLine | const | paratext/csi |
cursorPrevLine | const | paratext/csi |
cursorRestorePosition | const | paratext/csi |
cursorSavePosition | const | paratext/csi |
cursorShow | const | paratext/csi |
cursorTo | const | paratext/csi |
cursorUp | const | paratext/csi |
endSynchronizedOutput | const | paratext/csi |
enterAlternativeScreen | const | paratext/csi |
eraseDown | const | paratext/csi |
eraseEndLine | const | paratext/csi |
eraseLine | const | paratext/csi |
eraseLines | const | paratext/csi |
eraseScreen | const | paratext/csi |
eraseStartLine | const | paratext/csi |
eraseUp | const | paratext/csi |
exitAlternativeScreen | const | paratext/csi |
scrollDown | const | paratext/csi |
scrollUp | const | paratext/csi |
synchronizedOutput | const | paratext/csi |
Incremental migration
Move from ansi-escapes, terminal-link and term-img one import at a time, and from term-img's paths to bytes with one readFile.
paratext/csi
Every export of paratext/csi, with its signature and doc comment: cursorTo, cursorMove, cursorUp, cursorDown, cursorForward, cursorBackward and 25 more.