UNPKG

ttsc

Version:

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

95 lines 4.68 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TtscService = void 0; const node_path_1 = __importDefault(require("node:path")); const startResidentTransform_1 = require("./compiler/internal/startResidentTransform"); /** * Resident, incremental transform service for the `ttsc` TypeScript-Go * pipeline. * * Where {@link TtscCompiler.transform} spawns a fresh process and recompiles the * whole project on every call, `TtscService` keeps one long-lived host warm: it * compiles the project once and then answers per-file transform requests from * that warm program. A single service instance transforms many files (a watch * server, an editor session, a codegen tool) while paying the project compile * once instead of once per file. Sharing one host across separate worker * processes (a Metro worker pool) is tracked in samchon/ttsc#255. * * The shape mirrors a legacy TypeScript `LanguageService`: construct it against * a project context, ask it to transform individual files, and dispose it when * done. Construction is synchronous (it launches the host); the host compiles * in the background, so the first {@link transformFile} resolves once that * compile lands. * * Resident mode runs through the linked-plugin shared host, so the project must * declare at least one transform-stage plugin; the constructor throws * otherwise. It does not run check-stage plugins (unlike * {@link TtscCompiler.transform}); only the program's own type-checking gates an * {@link updateFile}. */ class TtscService { resident; projectRoot; /** * Create a service bound to the given project context and launch its resident * host. The context is the same shape {@link TtscCompiler} accepts; it is not * replaceable per call. */ constructor(context = {}) { const started = (0, startResidentTransform_1.startResidentTransform)({ ...context, env: context.env ? { ...context.env } : undefined, plugins: Array.isArray(context.plugins) ? [...context.plugins] : context.plugins, }); this.resident = started.process; this.projectRoot = started.projectRoot; } /** * Return the transformed TypeScript source for one file, or `undefined` when * the resident program does not contain it (for example a file excluded from * the tsconfig). A relative `fileName` is resolved against the project root. * * Rejects when the resident host failed to compile the project; the rejection * carries the host's diagnostics so callers can surface a real build error. */ async transformFile(fileName, options = {}) { const reply = await this.resident.request({ file: this.absolutePath(fileName) }, "transform", options); // The resident client already validated the reply shape (boolean `found`, // string `typescript` when found), so a malformed or wrong-shape reply // rejected instead of reaching here. `found: false` is the only path to // `undefined`; a protocol failure never masquerades as an absent file. return reply.found === true && typeof reply.typescript === "string" ? reply.typescript : undefined; } /** * Apply new in-memory content for one file and re-transform the project, so a * subsequent {@link transformFile} reflects the edit without restarting the * host. Returns whether the re-transform succeeded; `false` means the edit * did not compile and the previous transform is still in effect. A relative * `fileName` is resolved against the project root. */ async updateFile(fileName, content, options = {}) { const reply = await this.resident.request({ content, update: this.absolutePath(fileName) }, "update", options); // The resident client validated the reply carries a boolean `updated`, so a // malformed or wrong-shape reply rejected instead of collapsing to `false`. // `false` here means only that the edit did not compile. return reply.updated === true; } /** Terminate the resident host and reject any in-flight requests. */ dispose() { this.resident.dispose(); } absolutePath(fileName) { return node_path_1.default.isAbsolute(fileName) ? fileName : node_path_1.default.resolve(this.projectRoot, fileName); } } exports.TtscService = TtscService; //# sourceMappingURL=TtscService.js.map