UNPKG

ttsc

Version:

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

155 lines (154 loc) 7.65 kB
import { type FilesystemPathIdentityContext } from "../../internal/projectInputPathIdentity"; interface ResolveResult { url: string; format?: string | null; shortCircuit?: boolean; } /** * The compiler options that decide the emit format of a file, as declared by * the project that emitted it. Both fields matter: tsgo derives the module kind * from `target` whenever `module` is absent, so carrying only `module` cannot * reproduce its decision. */ export interface OwningModuleOptions { module?: string; target?: string; } /** * Lowest Node.js the ttsx source runtime supports. The synchronous * `module.registerHooks` (Node 22.15.0) is the highest floor among the runtime * APIs these hooks depend on — `stripTypeScriptTypes` (22.13.0) and the child's * `--disable-warning` flag (20.11.0) are both lower — so it sets the effective * minimum. Kept in sync with `packages/ttsc/package.json#engines.node` and the * documented requirement in `website/src/content/docs/development/index.mdx`. */ export declare const TTSX_MINIMUM_NODE_VERSION = "22.15.0"; /** * Report why the running (or a candidate) Node.js version cannot execute the * ttsx source runtime, or `null` when it can. Returning an actionable message — * rather than letting the child die with an internal `TypeError` on the missing * `registerHooks`, or Node 18 rejecting `--disable-warning` with exit 9 — is * what turns an opaque internal failure into a clear version diagnostic. * * Exported for direct exercise by the ttsx e2e suite: the built launcher can * only be spawned under the Node version running the tests, so the boundary * around the floor cannot otherwise be pinned on CI. */ export declare function checkNodeRuntimeSupport(version: string): string | null; /** * Install the source-loading hooks on the current (main) thread. Idempotent: * the bootstrap installs them for the entry process, and `NODE_OPTIONS` * re-imports the installer in every child process the program spawns — both may * run in the same process. * * Two hooks are needed, because `module.registerHooks` does not intercept a * `require()` made from inside a CommonJS module that was itself reached * through an ESM `import` (the interop translator loads it on the raw CJS * path). The ESM graph goes through `registerHooks`; the CommonJS `require` * graph goes through `Module._extensions` — the canonical loader extension * point `ts-node`/`tsx` use for the same reason. */ export declare function installRuntimeHooks(): void; /** * The module format of the entry source file, derived from the entry project's * compiler options (via the runtime manifest) the same way the served files are * classified. The bootstrap uses it to load the entry through a CommonJS * `require` or an ESM `import`. */ export declare function entryModuleFormat(entryFile: string): "module" | "commonjs"; /** * Restore a `node:` builtin URL when affected Node releases return the exact * prefix-stripped spelling from their synchronous CommonJS resolver. * * Every other result passes through unchanged. In particular, a user hook that * intentionally remaps a `node:` specifier to another URL retains ownership of * that mapping, while ordinary and ESM builtin results already carrying the * scheme avoid an unnecessary copy. */ export declare function restoreStrippedNodeBuiltinScheme(specifier: string, result: ResolveResult): ResolveResult; /** Cache of built projects keyed by owning tsconfig path. */ interface BuiltProject { emitDir: string; rootDir: string; emittedFiles?: readonly string[]; moduleOptions: OwningModuleOptions; } /** Narrow a resolved project's compiler options to the emit-format pair. */ export declare function projectModuleOptions(compilerOptions: Record<string, unknown>): OwningModuleOptions; /** * True when `real` is `directory` itself or sits beneath it. Handles a root * `directory` (`/`, `C:\`): naively appending a separator would yield `//`, * which no path starts with, so a root `rootDir` project would serve nothing. * Both sides are normalized to native separators first: a manifest `rootDir` * arrives slash-normalized from the synthesized tsconfig (`C:/` on Windows) * while `real` paths are native, and a raw prefix comparison across the two * forms silently never matches. Filesystem identity preserves ordinary Windows * aliases while keeping case-distinct paths under an opted-in directory * separate. Exported for direct exercise by the ttsx e2e suite — spawned runs * cannot pin both Windows case-semantics branches on CI. */ export declare function isWithin(real: string, directory: string, identities?: FilesystemPathIdentityContext): boolean; /** * Reuse a dependency another process (or an earlier import) already built. * * The completion marker names the exact emit generation, so this reads metadata * and emit as one unit: it returns a hit only when the marker parses to a valid * generation AND that generation's directory holds emitted JavaScript. A reader * that runs while a replacement build is populating a DIFFERENT generation * directory keeps returning the previous complete generation until the atomic * marker swap points at the new one — never a mix of old metadata and a partial * new emit. * * Exported for the ttsx dependency-cache regressions. */ export declare function readDependencyCache(cacheDir: string, metaPath: string): BuiltProject | null; /** Ownership token returned only to the process that acquired `current`. */ export type DependencyBuildLockLease = { generation: string; }; /** Opaque identity of one observed lock generation. */ export type DependencyBuildLockFence = { generation: string; }; /** * Atomically acquire the current generation of a dependency build lock, or * `null` when another process already holds it. Exported for the deterministic * multi-process cache regressions. */ export declare function acquireDependencyBuildLock(lockDir: string): DependencyBuildLockLease | null; /** Retire a held generation during the holder's `finally`. */ export declare function releaseDependencyBuildLock(lockDir: string, lease: DependencyBuildLockLease): boolean; /** * Retire exactly the generation carried by an abandoned observation. Exported * for the deterministic multi-process cache regressions. */ export declare function reclaimDependencyBuildLock(lockDir: string, fence: DependencyBuildLockFence): boolean; /** One observation of a dependency build lock's state. */ export type DependencyBuildLockObservation = { state: "active"; owner: string; fence: DependencyBuildLockFence; } | { state: "abandoned"; reason: string; fence: DependencyBuildLockFence; } | { state: "released"; }; /** * Classify the current state of a dependency build lock directory. Exported for * the deterministic multi-process cache regressions. */ export declare function inspectDependencyBuildLock(lockDir: string, now: number): DependencyBuildLockObservation; /** * The physical path, in the same spelling the launcher decided on. * * `realpathSync.native` first, because the plain implementation resolves * reparse points but leaves a Windows 8.3 component alone — and `TEMP` is * `C:\Users\RUNNER~1\...` on a GitHub Windows runner. The launcher resolves the * entry through `fs.realpathSync.native`, so answering here with the short name * would put a `..` in `path.relative(rootDir, real)`, drop the exact-mirror * lane, and leave the entry to whatever the trailing-stem matcher picks. */ export declare function realPath(target: string): string; export {};