ttsc 0.4.0-dev.20260424 → 0.4.0-dev.20260425

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,19 +1,21 @@
1
1
  # `ttsc`
2
2
 
3
- ![banner of ttsc and ttsx](https://private-user-images.githubusercontent.com/13158709/583518390-6df1deb5-9e8c-4f4b-9d0f-eae1cc3bb55c.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NzcwNTQ2NzUsIm5iZiI6MTc3NzA1NDM3NSwicGF0aCI6Ii8xMzE1ODcwOS81ODM1MTgzOTAtNmRmMWRlYjUtOWU4Yy00ZjRiLTlkMGYtZWFlMWNjM2JiNTVjLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjA0MjQlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwNDI0VDE4MTI1NVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTEzMzUxNTE4YThlZDYyNDZjYTVjYmRiMmZiYzAwYzYyZTkyNDk4MjVlYmI4OGZkYjE3NDllNWQzY2IxNmRhYWEmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT1pbWFnZSUyRnBuZyJ9.7MYb2S99lZfQV-BqD09ZrZwdj1C3XDyJ9nkaSEr901M)
3
+ ![banner of ttsc](https://raw.githubusercontent.com/samchon/ttsc/refs/heads/master/assets/og.jpg)
4
4
 
5
5
  [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/samchon/ttsc/blob/master/LICENSE)
6
6
  [![NPM Version](https://img.shields.io/npm/v/ttsc.svg)](https://www.npmjs.com/package/ttsc)
7
7
  [![NPM Downloads](https://img.shields.io/npm/dm/ttsc.svg)](https://www.npmjs.com/package/ttsc)
8
8
  [![Build Status](https://github.com/samchon/ttsc/workflows/test/badge.svg)](https://github.com/samchon/ttsc/actions?query=workflow%3Atest)
9
9
 
10
- A `typescript-go` compiler host for build-time transforms.
10
+ A `typescript-go` toolchain for compiler-powered transforms and type-safe execution.
11
11
 
12
- - **Build and check**: run the project through the native TypeScript compiler lane.
13
- - **Transformer support**: load `compilerOptions.plugins` from `tsconfig.json`.
14
- - **Library author surface**: publish `ttsc` plugins with native backends or JS output hooks.
12
+ - **`ttsc`**: build, check, and transform.
13
+ - **`ttsx`**: execute TypeScript with type checking.
14
+ - 10x faster than `ts-node`.
15
+ - type checking that `tsx` does not provide.
16
+ - **transformer support**: compiler-powered libraries, such as `typia`.
15
17
 
16
- `ttsc` is the compiler host used by `ttsx`. Use `ttsc` when you want one project-aware path for type checking, JavaScript emit, transformer loading, and native backend selection.
18
+ > `ttsx` (CLI command) can run existing `typescript@6` projects.
17
19
 
18
20
  ## Setup
19
21
 
@@ -23,18 +25,18 @@ Install the native TypeScript preview package with `ttsc`:
23
25
  npm i -D ttsc @typescript/native-preview
24
26
  ```
25
27
 
26
- Build, check, or watch the project:
28
+ Run TypeScript directly with `ttsx` (CLI command):
27
29
 
28
30
  ```bash
29
- npx ttsc
30
- npx ttsc --noEmit
31
- npx ttsc --watch
31
+ npx ttsx src/index.ts
32
32
  ```
33
33
 
34
- Transform a single file:
34
+ Build, check, or watch the project with `ttsc`:
35
35
 
36
36
  ```bash
37
- npx ttsc transform --file src/index.ts
37
+ npx ttsc
38
+ npx ttsc --noEmit
39
+ npx ttsc --watch
38
40
  ```
39
41
 
40
42
  ## Transformer Configuration
@@ -51,7 +53,7 @@ npx ttsc transform --file src/index.ts
51
53
  }
52
54
  ```
53
55
 
54
- The same configuration is used by `ttsc` and `ttsx`.
56
+ The same configuration is used by both `ttsc` commands.
55
57
 
56
58
  ```bash
57
59
  # compile
@@ -61,250 +63,65 @@ npx ttsc
61
63
  npx ttsx src/index.ts
62
64
  ```
63
65
 
64
- This gives compiler-powered libraries one transform path for build-time and runtime execution.
65
-
66
- ## CLI
66
+ This gives compiler-powered libraries one transform path for both build-time and runtime execution.
67
67
 
68
- ```bash
69
- ttsc [options]
70
- ttsc transform --file <path> [options]
71
- ttsc version
72
- ```
68
+ ## What Is a Transform?
73
69
 
74
- Common commands:
75
-
76
- ```bash
77
- ttsc
78
- ttsc -p tsconfig.json
79
- ttsc --noEmit
80
- ttsc --watch
81
- ttsc --outDir lib
82
- ttsc --verbose
83
- ttsc transform --file src/index.ts
84
- ttsc transform --file src/index.ts --out tmp/index.js
85
- ```
86
-
87
- Supported options:
88
-
89
- - `-p, --project <file>`: resolve project settings from this config file.
90
- - `--tsconfig <file>`: alias for an explicit project config file.
91
- - `--cwd <dir>`: resolve project-relative paths from another directory.
92
- - `--emit`: force emitted files during build.
93
- - `--noEmit`: type check and transform without writing emitted files.
94
- - `-w, --watch`: rebuild when project files change.
95
- - `--preserveWatchOutput`: keep watch output on screen.
96
- - `--outDir <dir>`: override `compilerOptions.outDir`.
97
- - `--rewrite-mode <mode>`: force a native rewrite backend id.
98
- - `--quiet`: keep native build output quiet.
99
- - `--verbose`: print the native build summary and emitted files.
100
- - `--out <path>`: write single-file transform output to a file.
101
- - `--binary <path>`: use an explicit native backend binary.
102
-
103
- Compatibility aliases:
104
-
105
- ```bash
106
- ttsc build
107
- ttsc check
108
- ```
109
-
110
- `ttsc build` is the same project build lane as `ttsc`. `ttsc check` is the same as `ttsc --noEmit`.
111
-
112
- ## JS API
113
-
114
- `ttsc` exposes a small JS API for bundlers, runners, and higher-level tools.
70
+ A transform uses TypeScript types to generate JavaScript before runtime.
115
71
 
116
72
  ```ts
117
- import { build, check, transform, version } from "ttsc";
118
- ```
73
+ import typia, { tags } from "typia";
74
+ import { v4 } from "uuid";
119
75
 
120
- Transform one file:
121
-
122
- ```ts
123
- import { transform } from "ttsc";
124
-
125
- const code = transform({
126
- cwd: "/project",
127
- file: "/project/src/index.ts",
128
- tsconfig: "/project/tsconfig.json",
129
- });
130
- ```
131
-
132
- Build or check a project:
133
-
134
- ```ts
135
- import { build, check } from "ttsc";
136
-
137
- const built = build({
138
- cwd: process.cwd(),
139
- tsconfig: "tsconfig.json",
140
- emit: true,
141
- });
142
-
143
- if (built.status !== 0) {
144
- console.error(built.stderr);
145
- }
146
-
147
- const checked = check({
148
- tsconfig: "tsconfig.json",
76
+ const matched: boolean = typia.is<IMember>({
77
+ id: v4(),
78
+ email: "samchon.github@gmail.com",
79
+ age: 30,
149
80
  });
150
- ```
151
-
152
- `transform()` throws when the native compiler exits with an error. `build()` and `check()` return `{ status, stdout, stderr }`, so callers can decide how to surface compiler failures.
153
-
154
- ## Transformer Library Authors
155
-
156
- Transformer libraries publish a normal tsconfig plugin entry:
157
-
158
- ```json
159
- {
160
- "compilerOptions": {
161
- "plugins": [
162
- { "transform": "my-lib/lib/transform" }
163
- ]
164
- }
165
- }
166
- ```
167
-
168
- The `transform` value may be:
169
-
170
- - a package specifier.
171
- - an absolute path.
172
- - a relative path from the project root.
173
-
174
- The plugin module may export a plugin object directly, a default export, a `plugin` export, or a `createTtscPlugin` factory.
175
-
176
- ```ts
177
- import { definePlugin } from "ttsc";
178
-
179
- export default definePlugin((config, context) => ({
180
- name: "my-lib",
181
- native: {
182
- mode: "my-lib",
183
- binary: require.resolve("my-lib-native/bin/ttsc-my-lib.js"),
184
- contractVersion: 1,
185
- capabilities: ["rewrite", "diagnostics"],
186
- },
187
- }));
188
- ```
189
-
190
- The factory receives:
191
-
192
- - `config`: the raw `compilerOptions.plugins[]` entry.
193
- - `context.binary`: the fallback `ttsc` native binary path.
194
- - `context.cwd`: the invocation working directory.
195
- - `context.projectRoot`: the resolved project root.
196
- - `context.tsconfig`: the resolved config file path.
197
-
198
- Keep this Node-side entry small. Use it for package discovery, feature flags, native binary selection, and manifest construction. Put compiler-sensitive work in the native backend.
199
-
200
- ## Native Backend Contract
201
-
202
- A native transform plugin describes the backend that owns type analysis and rewrite work.
203
-
204
- ```ts
205
- import { definePlugin } from "ttsc";
206
-
207
- export default definePlugin(() => ({
208
- name: "my-lib",
209
- native: {
210
- mode: "my-lib",
211
- binary: require.resolve("my-lib-native/bin/ttsc-my-lib.js"),
212
- contractVersion: 1,
213
- capabilities: ["rewrite", "diagnostics", "assets"],
214
- },
215
- }));
216
- ```
217
-
218
- Descriptor shape:
219
-
220
- ```ts
221
- interface TtscNativeBackend {
222
- mode: string;
223
- binary?: string;
224
- contractVersion?: 1;
225
- capabilities?: readonly string[];
81
+ console.log(matched); // true
82
+
83
+ interface IMember {
84
+ id: string & tags.Format<"uuid">;
85
+ email: string & tags.Format<"email">;
86
+ age: number &
87
+ tags.Type<"uint32"> &
88
+ tags.ExclusiveMinimum<19> &
89
+ tags.Maximum<100>;
226
90
  }
227
91
  ```
228
92
 
229
- - `mode` is the rewrite backend id passed to the native compiler process.
230
- - `binary` points at a consumer-owned native binary.
231
- - `contractVersion` pins the plugin to the current host protocol.
232
- - `capabilities` records the backend responsibilities.
233
-
234
- The backend is responsible for the work old TypeScript transformer libraries used to do through in-process compiler APIs:
235
-
236
- - loading the project through the `typescript-go` lane.
237
- - finding marker calls such as `typia.is<T>()`.
238
- - analyzing types through native checker access or a serialized IR.
239
- - emitting replacement JavaScript.
240
- - reporting plugin-specific diagnostics.
241
- - emitting plugin-owned assets when needed.
242
-
243
- ## JS Output Hooks
244
-
245
- For text-level post-processing, a plugin can provide `transformOutput()`.
246
-
247
- ```ts
248
- import { definePlugin } from "ttsc";
249
-
250
- export default definePlugin((config) => ({
251
- name: "banner-plugin",
252
- transformOutput(context) {
253
- if (context.command === "build") {
254
- return `/* generated by ${config.transform} */\n${context.code}`;
255
- }
256
- return context.code;
257
- },
258
- }));
259
- ```
260
-
261
- `transformOutput()` receives JavaScript text after native emit. Use it for:
262
-
263
- - banner injection.
264
- - output string patching.
265
- - runtime helper import rewrites.
266
- - consumer-specific output normalization.
267
-
268
- Use a native backend for compiler-sensitive work:
269
-
270
- - type analysis.
271
- - AST mutation.
272
- - call-site recognition.
273
- - `ts.Program` / `ts.TypeChecker` transformer compatibility.
274
-
275
- ## Current Constraints
276
-
277
- These are current host constraints transformer authors should design around.
278
-
279
- - One invocation can select one native `mode` / `binary` pair.
280
- - Multiple text-only `transformOutput()` plugins can run in order.
281
- - Passing `plugins` to the JS API replaces the tsconfig plugin list.
282
- - `transformOutput()` is a JS text hook, not a JS AST hook.
283
- - The current setup lane is `@typescript/native-preview`.
284
-
285
- ## Integration Patterns
286
-
287
- Consumer library:
288
-
289
- - publish a tsconfig plugin entry such as `my-lib/lib/transform`.
290
- - resolve a consumer-owned native backend binary from that entry.
291
- - keep type analysis and rewrite logic in the native backend.
292
- - optionally layer `transformOutput()` for final JavaScript text normalization.
293
-
294
- Bundler adapter:
295
-
296
- - call `transform()` for per-file rewrites.
297
- - pass `plugins` when the adapter needs deterministic plugin state.
298
- - let `ttsc` resolve the native backend instead of spawning it manually.
299
-
300
- Runner:
301
-
302
- - use `ttsx` for direct execution.
303
- - reuse the same `compilerOptions.plugins` contract.
304
- - keep build-time and runtime transform behavior aligned.
93
+ It is transformed into dedicated JavaScript:
94
+
95
+ > ```js
96
+ > import typia from "typia";
97
+ > import * as __typia_transform__isFormatEmail from "typia/lib/internal/_isFormatEmail";
98
+ > import * as __typia_transform__isFormatUuid from "typia/lib/internal/_isFormatUuid";
99
+ > import * as __typia_transform__isTypeUint32 from "typia/lib/internal/_isTypeUint32";
100
+ > import { v4 } from "uuid";
101
+ >
102
+ > const matched = (() => {
103
+ > const _io0 = (input) =>
104
+ > "string" === typeof input.id &&
105
+ > __typia_transform__isFormatUuid._isFormatUuid(input.id) &&
106
+ > "string" === typeof input.email &&
107
+ > __typia_transform__isFormatEmail._isFormatEmail(input.email) &&
108
+ > "number" === typeof input.age &&
109
+ > __typia_transform__isTypeUint32._isTypeUint32(input.age) &&
110
+ > 19 < input.age &&
111
+ > input.age <= 100;
112
+ > return (input) => "object" === typeof input && null !== input && _io0(input);
113
+ > })()({
114
+ > id: v4(),
115
+ > email: "samchon.github@gmai19l.com",
116
+ > age: 30,
117
+ > });
118
+ > console.log(matched); // true
119
+ > ```
120
+
121
+ `ttsc` runs this transform during build, and `ttsx` runs through the same transform path during execution.
305
122
 
306
123
  ## References
307
124
 
308
125
  - TypeScript runners: [`ts-node`](https://github.com/TypeStrong/ts-node) and [`tsx`](https://github.com/privatenumber/tsx)
309
126
  - Transformer tooling: [`ttypescript`](https://github.com/cevek/ttypescript) and [`ts-patch`](https://github.com/nonara/ts-patch)
310
- - Inspired by: [`typical`](https://github.com/samchon/typical) and [`tsgonest`](https://github.com/samchon/tsgonest)
127
+ - Inspired by: [`typical`](https://github.com/elliots/typical) and [`tsgonest`](https://github.com/tsgonest/tsgonest)
package/lib/index.d.ts CHANGED
@@ -15,3 +15,4 @@ export * from "./platform";
15
15
  export * from "./api";
16
16
  export * from "./project";
17
17
  export * from "./plugin";
18
+ export * from "./runner/register";
package/lib/index.js CHANGED
@@ -31,4 +31,5 @@ __exportStar(require("./platform"), exports);
31
31
  __exportStar(require("./api"), exports);
32
32
  __exportStar(require("./project"), exports);
33
33
  __exportStar(require("./plugin"), exports);
34
+ __exportStar(require("./runner/register"), exports);
34
35
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;;;;;;;;;;;;;;;AAEH,6CAA2B;AAC3B,wCAAsB;AACtB,4CAA0B;AAC1B,2CAAyB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;;;;;;;;;;;;;;;AAEH,6CAA2B;AAC3B,wCAAsB;AACtB,4CAA0B;AAC1B,2CAAyB;AACzB,oDAAkC"}
@@ -0,0 +1 @@
1
+ export declare function main(argv?: readonly string[]): number;
@@ -0,0 +1,284 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.main = main;
37
+ const fs = __importStar(require("node:fs"));
38
+ const Module = require("node:module");
39
+ const node_child_process_1 = require("node:child_process");
40
+ const path = __importStar(require("node:path"));
41
+ const api_1 = require("../api");
42
+ const register_1 = require("./register");
43
+ function main(argv = process.argv.slice(2)) {
44
+ try {
45
+ return run(argv);
46
+ }
47
+ catch (error) {
48
+ process.stderr.write(`${formatError(error)}\n`);
49
+ return 2;
50
+ }
51
+ }
52
+ function run(argv) {
53
+ const parsed = parseCLI(argv);
54
+ if (parsed === "help") {
55
+ printHelp();
56
+ return 0;
57
+ }
58
+ if (parsed === "version") {
59
+ process.stdout.write(`${(0, api_1.version)().replace(/^ttsc\b/, "ttsx")}\n`);
60
+ return 0;
61
+ }
62
+ const cwd = path.resolve(parsed.cwd ?? process.cwd());
63
+ const entry = path.resolve(cwd, parsed.entry);
64
+ if (!fs.existsSync(entry)) {
65
+ process.stderr.write(`ttsx: entry not found: ${entry}\n`);
66
+ return 2;
67
+ }
68
+ const prepared = (0, register_1.prepareExecution)(entry, {
69
+ binary: parsed.binary,
70
+ cacheDir: parsed.cacheDir,
71
+ cwd,
72
+ env: parsed.env,
73
+ extensions: parsed.extensions,
74
+ project: parsed.project,
75
+ });
76
+ if (prepared.moduleKind === "esm") {
77
+ return runEsmEntry(parsed, prepared, cwd);
78
+ }
79
+ const unregister = (0, register_1.register)({
80
+ binary: parsed.binary,
81
+ cacheDir: parsed.cacheDir,
82
+ cwd,
83
+ env: parsed.env,
84
+ extensions: parsed.extensions,
85
+ project: parsed.project,
86
+ });
87
+ process.once("exit", unregister);
88
+ for (const preload of parsed.preload) {
89
+ require(resolvePreload(cwd, preload));
90
+ }
91
+ process.argv = [process.execPath, entry, ...parsed.passthrough];
92
+ Module.runMain();
93
+ return 0;
94
+ }
95
+ function formatError(error) {
96
+ if (error instanceof Error) {
97
+ return error.message;
98
+ }
99
+ return String(error);
100
+ }
101
+ function parseCLI(argv) {
102
+ const preload = [];
103
+ const passthroughIndex = argv.indexOf("--");
104
+ const head = passthroughIndex === -1 ? [...argv] : [...argv.slice(0, passthroughIndex)];
105
+ const passthrough = passthroughIndex === -1 ? [] : [...argv.slice(passthroughIndex + 1)];
106
+ let binary;
107
+ let cacheDir;
108
+ let cwd;
109
+ let entry;
110
+ let project;
111
+ while (head.length !== 0) {
112
+ const current = head.shift();
113
+ if (entry) {
114
+ passthrough.push(current, ...head);
115
+ break;
116
+ }
117
+ switch (current) {
118
+ case "-h":
119
+ case "--help":
120
+ return "help";
121
+ case "-v":
122
+ case "--version":
123
+ return "version";
124
+ case "-P":
125
+ case "--project":
126
+ project = takeValue(current, head);
127
+ break;
128
+ case "--cwd":
129
+ cwd = takeValue(current, head);
130
+ break;
131
+ case "--cache-dir":
132
+ cacheDir = takeValue(current, head);
133
+ break;
134
+ case "-r":
135
+ case "--require":
136
+ preload.push(takeValue(current, head));
137
+ break;
138
+ case "--binary":
139
+ binary = takeValue(current, head);
140
+ break;
141
+ default:
142
+ if (current.startsWith("--project=")) {
143
+ project = current.slice("--project=".length);
144
+ }
145
+ else if (current.startsWith("--cwd=")) {
146
+ cwd = current.slice("--cwd=".length);
147
+ }
148
+ else if (current.startsWith("--cache-dir=")) {
149
+ cacheDir = current.slice("--cache-dir=".length);
150
+ }
151
+ else if (current.startsWith("--binary=")) {
152
+ binary = current.slice("--binary=".length);
153
+ }
154
+ else if (current.startsWith("-")) {
155
+ throw new Error(`ttsx: unknown option ${current}`);
156
+ }
157
+ else {
158
+ entry = current;
159
+ }
160
+ break;
161
+ }
162
+ }
163
+ if (!entry) {
164
+ throw new Error("ttsx: entry file is required");
165
+ }
166
+ return {
167
+ binary,
168
+ cacheDir,
169
+ cwd,
170
+ entry,
171
+ passthrough,
172
+ preload,
173
+ project,
174
+ };
175
+ }
176
+ function printHelp() {
177
+ process.stdout.write([
178
+ "ttsx — TypeScript runner provided by ttsc.",
179
+ "",
180
+ "Usage:",
181
+ " ttsx [options] <entry.ts> [-- <argv...>]",
182
+ "",
183
+ "Options:",
184
+ " -P, --project <file> Use an explicit tsconfig.json",
185
+ " --cwd <dir> Resolve entry/project relative to this directory",
186
+ " --cache-dir <dir> Override the compiled JS cache directory",
187
+ " --binary <path> Use an explicit ttsc native binary",
188
+ " -r, --require <file> Preload a module before the entrypoint",
189
+ " -h, --help Show this help",
190
+ " -v, --version Print the runner version",
191
+ "",
192
+ "Runtime:",
193
+ " CommonJS projects execute in-process via the require hook.",
194
+ " ESM projects execute the cached emitted entry in a child Node process.",
195
+ "",
196
+ "Examples:",
197
+ " ttsx src/index.ts",
198
+ " ttsx --project tsconfig.json src/index.ts -- --port 3000",
199
+ ].join("\n"));
200
+ process.stdout.write("\n");
201
+ }
202
+ function resolvePreload(cwd, preload) {
203
+ if (preload.startsWith(".") || preload.startsWith("/") || preload.includes(path.sep)) {
204
+ return path.resolve(cwd, preload);
205
+ }
206
+ return preload;
207
+ }
208
+ function takeValue(flag, rest) {
209
+ const value = rest.shift();
210
+ if (!value) {
211
+ throw new Error(`ttsx: ${flag} requires a value`);
212
+ }
213
+ return value;
214
+ }
215
+ function runEsmEntry(parsed, execution, cwd) {
216
+ fs.mkdirSync(execution.emitDir, { recursive: true });
217
+ rewriteEsmSpecifiers(execution.emitDir);
218
+ fs.writeFileSync(path.join(execution.emitDir, "package.json"), JSON.stringify({ type: "module" }), "utf8");
219
+ const args = [
220
+ ...parsed.preload.flatMap((preload) => ["-r", resolvePreload(cwd, preload)]),
221
+ execution.entryFile,
222
+ ...parsed.passthrough,
223
+ ];
224
+ const result = (0, node_child_process_1.spawnSync)(process.execPath, args, {
225
+ stdio: "inherit",
226
+ env: process.env,
227
+ windowsHide: true,
228
+ });
229
+ if (result.error) {
230
+ process.stderr.write(`${result.error.message}\n`);
231
+ return 1;
232
+ }
233
+ return result.status ?? 1;
234
+ }
235
+ function rewriteEsmSpecifiers(root) {
236
+ const stack = [root];
237
+ while (stack.length !== 0) {
238
+ const current = stack.pop();
239
+ for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
240
+ const next = path.join(current, entry.name);
241
+ if (entry.isDirectory()) {
242
+ stack.push(next);
243
+ continue;
244
+ }
245
+ if (!entry.isFile() || !isJavaScriptOutput(next)) {
246
+ continue;
247
+ }
248
+ const before = fs.readFileSync(next, "utf8");
249
+ const after = before
250
+ .replace(/\bfrom\s+(['"])(\.[^'"]+)\1/g, (_, quote, specifier) => `from ${quote}${withResolvableExtension(next, specifier)}${quote}`)
251
+ .replace(/\bimport\(\s*(['"])(\.[^'"]+)\1\s*\)/g, (_, quote, specifier) => `import(${quote}${withResolvableExtension(next, specifier)}${quote})`);
252
+ if (after !== before) {
253
+ fs.writeFileSync(next, after, "utf8");
254
+ }
255
+ }
256
+ }
257
+ }
258
+ function withResolvableExtension(fromFile, specifier) {
259
+ if (!specifier.startsWith(".")) {
260
+ return specifier;
261
+ }
262
+ if (/\.(?:[cm]?js|json|node)$/i.test(specifier)) {
263
+ return specifier;
264
+ }
265
+ const [pathname, suffix = ""] = splitSpecifierSuffix(specifier);
266
+ const fromDir = path.dirname(fromFile);
267
+ for (const extension of [".js", ".mjs", ".cjs"]) {
268
+ if (fs.existsSync(path.resolve(fromDir, pathname + extension))) {
269
+ return pathname + extension + suffix;
270
+ }
271
+ }
272
+ return `${specifier}.js`;
273
+ }
274
+ function splitSpecifierSuffix(specifier) {
275
+ const index = specifier.search(/[?#]/);
276
+ if (index === -1) {
277
+ return [specifier];
278
+ }
279
+ return [specifier.slice(0, index), specifier.slice(index)];
280
+ }
281
+ function isJavaScriptOutput(filename) {
282
+ return /\.(?:[cm]?js)$/i.test(filename);
283
+ }
284
+ //# sourceMappingURL=cli.js.map