/** * 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