UNPKG

ttsc

Version:

General-purpose TypeScript-Go compiler, runtime, plugin host, and LSP host.

192 lines (191 loc) 9.25 kB
/** * Subcommands the ttsc CLI dispatches to. The bare `"ttsc"` entry covers the * default lane (no explicit subcommand, e.g. `ttsc -p tsconfig.json`). */ export type TtscSubcommand = "ttsc" | "build" | "cache" | "check" | "fix" | "format" | "prepare" | "clean"; /** * Subcommands the ttsx CLI dispatches to. ttsx exposes a single lane today but * the schema mirrors ttsc's shape so future subcommands plug in without a * second engine. */ export type TtsxSubcommand = "ttsx"; export type AnySubcommand = TtscSubcommand | TtsxSubcommand; /** * Layers a flag can be consumed by. The order reflects the runtime pipeline: * * Launcher → runBuild → tsgo / native sidecars (host, lint). * * A flag must declare at least one consumer. `forwardTo` declares where the * flag travels when the consuming layer does not absorb it (e.g. ttsc-owned * flags that the JS launcher consumes and re-emits as different tsgo flags). */ export type FlagLayer = "launcher" | "runBuild" | "tsgo" | "host" | "lint"; /** * Argument shape of a flag. * * - `boolean` — `--flag` with an optional spaced `true` / `false`. Launcher flags * also accept `--flag=true` / `--flag=false`; tsgo-forwarded flags stay * verbatim because pinned tsgo does not split `=`. * - `value` — `--flag value`. Launcher flags also accept `--flag=value`. * - `valueOptional` — `--flag` standalone is allowed; if followed by a non-flag * token that token is consumed as the value. (Currently unused — declared for * future flags like `--watch [path]`.) */ export type FlagKind = "boolean" | "value" | "valueOptional"; /** * Validation predicate for `value`-kind flags. `none` is the default (accept * any string). */ export type ValueValidator = "none" | "positiveInt"; /** * One CLI flag's complete contract. Every layer's behaviour is structural — * which subcommands accept the flag, where it is consumed, where it is * forwarded, whether it is terminal (prints and exits) — so the next layer * never silently drops the flag. */ export interface FlagSpec { /** * Canonical flag name including leading dashes (`"--singleThreaded"`). The * generator uses this as the map key in the Go allow-list and as the first * column of the docs table. */ readonly name: string; /** * Alternative spellings (`"-p"`, `"--project"` for `--tsconfig`). The parsing * engine treats every alias as an equivalent of `name`. */ readonly aliases?: readonly string[]; /** Argument shape: boolean / required value / optional value. */ readonly kind: FlagKind; /** * For `value` flags: optional validator. `positiveInt` mirrors the * `--checkers minValue:1` constraint tsgo enforces. */ readonly validator?: ValueValidator; /** Subcommands that accept this flag. */ readonly subcommands: readonly AnySubcommand[]; /** * Layers that read the flag into a typed option. Order matters only for * documentation; the parsing engine merges across layers. */ readonly consumedBy: readonly FlagLayer[]; /** * Where the flag travels when the consuming layer does not absorb it. Default * for any flag a layer does not consume is `"tsgo"` — i.e. the launcher * forwards an unknown flag to tsgo via passthrough. Setting this to * `undefined` while `consumedBy: ["launcher"]` is set means the flag is * intentionally consumed-not-forwarded (e.g. ttsc-internal `--binary`). */ readonly forwardTo?: FlagLayer; /** * Terminal flags ask the underlying tool to print something and exit * (`--help`, `--version`, `--showConfig`, `--listFilesOnly`, `--all`, * `--init`). ttsc must not wrap them in a pre-emit pass — that is how the * `--showConfig prints twice` bug appeared (RC-2). */ readonly terminal?: boolean; /** * `true` when a `terminal` flag's meaning does not presuppose a resolved * project, so ttsc must answer it before project resolution runs (`--init` * writes the starter tsconfig, `--all` and `-?` print tsgo's help). Without * this split `ttsc --init` failed with "could not find tsconfig.json …" in * the only directory where it is useful. * * `--showConfig` and `--listFilesOnly` are terminal but deliberately NOT * project-free: both describe a project, so failing without one is correct. */ readonly projectFree?: boolean; /** * `true` when every occurrence of a repeated `value` flag counts rather than * the last one winning (`ttsx -r a -r b` preloads both). The engine keeps the * last value in `ParseResult.values` for callers that want a single answer * and records the complete ordered list in `ParseResult.repeated`. */ readonly repeatable?: boolean; /** * `true` when ttsc may add this flag to tsgo internally and post-process the * output. If the user also forwards the same flag, ttsc keeps the * user-visible behaviour (no double-print, no swallowed output). The shadow * check is structural rather than `passthrough.includes("…")`. * * Currently true for `--listEmittedFiles`, `--noEmit`, `--pretty`. */ readonly internalShadow?: boolean; /** * `true` when pinned tsgo only permits the option in tsconfig, except for * command-line `false` or `null`. The launcher forwards the original argv so * tsgo remains the diagnostic authority. */ readonly tsconfigOnly?: boolean; /** * Native sidecar capability that must be declared before ttsc sends this flag * as a bare CLI argument. Everything else routes through `--tsgo-args` or * stays in the JS launcher. */ readonly nativeCapability?: "diagnosticsTiming" | "threadingArgs"; /** Human description for `--help` and the docs table. */ readonly description: string; } /** * Single source of truth for every flag the ttsc / ttsx CLI accepts. New flags * are added here and only here; the generator rebuilds the parsers and the Go * allow-lists from this table. * * Constraints enforced by the parser and the generator: * * 1. Every flag is uniquely identified by `name`; aliases must not collide with * other flags' `name` or `aliases`. * 2. A flag listed in `consumedBy: ["launcher"]` without a `forwardTo` * consumes-not-forwards. The generator flags this in the docs and the Go * allow-list so the boundary is explicit. * 3. A flag with `subcommands` covering `clean` or `prepare` is parsed by the * project-args lane; the parsing engine accepts the same flag in build / * check / fix / format without a separate parser. */ export declare const FLAG_SCHEMA: readonly FlagSpec[]; /** * Normalize a CLI token to the identity the compiler ttsc wraps resolves it by: * one or two leading dashes removed, the remainder lower-cased. * * TypeScript's option parser — legacy `tsc` and native tsgo alike — strips a * `--` or `-` prefix and matches the rest case-insensitively, so `--noEmit`, * `--noemit`, `--NOEMIT`, and `-noEmit` all name the same option to the tool * ttsc forwards to. The launcher used to key its index on the exact spelling, * so a case variant of a ttsc-owned flag fell through the unknown-flag escape * hatch: tsgo honoured it and every ttsc-side consumer of the same flag never * fired, with no diagnostic. * * This is the single normalization. Everything that resolves a token against * `FLAG_SCHEMA` — the parsing engine, the terminal / shadow / project-free * classifications, and the generated Go allow-lists — keys off this function, * so no two layers can disagree about which flag a spelling names. */ export declare function normalizeFlagToken(token: string): string; /** * Resolve a raw argv token to the flag it names, or `undefined` when the schema * claims no such flag. * * Accepts every spelling the compiler accepts — any casing, one or two leading * dashes — plus the inline `--flag=value` form, whose value is not part of the * identity. A token without a leading dash is never a flag: bare tokens are * input files and flag values, and resolving them here would let a value like * the `all` of `--target all` masquerade as `--all`. */ export declare function resolveFlagSpec(token: string): FlagSpec | undefined; /** * Lookup of every declared spelling → its canonical FlagSpec, keyed by * {@link normalizeFlagToken}. Built once at module load so the parsing engine * has O(1) flag resolution. Prefer {@link resolveFlagSpec}, which applies the * normalization for the caller. */ export declare const FLAG_BY_TOKEN: ReadonlyMap<string, FlagSpec>; /** Tokens (canonical name + aliases) accepted in `subcommand`. */ export declare function flagsForSubcommand(subcommand: AnySubcommand): FlagSpec[]; /** * Allow-list map for the Go layer named `layer` (`"host"` or `"lint"`): * flag-name (no leading dashes) → whether the flag takes a value token. The * generator emits a literal Go map with the same shape, but this function is * the runtime equivalent — used in tests to verify the generated Go matches the * schema. */ export declare function buildGoAllowList(layer: "host" | "lint"): Map<string, boolean>;