UNPKG

ttsc

Version:

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

115 lines 5.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.startResidentTransform = startResidentTransform; const node_path_1 = __importDefault(require("node:path")); const loadProjectPlugins_1 = require("../../plugin/internal/loadProjectPlugins"); const readProjectConfig_1 = require("./project/readProjectConfig"); const residentTransformProcess_1 = require("./residentTransformProcess"); const resolveBinary_1 = require("./resolveBinary"); const resolveTsgo_1 = require("./resolveTsgo"); const sharedHostHelpers_1 = require("./sharedHostHelpers"); /** * Start a resident `serve` host for the configured project. * * Mirrors the plugin spawn of `transformProjectInMemory`, but launches the * shared host's `serve` subcommand as one long-lived process instead of a * per-call `transform` subprocess. The host compiles the whole project once at * startup and then answers per-file requests, so one caller pays the project * compile once and reuses it across its own per-file requests. * * Resident mode runs through the linked-plugin shared host * (`cmd/utility-host`), which is the only binary that exposes `serve`. It * therefore requires at least one transform-stage plugin; executable transform * hosts that own their own process are not served and must use the per-call * transform path. Check-stage plugins are not run by the resident host. */ function startResidentTransform(context) { const cwd = node_path_1.default.resolve(context.cwd ?? process.cwd()); const project = (0, readProjectConfig_1.readProjectConfig)({ cwd, projectRoot: context.projectRoot, tsconfig: context.tsconfig, }); const loaded = (0, loadProjectPlugins_1.loadProjectPlugins)({ binary: (0, resolveBinary_1.resolveBinary)(context) ?? "", cacheDir: context.cacheDir ?? context.env?.TTSC_CACHE_DIR, cwd, entries: context.plugins, env: { ...process.env, ...context.env }, pluginConfigDir: context.pluginConfigDir, projectRoot: context.projectRoot, tsconfig: project.path, }); const transformers = loaded.nativePlugins.filter((plugin) => plugin.stage === "transform"); if (transformers.length === 0) { throw new Error("ttsc: TtscService resident mode requires at least one transform-stage plugin; " + "use TtscCompiler.transform for projects with only check-stage plugins or none"); } (0, sharedHostHelpers_1.assertSharedHostCompatibility)(transformers, "source-to-source"); const host = (0, sharedHostHelpers_1.selectSharedHostPlugin)(transformers); const tsgoBinary = (0, resolveTsgo_1.resolveTsgo)({ ...context, cwd: project.root }).binary; const resident = new residentTransformProcess_1.ResidentTransformProcess({ args: [ "serve", `--tsconfig=${project.path}`, `--plugins-json=${serializeNativePlugins(transformers)}`, `--cwd=${project.root}`, ], binary: host.binary, cwd: project.root, env: residentEnv(context, tsgoBinary, loaded.nativePlugins), }); return { process: resident, projectRoot: project.root }; } /** * Build the environment for the resident host spawn. Matches the per-call * transform spawn: injects the Node, tsgo, and ttsx binaries so the host never * searches PATH, sets `TTSC_PLUGIN_CONFIG_DIR` when the caller declared a * plugin config anchor (an embedder compiling through a generated wrapper * tsconfig) so config-file discovery walks the real project instead of the * wrapper's temp-dir ancestry, and forwards linked transform plugins via * `TTSC_LINKED_PLUGINS_JSON`. */ function residentEnv(context, tsgoBinary, nativePlugins) { const pluginConfigDir = (0, sharedHostHelpers_1.resolvePluginConfigDir)(context); const env = { ...process.env, TTSC_NODE_BINARY: process.env.TTSC_NODE_BINARY ?? process.execPath, ...(pluginConfigDir === undefined ? {} : { TTSC_PLUGIN_CONFIG_DIR: pluginConfigDir }), TTSC_TSGO_BINARY: process.env.TTSC_TSGO_BINARY ?? tsgoBinary, TTSC_TTSX_BINARY: process.env.TTSC_TTSX_BINARY ?? node_path_1.default.join(__dirname, "..", "..", "launcher", "ttsx.js"), ...context.env, }; // The anchor is per-invocation state owned by this host: when this run // declared none (and the caller's env does not name one), drop any value // inherited from an ancestor ttsc process so a nested build never // mis-anchors its plugins at the outer project. if (pluginConfigDir === undefined && context.env?.TTSC_PLUGIN_CONFIG_DIR === undefined) { delete env.TTSC_PLUGIN_CONFIG_DIR; } const linked = (0, sharedHostHelpers_1.linkedTransformPlugins)(nativePlugins); if (linked.length !== 0) { env.TTSC_LINKED_PLUGINS_JSON = serializeNativePlugins(linked); } return env; } /** * Serialize the plugin list to the `--plugins-json` / * `TTSC_LINKED_PLUGINS_JSON` shape the native host reads: only the fields it * needs, to keep the arg short. */ function serializeNativePlugins(plugins) { return JSON.stringify(plugins.map((plugin) => ({ config: plugin.config, name: plugin.name, stage: plugin.stage, }))); } //# sourceMappingURL=startResidentTransform.js.map