/**
* One screen, compiled — with the compiler HANDED OVER, and its standard library
* with it.
*
* This is `screen-tsc.ts` minus the one thing that made it Node's: the compiler
* loader. Everything here — the in-memory compiler host, the options a screen is
* checked under, and the translation of a diagnostic into the floor's sentence —
* needs a filesystem for nothing, so it runs wherever the caller found a
* compiler. `screen-tsc.ts` is that caller on Node, resolving `typescript`
* through `createRequire` and answering the lib files off disk;
* `server/edge/typecheck.ts` is that caller on a Worker, importing the compiler
* and answering the lib files out of a `Map`.
*
* THE SPLIT IS THE POINT, and it is structural rather than careful. A single
* `import { createRequire } from "node:module"` at the top of `screen-tsc.ts` is
* emitted into any bundle that reaches this module — esbuild keeps the external
* import statement even after tree-shaking away every consumer, and `sideEffects:
* false` does not change that. Under workerd without `nodejs_compat` the whole
* worker then refuses to START, before a single request: `No such module
* "node:module"`. A lazy import would have depended on bundler behaviour and on
* whichever externals a consumer configured; a module boundary cannot be
* defeated by either. Nothing under this file may import a Node builtin.
*
* The sentences are written from the AST, not scraped from the compiler's prose:
* a raw `TS2322` dump naming two anonymous object types is unactionable, where
* "sets unknown prop \"data\" on
; the renderer drops it. Allowed props:
* columns, rows, …" is the same sentence the bespoke checks already speak. They
* live here, not with either caller, because a screen author must read the same
* sentence whatever compiled the screen.
*/
import type TS from "typescript";
import type { Finding } from "./types.js";
export interface ScreenTscInput {
/** The screen file's text, verbatim. */
readonly screen: string;
/** The ambient declarations from {@link screenTypings}. */
readonly typings: string;
/**
* The standard library, when the default is too small. The wire screen is
* declarative and needs nothing past ES5; a COMPONENT screen awaits tool
* calls, so it needs a `Promise`. No DOM lib is available in either case —
* that is deliberate, not an omission.
*/
readonly lib?: readonly string[];
}
/**
* The standard library, as the compiler host asks for it. `ts.sys` is Node's
* disk; a venue without one carries its libs some other way, which is the whole
* reason this is an argument.
*
* `exists` is separate from `read` because the compiler PROBES far more files
* than it reads, and a lib file is hundreds of kilobytes: answering existence by
* reading the body would pay for every probe, and would call a file that exists
* but cannot be read absent. An in-memory provider answers both with one lookup.
*/
export interface LibTextProvider {
read(fileName: string): string | undefined;
exists(fileName: string): boolean;
}
/**
* One compiled screen, for a caller that writes its OWN sentences.
*
* `ok: false` NAMES why nothing was checked, instead of returning silence a
* caller cannot tell apart from a clean screen. That distinction is the point:
* the wire screen's check degrades to no findings by policy (below), while the
* component screen's gauntlet treats an unreachable compiler as a failure —
* a gate that cannot read the file must not pass it.
*/
export type ScreenProgram = {
ok: true;
ts: typeof TS;
file: TS.SourceFile;
checker: TS.TypeChecker;
/** Syntax errors. Semantic diagnostics over a file that does not parse
* are a cascade of consequences of the same break, so `semantic` is
* empty whenever this is not. */
syntactic: readonly TS.Diagnostic[];
semantic: readonly TS.Diagnostic[];
} | {
ok: false;
why: string;
};
/** Build the program and collect its diagnostics, with the compiler and its
* standard library HANDED OVER — for a caller that resolved both somewhere this
* package cannot reach (`checking/toolchain.ts`). Never throws. */
export declare function screenProgramWith(ts: typeof TS, input: ScreenTscInput, libs: LibTextProvider, defaultLibFileName: (options: TS.CompilerOptions) => string): ScreenProgram;
/** One diagnostic as the floor's sentence. Exported for the component screen's
* gauntlet, which overrides the handful of classes whose prose is specific to
* the wire dialect and reuses the rest of this translation. */
export declare function translateDiagnostic(ts: typeof TS, file: TS.SourceFile, checker: TS.TypeChecker, diagnostic: TS.Diagnostic): Finding[];
/** A diagnostic's 1-based line in the screen file — the author's own line. */
export declare const diagnosticLine: (file: TS.SourceFile, diagnostic: TS.Diagnostic) => number;
//# sourceMappingURL=screen-program.d.ts.map