ttsc 0.12.3 → 0.13.0
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/cmd/platform/main.go +9 -0
- package/cmd/ttsc/api_compile.go +122 -101
- package/cmd/ttsc/api_compile_branches_test.go +55 -57
- package/cmd/ttsc/api_transform.go +67 -49
- package/cmd/ttsc/api_transform_branches_test.go +30 -32
- package/cmd/ttsc/build.go +141 -108
- package/cmd/ttsc/build_branches_test.go +95 -97
- package/cmd/ttsc/filter.go +70 -0
- package/cmd/ttsc/filter_strips_unknown_forwarded_flag_test.go +61 -0
- package/cmd/ttsc/flags_gen.go +30 -0
- package/cmd/ttsc/helpers_test.go +39 -28
- package/cmd/ttsc/main.go +111 -104
- package/cmd/ttsc/main_alias_branches_test.go +21 -23
- package/cmd/ttscserver/main.go +96 -90
- package/cmd/ttscserver/run_lsp_prefers_tsgo_flag_test.go +22 -22
- package/cmd/ttscserver/run_lsp_reports_server_error_test.go +22 -22
- package/cmd/ttscserver/run_lsp_uses_tsgo_environment_test.go +23 -23
- package/cmd/utility-host/main.go +30 -23
- package/driver/lsp.go +53 -7
- package/driver/plugins.go +88 -72
- package/driver/program.go +464 -340
- package/driver/rewrite.go +477 -380
- package/internal/lspserver/lsp_envelope.go +64 -64
- package/internal/lspserver/lsp_frame.go +60 -60
- package/internal/lspserver/lsp_plugin.go +57 -57
- package/internal/lspserver/lsp_proxy.go +265 -251
- package/internal/lspserver/lsp_server.go +155 -144
- package/lib/TtscCompiler.d.ts +7 -0
- package/lib/TtscCompiler.js +7 -0
- package/lib/TtscCompiler.js.map +1 -1
- package/lib/compiler/internal/buildNativeCompiler.d.ts +11 -1
- package/lib/compiler/internal/buildNativeCompiler.js +23 -3
- package/lib/compiler/internal/buildNativeCompiler.js.map +1 -1
- package/lib/compiler/internal/compileProjectInMemory.d.ts +9 -0
- package/lib/compiler/internal/compileProjectInMemory.js +36 -21
- package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
- package/lib/compiler/internal/paths.d.ts +27 -0
- package/lib/compiler/internal/paths.js +70 -0
- package/lib/compiler/internal/paths.js.map +1 -0
- package/lib/compiler/internal/project/readProjectConfig.d.ts +9 -1
- package/lib/compiler/internal/project/readProjectConfig.js +80 -1
- package/lib/compiler/internal/project/readProjectConfig.js.map +1 -1
- package/lib/compiler/internal/project/resolveProjectConfig.d.ts +13 -1
- package/lib/compiler/internal/project/resolveProjectConfig.js +42 -1
- package/lib/compiler/internal/project/resolveProjectConfig.js.map +1 -1
- package/lib/compiler/internal/resolveBinary.d.ts +9 -1
- package/lib/compiler/internal/resolveBinary.js +17 -1
- package/lib/compiler/internal/resolveBinary.js.map +1 -1
- package/lib/compiler/internal/resolveEmittedJavaScript.d.ts +16 -1
- package/lib/compiler/internal/resolveEmittedJavaScript.js +42 -10
- package/lib/compiler/internal/resolveEmittedJavaScript.js.map +1 -1
- package/lib/compiler/internal/resolveTsgo.d.ts +21 -1
- package/lib/compiler/internal/resolveTsgo.js +23 -1
- package/lib/compiler/internal/resolveTsgo.js.map +1 -1
- package/lib/compiler/internal/runBuild.d.ts +24 -4
- package/lib/compiler/internal/runBuild.js +355 -93
- package/lib/compiler/internal/runBuild.js.map +1 -1
- package/lib/compiler/internal/runSingleFileEmit.d.ts +10 -1
- package/lib/compiler/internal/runSingleFileEmit.js +14 -1
- package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
- package/lib/compiler/internal/sharedHostHelpers.d.ts +5 -0
- package/lib/compiler/internal/sharedHostHelpers.js +6 -2
- package/lib/compiler/internal/sharedHostHelpers.js.map +1 -1
- package/lib/compiler/internal/spawnNative.d.ts +21 -0
- package/lib/compiler/internal/spawnNative.js +59 -0
- package/lib/compiler/internal/spawnNative.js.map +1 -0
- package/lib/compiler/internal/transformProjectInMemory.d.ts +15 -1
- package/lib/compiler/internal/transformProjectInMemory.js +57 -61
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/flags/parser.d.ts +63 -0
- package/lib/flags/parser.js +254 -0
- package/lib/flags/parser.js.map +1 -0
- package/lib/flags/schema.d.ts +147 -0
- package/lib/flags/schema.js +405 -0
- package/lib/flags/schema.js.map +1 -0
- package/lib/launcher/internal/getCompilerVersionText.js +7 -0
- package/lib/launcher/internal/getCompilerVersionText.js.map +1 -1
- package/lib/launcher/internal/prepareExecution.js +35 -0
- package/lib/launcher/internal/prepareExecution.js.map +1 -1
- package/lib/launcher/internal/resolveCacheDir.d.ts +9 -0
- package/lib/launcher/internal/resolveCacheDir.js +22 -0
- package/lib/launcher/internal/resolveCacheDir.js.map +1 -0
- package/lib/launcher/internal/resolveTtscserverBinary.js +2 -0
- package/lib/launcher/internal/resolveTtscserverBinary.js.map +1 -1
- package/lib/launcher/internal/runTtsc.d.ts +10 -0
- package/lib/launcher/internal/runTtsc.js +90 -153
- package/lib/launcher/internal/runTtsc.js.map +1 -1
- package/lib/launcher/internal/runTtscserver.js +10 -35
- package/lib/launcher/internal/runTtscserver.js.map +1 -1
- package/lib/launcher/internal/runTtsx.d.ts +8 -0
- package/lib/launcher/internal/runTtsx.js +137 -79
- package/lib/launcher/internal/runTtsx.js.map +1 -1
- package/lib/plugin/internal/buildSourcePlugin.d.ts +38 -0
- package/lib/plugin/internal/buildSourcePlugin.js +40 -17
- package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/loadProjectPlugins.d.ts +26 -0
- package/lib/plugin/internal/loadProjectPlugins.js +90 -41
- package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
- package/lib/structures/ITtscCompilerTransformation.d.ts +15 -2
- package/lib/structures/ITtscPlugin.d.ts +24 -0
- package/lib/structures/ITtscPluginCapabilities.d.ts +29 -0
- package/lib/structures/ITtscPluginCapabilities.js +3 -0
- package/lib/structures/ITtscPluginCapabilities.js.map +1 -0
- package/lib/structures/index.d.ts +1 -0
- package/lib/structures/index.js +1 -0
- package/lib/structures/index.js.map +1 -1
- package/lib/structures/internal/ITtscLoadedNativePlugin.d.ts +5 -0
- package/lib/structures/internal/TtscCommonOptions.d.ts +19 -0
- package/lib/structures/internal/TtscSingleFileEmitOptions.d.ts +0 -2
- package/package.json +9 -9
- package/shim/ast/shim.go +24 -0
- package/shim/checker/shim.go +35 -0
- package/shim/core/shim.go +17 -0
- package/shim/diagnosticwriter/shim.go +4 -0
- package/shim/lsp/shim.go +3 -3
- package/shim/printer/shim.go +20 -0
- package/src/TtscCompiler.ts +7 -0
- package/src/compiler/internal/buildNativeCompiler.ts +23 -3
- package/src/compiler/internal/compileProjectInMemory.ts +34 -25
- package/src/compiler/internal/paths.ts +68 -0
- package/src/compiler/internal/project/readProjectConfig.ts +86 -1
- package/src/compiler/internal/project/resolveProjectConfig.ts +44 -1
- package/src/compiler/internal/resolveBinary.ts +17 -1
- package/src/compiler/internal/resolveEmittedJavaScript.ts +43 -12
- package/src/compiler/internal/resolveTsgo.ts +29 -1
- package/src/compiler/internal/runBuild.ts +398 -112
- package/src/compiler/internal/runSingleFileEmit.ts +14 -1
- package/src/compiler/internal/sharedHostHelpers.ts +7 -7
- package/src/compiler/internal/spawnNative.ts +64 -0
- package/src/compiler/internal/transformProjectInMemory.ts +47 -67
- package/src/flags/parser.ts +367 -0
- package/src/flags/schema.ts +570 -0
- package/src/launcher/internal/getCompilerVersionText.ts +7 -0
- package/src/launcher/internal/prepareExecution.ts +35 -0
- package/src/launcher/internal/resolveCacheDir.ts +19 -0
- package/src/launcher/internal/resolveTtscserverBinary.ts +2 -0
- package/src/launcher/internal/runTtsc.ts +97 -143
- package/src/launcher/internal/runTtscserver.ts +9 -1
- package/src/launcher/internal/runTtsx.ts +149 -82
- package/src/plugin/internal/buildSourcePlugin.ts +40 -14
- package/src/plugin/internal/loadProjectPlugins.ts +116 -45
- package/src/structures/ITtscCompilerTransformation.ts +15 -2
- package/src/structures/ITtscPlugin.ts +26 -1
- package/src/structures/ITtscPluginCapabilities.ts +29 -0
- package/src/structures/index.ts +1 -0
- package/src/structures/internal/ITtscLoadedNativePlugin.ts +5 -0
- package/src/structures/internal/TtscCommonOptions.ts +19 -0
- package/src/structures/internal/TtscSingleFileEmitOptions.ts +0 -2
- package/tools/gen_shims/main.go +43 -8
- package/utility/flags_gen.go +30 -0
- package/utility/host.go +304 -245
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
// SOURCE-OF-TRUTH FLAG SCHEMA for the ttsc / ttsx command-line surface.
|
|
2
|
+
//
|
|
3
|
+
// One declaration per flag, consumed by every layer that needs to know about
|
|
4
|
+
// the flag:
|
|
5
|
+
//
|
|
6
|
+
// * `packages/ttsc/src/flags/parser.ts` — runtime TS parsing engine used
|
|
7
|
+
// by `runTtsc.ts` and `runTtsx.ts`.
|
|
8
|
+
// * `packages/ttsc/scripts/gen-flags.cjs` — codegen that emits Go
|
|
9
|
+
// allow-lists and the docs table.
|
|
10
|
+
// * `packages/ttsc/cmd/ttsc/flags_gen.go` — generated Go allow-list shared
|
|
11
|
+
// by `cmd/ttsc/*.go` and
|
|
12
|
+
// `utility/host.go`.
|
|
13
|
+
// * `packages/lint/linthost/flags_gen.go` — generated Go allow-list shared
|
|
14
|
+
// by lint subcommand parsers.
|
|
15
|
+
// * `website/src/content/docs/ttsc/flags.mdx` — generated reference table.
|
|
16
|
+
//
|
|
17
|
+
// The generator runs from `pnpm format`; its committed output is the spec the
|
|
18
|
+
// Go side reads, just like the `gen_shims:hand-maintained` pattern from
|
|
19
|
+
// AGENTS.md §2.1. Editing the generated files by hand is rejected by the
|
|
20
|
+
// `format` check.
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Subcommands the ttsc CLI dispatches to. The bare `"ttsc"` entry covers the
|
|
24
|
+
* default lane (no explicit subcommand, e.g. `ttsc -p tsconfig.json`).
|
|
25
|
+
*/
|
|
26
|
+
export type TtscSubcommand =
|
|
27
|
+
| "ttsc"
|
|
28
|
+
| "build"
|
|
29
|
+
| "check"
|
|
30
|
+
| "fix"
|
|
31
|
+
| "format"
|
|
32
|
+
| "prepare"
|
|
33
|
+
| "clean";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Subcommands the ttsx CLI dispatches to. ttsx exposes a single lane today
|
|
37
|
+
* but the schema mirrors ttsc's shape so future subcommands plug in without a
|
|
38
|
+
* second engine.
|
|
39
|
+
*/
|
|
40
|
+
export type TtsxSubcommand = "ttsx";
|
|
41
|
+
|
|
42
|
+
export type AnySubcommand = TtscSubcommand | TtsxSubcommand;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Layers a flag can be consumed by. The order reflects the runtime pipeline:
|
|
46
|
+
*
|
|
47
|
+
* launcher → runBuild → tsgo / native sidecars (host, lint).
|
|
48
|
+
*
|
|
49
|
+
* A flag must declare at least one consumer. `forwardTo` declares where the
|
|
50
|
+
* flag travels when the consuming layer does not absorb it (e.g. ttsc-owned
|
|
51
|
+
* flags that the JS launcher consumes and re-emits as different tsgo flags).
|
|
52
|
+
*/
|
|
53
|
+
export type FlagLayer =
|
|
54
|
+
| "launcher" // JS layer (`runTtsc.ts` / `runTtsx.ts`)
|
|
55
|
+
| "runBuild" // JS layer (`runBuild.ts`) — internally adds the flag to tsgo
|
|
56
|
+
| "tsgo" // tsgo binary (TypeScript-Go option parser)
|
|
57
|
+
| "host" // native shared host (`utility/host.go`, `cmd/ttsc/build.go`)
|
|
58
|
+
| "lint"; // native lint subcommand (`packages/lint/linthost/*.go`)
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Argument shape of a flag.
|
|
62
|
+
*
|
|
63
|
+
* * `boolean` — `--flag` / `--flag=true` / `--flag=false`. No value
|
|
64
|
+
* token is consumed.
|
|
65
|
+
* * `value` — `--flag value` or `--flag=value`. Required value.
|
|
66
|
+
* * `valueOptional` — `--flag` standalone is allowed; if followed by a
|
|
67
|
+
* non-flag token that token is consumed as the value.
|
|
68
|
+
* (Currently unused — declared for future flags like
|
|
69
|
+
* `--watch [path]`.)
|
|
70
|
+
*/
|
|
71
|
+
export type FlagKind = "boolean" | "value" | "valueOptional";
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Validation predicate for `value`-kind flags. `none` is the default
|
|
75
|
+
* (accept any string).
|
|
76
|
+
*/
|
|
77
|
+
export type ValueValidator = "none" | "positiveInt";
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* One CLI flag's complete contract. Every layer's behaviour is structural —
|
|
81
|
+
* which subcommands accept the flag, where it is consumed, where it is
|
|
82
|
+
* forwarded, whether it is terminal (prints and exits) — so the next layer
|
|
83
|
+
* never silently drops the flag.
|
|
84
|
+
*/
|
|
85
|
+
export interface FlagSpec {
|
|
86
|
+
/**
|
|
87
|
+
* Canonical flag name including leading dashes (`"--singleThreaded"`). The
|
|
88
|
+
* generator uses this as the map key in the Go allow-list and as the first
|
|
89
|
+
* column of the docs table.
|
|
90
|
+
*/
|
|
91
|
+
readonly name: string;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Alternative spellings (`"-p"`, `"--project"` for `--tsconfig`). The
|
|
95
|
+
* parsing engine treats every alias as an equivalent of `name`.
|
|
96
|
+
*/
|
|
97
|
+
readonly aliases?: readonly string[];
|
|
98
|
+
|
|
99
|
+
/** Argument shape: boolean / required value / optional value. */
|
|
100
|
+
readonly kind: FlagKind;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* For `value` flags: optional validator. `positiveInt` mirrors the
|
|
104
|
+
* `--checkers minValue:1` constraint tsgo enforces.
|
|
105
|
+
*/
|
|
106
|
+
readonly validator?: ValueValidator;
|
|
107
|
+
|
|
108
|
+
/** Subcommands that accept this flag. */
|
|
109
|
+
readonly subcommands: readonly AnySubcommand[];
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Layers that read the flag into a typed option. Order matters only for
|
|
113
|
+
* documentation; the parsing engine merges across layers.
|
|
114
|
+
*/
|
|
115
|
+
readonly consumedBy: readonly FlagLayer[];
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Where the flag travels when the consuming layer does not absorb it.
|
|
119
|
+
* Default for any flag a layer does not consume is `"tsgo"` — i.e. the
|
|
120
|
+
* launcher forwards an unknown flag to tsgo via passthrough. Setting this
|
|
121
|
+
* to `undefined` while `consumedBy: ["launcher"]` is set means the flag is
|
|
122
|
+
* intentionally consumed-not-forwarded (e.g. ttsc-internal `--binary`).
|
|
123
|
+
*/
|
|
124
|
+
readonly forwardTo?: FlagLayer;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Terminal flags ask the underlying tool to print something and exit
|
|
128
|
+
* (`--help`, `--version`, `--showConfig`, `--listFilesOnly`, `--all`,
|
|
129
|
+
* `--init`). ttsc must not wrap them in a pre-emit pass — that is how the
|
|
130
|
+
* `--showConfig prints twice` bug appeared (RC-2).
|
|
131
|
+
*/
|
|
132
|
+
readonly terminal?: boolean;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* `true` when ttsc may add this flag to tsgo internally and post-process
|
|
136
|
+
* the output. If the user also forwards the same flag, ttsc keeps the
|
|
137
|
+
* user-visible behaviour (no double-print, no swallowed output). The
|
|
138
|
+
* shadow check is structural rather than `passthrough.includes("…")`.
|
|
139
|
+
*
|
|
140
|
+
* Currently true for `--listEmittedFiles`, `--noEmit`, `--pretty`.
|
|
141
|
+
*/
|
|
142
|
+
readonly internalShadow?: boolean;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Reserved for future use: native hosts that opt in via
|
|
146
|
+
* `capabilities.threadingArgs`. The flag travels to such hosts as a bare
|
|
147
|
+
* CLI argument; everything else routes through `--tsgo-args`.
|
|
148
|
+
*/
|
|
149
|
+
readonly nativeCapability?: "threadingArgs";
|
|
150
|
+
|
|
151
|
+
/** Human description for `--help` and the docs table. */
|
|
152
|
+
readonly description: string;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Single source of truth for every flag the ttsc / ttsx CLI accepts. New
|
|
157
|
+
* flags are added here and only here; the generator rebuilds the parsers and
|
|
158
|
+
* the Go allow-lists from this table.
|
|
159
|
+
*
|
|
160
|
+
* Constraints enforced by the parser and the generator:
|
|
161
|
+
*
|
|
162
|
+
* 1. Every flag is uniquely identified by `name`; aliases must not collide
|
|
163
|
+
* with other flags' `name` or `aliases`.
|
|
164
|
+
* 2. A flag listed in `consumedBy: ["launcher"]` without a `forwardTo`
|
|
165
|
+
* consumes-not-forwards. The generator flags this in the docs and the
|
|
166
|
+
* Go allow-list so the boundary is explicit.
|
|
167
|
+
* 3. A flag with `subcommands` covering `clean` or `prepare` is parsed by
|
|
168
|
+
* the project-args lane; the parsing engine accepts the same flag in
|
|
169
|
+
* build / check / fix / format without a separate parser.
|
|
170
|
+
*/
|
|
171
|
+
export const FLAG_SCHEMA: readonly FlagSpec[] = [
|
|
172
|
+
// -------------------------------------------------------------------------
|
|
173
|
+
// ttsc — terminal flags (print and exit; never wrapped in pre-emit pass)
|
|
174
|
+
// -------------------------------------------------------------------------
|
|
175
|
+
{
|
|
176
|
+
name: "--help",
|
|
177
|
+
aliases: ["-h"],
|
|
178
|
+
kind: "boolean",
|
|
179
|
+
subcommands: ["ttsc", "ttsx", "build", "check", "fix", "format"],
|
|
180
|
+
consumedBy: ["launcher"],
|
|
181
|
+
terminal: true,
|
|
182
|
+
description: "Show command help and exit.",
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: "--version",
|
|
186
|
+
aliases: ["-v"],
|
|
187
|
+
kind: "boolean",
|
|
188
|
+
subcommands: ["ttsc", "ttsx"],
|
|
189
|
+
consumedBy: ["launcher"],
|
|
190
|
+
terminal: true,
|
|
191
|
+
description: "Print the launcher version and exit.",
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
// -------------------------------------------------------------------------
|
|
195
|
+
// Project location: shared by every subcommand.
|
|
196
|
+
// -------------------------------------------------------------------------
|
|
197
|
+
{
|
|
198
|
+
name: "--tsconfig",
|
|
199
|
+
aliases: ["-p", "--project"],
|
|
200
|
+
kind: "value",
|
|
201
|
+
subcommands: [
|
|
202
|
+
"ttsc",
|
|
203
|
+
"ttsx",
|
|
204
|
+
"build",
|
|
205
|
+
"check",
|
|
206
|
+
"fix",
|
|
207
|
+
"format",
|
|
208
|
+
"prepare",
|
|
209
|
+
"clean",
|
|
210
|
+
],
|
|
211
|
+
consumedBy: ["launcher", "host", "lint"],
|
|
212
|
+
description: "Resolve project settings from this tsconfig.",
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
name: "--cwd",
|
|
216
|
+
kind: "value",
|
|
217
|
+
subcommands: [
|
|
218
|
+
"ttsc",
|
|
219
|
+
"ttsx",
|
|
220
|
+
"build",
|
|
221
|
+
"check",
|
|
222
|
+
"fix",
|
|
223
|
+
"format",
|
|
224
|
+
"prepare",
|
|
225
|
+
"clean",
|
|
226
|
+
],
|
|
227
|
+
consumedBy: ["launcher", "host", "lint"],
|
|
228
|
+
description: "Resolve project-relative paths from this directory.",
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
// -------------------------------------------------------------------------
|
|
232
|
+
// Emit / build mode.
|
|
233
|
+
// -------------------------------------------------------------------------
|
|
234
|
+
{
|
|
235
|
+
name: "--emit",
|
|
236
|
+
kind: "boolean",
|
|
237
|
+
subcommands: ["ttsc", "build", "check"],
|
|
238
|
+
consumedBy: ["launcher", "runBuild", "host", "lint"],
|
|
239
|
+
description: "Force emitted files during build.",
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
name: "--noEmit",
|
|
243
|
+
kind: "boolean",
|
|
244
|
+
subcommands: ["ttsc", "build", "check"],
|
|
245
|
+
consumedBy: ["launcher", "runBuild", "host", "lint"],
|
|
246
|
+
internalShadow: true,
|
|
247
|
+
description: "Force analysis-only build with no file writes.",
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
name: "--outDir",
|
|
251
|
+
kind: "value",
|
|
252
|
+
subcommands: ["ttsc", "build", "check"],
|
|
253
|
+
consumedBy: ["launcher", "host", "lint"],
|
|
254
|
+
description: "Override compilerOptions.outDir for this invocation.",
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
// -------------------------------------------------------------------------
|
|
258
|
+
// Watch mode (launcher only).
|
|
259
|
+
// -------------------------------------------------------------------------
|
|
260
|
+
{
|
|
261
|
+
name: "--watch",
|
|
262
|
+
aliases: ["-w"],
|
|
263
|
+
kind: "boolean",
|
|
264
|
+
subcommands: ["ttsc", "build", "check"],
|
|
265
|
+
consumedBy: ["launcher"],
|
|
266
|
+
description: "Rebuild when project files change.",
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
name: "--preserveWatchOutput",
|
|
270
|
+
kind: "boolean",
|
|
271
|
+
subcommands: ["ttsc", "build", "check"],
|
|
272
|
+
consumedBy: ["launcher"],
|
|
273
|
+
description: "Do not clear the screen between watch rebuilds.",
|
|
274
|
+
},
|
|
275
|
+
|
|
276
|
+
// -------------------------------------------------------------------------
|
|
277
|
+
// Output verbosity.
|
|
278
|
+
// -------------------------------------------------------------------------
|
|
279
|
+
{
|
|
280
|
+
name: "--quiet",
|
|
281
|
+
kind: "boolean",
|
|
282
|
+
subcommands: ["ttsc", "build", "check", "fix", "format"],
|
|
283
|
+
consumedBy: ["launcher", "host", "lint"],
|
|
284
|
+
description: "Keep build output quiet (default).",
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
name: "--verbose",
|
|
288
|
+
kind: "boolean",
|
|
289
|
+
subcommands: ["ttsc", "build", "check", "fix", "format"],
|
|
290
|
+
consumedBy: ["launcher", "host", "lint"],
|
|
291
|
+
description: "Print the build summary and emitted files.",
|
|
292
|
+
},
|
|
293
|
+
|
|
294
|
+
// -------------------------------------------------------------------------
|
|
295
|
+
// tsgo-binary / cache plumbing (consumed by launcher, not forwarded).
|
|
296
|
+
// -------------------------------------------------------------------------
|
|
297
|
+
{
|
|
298
|
+
name: "--binary",
|
|
299
|
+
kind: "value",
|
|
300
|
+
subcommands: [
|
|
301
|
+
"ttsc",
|
|
302
|
+
"ttsx",
|
|
303
|
+
"build",
|
|
304
|
+
"check",
|
|
305
|
+
"fix",
|
|
306
|
+
"format",
|
|
307
|
+
"prepare",
|
|
308
|
+
"clean",
|
|
309
|
+
],
|
|
310
|
+
consumedBy: ["launcher"],
|
|
311
|
+
description: "Use an explicit tsgo binary.",
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
name: "--cache-dir",
|
|
315
|
+
kind: "value",
|
|
316
|
+
subcommands: [
|
|
317
|
+
"ttsc",
|
|
318
|
+
"ttsx",
|
|
319
|
+
"build",
|
|
320
|
+
"check",
|
|
321
|
+
"fix",
|
|
322
|
+
"format",
|
|
323
|
+
"prepare",
|
|
324
|
+
"clean",
|
|
325
|
+
],
|
|
326
|
+
consumedBy: ["launcher"],
|
|
327
|
+
description: "Override the runner and source-plugin cache root.",
|
|
328
|
+
},
|
|
329
|
+
|
|
330
|
+
// -------------------------------------------------------------------------
|
|
331
|
+
// Threading (tsgo-native; lint host opts in via capability).
|
|
332
|
+
// -------------------------------------------------------------------------
|
|
333
|
+
{
|
|
334
|
+
name: "--singleThreaded",
|
|
335
|
+
kind: "boolean",
|
|
336
|
+
subcommands: ["ttsc", "ttsx", "build", "check", "fix", "format"],
|
|
337
|
+
consumedBy: ["launcher", "runBuild", "tsgo", "host", "lint"],
|
|
338
|
+
nativeCapability: "threadingArgs",
|
|
339
|
+
description: "Run TypeScript-Go single-threaded (one checker).",
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
name: "--checkers",
|
|
343
|
+
kind: "value",
|
|
344
|
+
validator: "positiveInt",
|
|
345
|
+
subcommands: ["ttsc", "ttsx", "build", "check", "fix", "format"],
|
|
346
|
+
consumedBy: ["launcher", "runBuild", "tsgo", "host", "lint"],
|
|
347
|
+
nativeCapability: "threadingArgs",
|
|
348
|
+
description: "Type-checker pool size (default: TypeScript-Go's).",
|
|
349
|
+
},
|
|
350
|
+
|
|
351
|
+
// -------------------------------------------------------------------------
|
|
352
|
+
// ttsx-specific options.
|
|
353
|
+
// -------------------------------------------------------------------------
|
|
354
|
+
{
|
|
355
|
+
name: "--require",
|
|
356
|
+
aliases: ["-r"],
|
|
357
|
+
kind: "value",
|
|
358
|
+
subcommands: ["ttsx"],
|
|
359
|
+
consumedBy: ["launcher"],
|
|
360
|
+
description: "Preload a module before the entrypoint (ttsx).",
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
name: "--no-plugins",
|
|
364
|
+
kind: "boolean",
|
|
365
|
+
subcommands: ["ttsx"],
|
|
366
|
+
consumedBy: ["launcher"],
|
|
367
|
+
description: "Build the project without ttsc plugins (ttsx).",
|
|
368
|
+
},
|
|
369
|
+
|
|
370
|
+
// -------------------------------------------------------------------------
|
|
371
|
+
// tsgo-internal flags ttsc adds itself; users may also forward them.
|
|
372
|
+
// Declaring them keeps the launcher's parser from treating them as
|
|
373
|
+
// unknown forwarded flags whose value token gets misclassified.
|
|
374
|
+
// -------------------------------------------------------------------------
|
|
375
|
+
{
|
|
376
|
+
name: "--listEmittedFiles",
|
|
377
|
+
kind: "boolean",
|
|
378
|
+
subcommands: ["ttsc", "build", "check"],
|
|
379
|
+
consumedBy: ["runBuild", "tsgo"],
|
|
380
|
+
forwardTo: "tsgo",
|
|
381
|
+
internalShadow: true,
|
|
382
|
+
description:
|
|
383
|
+
"Print the list of emitted files (forwarded to tsgo; ttsc keeps the lines when forwarded).",
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
name: "--pretty",
|
|
387
|
+
kind: "value",
|
|
388
|
+
subcommands: ["ttsc", "ttsx", "build", "check", "fix", "format"],
|
|
389
|
+
consumedBy: ["tsgo"],
|
|
390
|
+
forwardTo: "tsgo",
|
|
391
|
+
internalShadow: true,
|
|
392
|
+
description: "Toggle tsgo pretty-printed diagnostics (forwarded to tsgo).",
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
name: "--showConfig",
|
|
396
|
+
kind: "boolean",
|
|
397
|
+
subcommands: ["ttsc", "build", "check"],
|
|
398
|
+
consumedBy: ["tsgo"],
|
|
399
|
+
forwardTo: "tsgo",
|
|
400
|
+
terminal: true,
|
|
401
|
+
description: "Print the resolved tsconfig and exit (forwarded to tsgo).",
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
name: "--listFilesOnly",
|
|
405
|
+
kind: "boolean",
|
|
406
|
+
subcommands: ["ttsc", "build", "check"],
|
|
407
|
+
consumedBy: ["tsgo"],
|
|
408
|
+
forwardTo: "tsgo",
|
|
409
|
+
terminal: true,
|
|
410
|
+
description: "Print the project file list and exit (forwarded to tsgo).",
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
name: "--all",
|
|
414
|
+
kind: "boolean",
|
|
415
|
+
subcommands: ["ttsc", "build", "check"],
|
|
416
|
+
consumedBy: ["tsgo"],
|
|
417
|
+
forwardTo: "tsgo",
|
|
418
|
+
terminal: true,
|
|
419
|
+
description: "Print the full tsgo CLI help and exit.",
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
name: "--init",
|
|
423
|
+
kind: "boolean",
|
|
424
|
+
subcommands: ["ttsc", "build", "check"],
|
|
425
|
+
consumedBy: ["tsgo"],
|
|
426
|
+
forwardTo: "tsgo",
|
|
427
|
+
terminal: true,
|
|
428
|
+
description: "Write a starter tsconfig.json and exit (forwarded to tsgo).",
|
|
429
|
+
},
|
|
430
|
+
|
|
431
|
+
// -------------------------------------------------------------------------
|
|
432
|
+
// `--tsgo-args` — JSON-encoded passthrough envelope the launcher emits on
|
|
433
|
+
// the way down to native sidecars. The sidecars decode it back into the
|
|
434
|
+
// tsgo argv. Listed here so the schema describes every flag the Go layers
|
|
435
|
+
// accept, not just the user-facing ones.
|
|
436
|
+
// -------------------------------------------------------------------------
|
|
437
|
+
{
|
|
438
|
+
name: "--tsgo-args",
|
|
439
|
+
kind: "value",
|
|
440
|
+
subcommands: [
|
|
441
|
+
"ttsc",
|
|
442
|
+
"build",
|
|
443
|
+
"check",
|
|
444
|
+
"fix",
|
|
445
|
+
"format",
|
|
446
|
+
"prepare",
|
|
447
|
+
"clean",
|
|
448
|
+
],
|
|
449
|
+
consumedBy: ["host", "lint"],
|
|
450
|
+
description:
|
|
451
|
+
"JSON-encoded tsgo passthrough argv (internal: emitted by runBuild).",
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
name: "--plugins-json",
|
|
455
|
+
kind: "value",
|
|
456
|
+
subcommands: ["build", "check", "fix", "format"],
|
|
457
|
+
consumedBy: ["host", "lint"],
|
|
458
|
+
description:
|
|
459
|
+
"JSON-encoded ttsc plugin manifest (internal: emitted by runBuild).",
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
name: "--manifest",
|
|
463
|
+
kind: "value",
|
|
464
|
+
subcommands: ["build"],
|
|
465
|
+
consumedBy: ["host"],
|
|
466
|
+
description:
|
|
467
|
+
"Write emitted file list as JSON to this path (host build only).",
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
name: "--file",
|
|
471
|
+
kind: "value",
|
|
472
|
+
subcommands: ["build", "check"],
|
|
473
|
+
consumedBy: ["lint"],
|
|
474
|
+
description:
|
|
475
|
+
"Absolute or cwd-relative path of the .ts file to transform (lint transform only).",
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
name: "--out",
|
|
479
|
+
kind: "value",
|
|
480
|
+
subcommands: ["build", "check"],
|
|
481
|
+
consumedBy: ["lint"],
|
|
482
|
+
description:
|
|
483
|
+
"Write transform output to PATH (lint transform only; default: stdout).",
|
|
484
|
+
},
|
|
485
|
+
];
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Lookup of `name` and every alias → its canonical FlagSpec. Built once at
|
|
489
|
+
* module load so the parsing engine has O(1) flag resolution.
|
|
490
|
+
*/
|
|
491
|
+
export const FLAG_BY_NAME: ReadonlyMap<string, FlagSpec> = buildFlagIndex();
|
|
492
|
+
|
|
493
|
+
function buildFlagIndex(): ReadonlyMap<string, FlagSpec> {
|
|
494
|
+
const index = new Map<string, FlagSpec>();
|
|
495
|
+
for (const flag of FLAG_SCHEMA) {
|
|
496
|
+
register(index, flag.name, flag);
|
|
497
|
+
for (const alias of flag.aliases ?? []) {
|
|
498
|
+
register(index, alias, flag);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return index;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function register(
|
|
505
|
+
index: Map<string, FlagSpec>,
|
|
506
|
+
key: string,
|
|
507
|
+
flag: FlagSpec,
|
|
508
|
+
): void {
|
|
509
|
+
const existing = index.get(key);
|
|
510
|
+
if (existing && existing !== flag) {
|
|
511
|
+
throw new Error(
|
|
512
|
+
`ttsc flag schema: duplicate token ${JSON.stringify(key)} claimed by ${existing.name} and ${flag.name}`,
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
index.set(key, flag);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Terminal flags as a derived set. Used by `runBuild.ts` to skip the
|
|
520
|
+
* pre-emit pass when one is present.
|
|
521
|
+
*/
|
|
522
|
+
export const TERMINAL_FLAGS: ReadonlySet<string> = new Set(
|
|
523
|
+
FLAG_SCHEMA.flatMap((flag) =>
|
|
524
|
+
flag.terminal === true ? [flag.name, ...(flag.aliases ?? [])] : [],
|
|
525
|
+
),
|
|
526
|
+
);
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* `internalShadow: true` flags as a derived set. Used by `runBuild.ts` to
|
|
530
|
+
* detect a user-forwarded copy of a flag ttsc adds internally so the
|
|
531
|
+
* post-processor does not eat the user's output.
|
|
532
|
+
*/
|
|
533
|
+
export const INTERNAL_SHADOW_FLAGS: ReadonlySet<string> = new Set(
|
|
534
|
+
FLAG_SCHEMA.flatMap((flag) =>
|
|
535
|
+
flag.internalShadow === true ? [flag.name, ...(flag.aliases ?? [])] : [],
|
|
536
|
+
),
|
|
537
|
+
);
|
|
538
|
+
|
|
539
|
+
/** Tokens (canonical name + aliases) accepted in `subcommand`. */
|
|
540
|
+
export function flagsForSubcommand(subcommand: AnySubcommand): FlagSpec[] {
|
|
541
|
+
return FLAG_SCHEMA.filter((flag) => flag.subcommands.includes(subcommand));
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Allow-list map for the Go layer named `layer` (`"host"` or `"lint"`):
|
|
546
|
+
* flag-name (no leading dashes) → whether the flag takes a value token.
|
|
547
|
+
* The generator emits a literal Go map with the same shape, but this
|
|
548
|
+
* function is the runtime equivalent — used in tests to verify the
|
|
549
|
+
* generated Go matches the schema.
|
|
550
|
+
*/
|
|
551
|
+
export function buildGoAllowList(layer: "host" | "lint"): Map<string, boolean> {
|
|
552
|
+
const out = new Map<string, boolean>();
|
|
553
|
+
for (const flag of FLAG_SCHEMA) {
|
|
554
|
+
if (!flag.consumedBy.includes(layer)) continue;
|
|
555
|
+
const takesValue = flag.kind === "value" || flag.kind === "valueOptional";
|
|
556
|
+
for (const name of [flag.name, ...(flag.aliases ?? [])]) {
|
|
557
|
+
const key = name.replace(/^--?/, "");
|
|
558
|
+
// The Go side strips the leading dashes; if two flags collide on the
|
|
559
|
+
// stripped key (e.g. `-p` vs `--project`), use the value-taking shape.
|
|
560
|
+
const existing = out.get(key);
|
|
561
|
+
if (existing !== undefined && existing !== takesValue) {
|
|
562
|
+
throw new Error(
|
|
563
|
+
`ttsc flag schema: conflicting Go allow-list entry for ${JSON.stringify(key)} on layer ${layer}`,
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
out.set(key, takesValue);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
return out;
|
|
570
|
+
}
|
|
@@ -23,6 +23,7 @@ export function getCompilerVersionText(
|
|
|
23
23
|
return `ttsc ${readOwnPackageVersion()} (${outputText(res.stdout).trim()})`;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
/** Coerce a spawnSync stdio field (string | Buffer | null) to a plain string. */
|
|
26
27
|
function outputText(value: string | Buffer | null | undefined): string {
|
|
27
28
|
if (value == null) {
|
|
28
29
|
return "";
|
|
@@ -30,6 +31,12 @@ function outputText(value: string | Buffer | null | undefined): string {
|
|
|
30
31
|
return typeof value === "string" ? value : value.toString("utf8");
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Read the `version` field from the `@ttsc/ttsc` package.json that sits three
|
|
36
|
+
* directories above the compiled launcher output (`lib/launcher/internal/`).
|
|
37
|
+
* Returns `"0.0.0"` on any I/O or parse failure so the banner is always safe to
|
|
38
|
+
* display.
|
|
39
|
+
*/
|
|
33
40
|
function readOwnPackageVersion(): string {
|
|
34
41
|
try {
|
|
35
42
|
const file = path.resolve(__dirname, "..", "..", "..", "package.json");
|
|
@@ -7,7 +7,14 @@ import { resolveEmittedJavaScript } from "../../compiler/internal/resolveEmitted
|
|
|
7
7
|
import { runBuild } from "../../compiler/internal/runBuild";
|
|
8
8
|
import type { TtscCommonOptions } from "../../structures/internal/TtscCommonOptions";
|
|
9
9
|
|
|
10
|
+
/** Subdirectory name that isolates concurrent ttsx processes by PID. */
|
|
10
11
|
const PROCESS_CACHE_KEY = String(process.pid);
|
|
12
|
+
/**
|
|
13
|
+
* Maximum number of ancestor directories above the project root that the
|
|
14
|
+
* virtual filesystem overlay mirrors. Three levels covers the common monorepo
|
|
15
|
+
* layout (workspace-root → packages → package-root) so `node_modules` symlinks
|
|
16
|
+
* resolve correctly without reaching an unsafe boundary.
|
|
17
|
+
*/
|
|
11
18
|
const MAX_VIRTUAL_PARENT_DEPTH = 3;
|
|
12
19
|
|
|
13
20
|
/** Build the owning project and locate the emitted JavaScript entry for `ttsx`. */
|
|
@@ -102,14 +109,17 @@ function buildProject(
|
|
|
102
109
|
fs.mkdirSync(path.dirname(context.emitDir), { recursive: true });
|
|
103
110
|
const result = runBuild({
|
|
104
111
|
binary: options.binary,
|
|
112
|
+
checkers: options.checkers,
|
|
105
113
|
cwd: context.root,
|
|
106
114
|
emit: true,
|
|
107
115
|
env: options.env,
|
|
108
116
|
forceListEmittedFiles: true,
|
|
109
117
|
cacheDir: context.pluginCacheDir,
|
|
110
118
|
outDir: context.emitDir,
|
|
119
|
+
passthrough: options.passthrough,
|
|
111
120
|
plugins: options.plugins,
|
|
112
121
|
quiet: true,
|
|
122
|
+
singleThreaded: options.singleThreaded,
|
|
113
123
|
tsconfig: context.tsconfig,
|
|
114
124
|
});
|
|
115
125
|
if (result.status === 0) {
|
|
@@ -162,6 +172,7 @@ function linkVirtualEntry(
|
|
|
162
172
|
entry: fs.Dirent,
|
|
163
173
|
): void {
|
|
164
174
|
if (entry.isDirectory()) {
|
|
175
|
+
// Use junction points on Windows; plain symlinks elsewhere.
|
|
165
176
|
fs.symlinkSync(
|
|
166
177
|
realEntry,
|
|
167
178
|
virtualEntry,
|
|
@@ -171,15 +182,25 @@ function linkVirtualEntry(
|
|
|
171
182
|
}
|
|
172
183
|
if (entry.isFile()) {
|
|
173
184
|
try {
|
|
185
|
+
// Hard-link first: cheap, preserves inode, no extra disk usage.
|
|
174
186
|
fs.linkSync(realEntry, virtualEntry);
|
|
175
187
|
} catch {
|
|
188
|
+
// Cross-device or unsupported filesystem: fall back to a full copy.
|
|
176
189
|
fs.copyFileSync(realEntry, virtualEntry);
|
|
177
190
|
}
|
|
178
191
|
return;
|
|
179
192
|
}
|
|
193
|
+
// Symlinks (and other special entries) are re-symlinked as-is.
|
|
180
194
|
fs.symlinkSync(realEntry, virtualEntry);
|
|
181
195
|
}
|
|
182
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Walk from `projectRoot` upward (up to `MAX_VIRTUAL_PARENT_DEPTH` steps),
|
|
199
|
+
* stopping early at a workspace root (`pnpm-workspace.yaml` or `.git`). The
|
|
200
|
+
* collected directories are reversed so callers can iterate outermost-first,
|
|
201
|
+
* which lets inner symlinks override outer ones without conflicting mkdir
|
|
202
|
+
* calls.
|
|
203
|
+
*/
|
|
183
204
|
function collectLinkDirectories(projectRoot: string): string[] {
|
|
184
205
|
const out: string[] = [];
|
|
185
206
|
let current = projectRoot;
|
|
@@ -207,6 +228,14 @@ function isUnsafeVirtualParent(directory: string): boolean {
|
|
|
207
228
|
return resolved === root || resolved === path.resolve(os.tmpdir());
|
|
208
229
|
}
|
|
209
230
|
|
|
231
|
+
/**
|
|
232
|
+
* Map an absolute path into a stable, filesystem-safe subtree under `root`.
|
|
233
|
+
*
|
|
234
|
+
* On POSIX the root is always `/`, so every path shares the same prefix —
|
|
235
|
+
* represented here as `"posix"`. On Windows, drive letters and UNC roots each
|
|
236
|
+
* get a sanitized label (e.g. `"C_"` for `C:\`), preventing collisions between
|
|
237
|
+
* paths from different drives inside the same virtual root.
|
|
238
|
+
*/
|
|
210
239
|
function virtualPath(root: string, absolute: string): string {
|
|
211
240
|
const parsed = path.parse(path.resolve(absolute));
|
|
212
241
|
const label =
|
|
@@ -218,6 +247,12 @@ function virtualPath(root: string, absolute: string): string {
|
|
|
218
247
|
return path.join(root, label, relative);
|
|
219
248
|
}
|
|
220
249
|
|
|
250
|
+
/**
|
|
251
|
+
* Heuristic: classify emitted JS as ESM when it contains top-level `import` or
|
|
252
|
+
* `export` statements but none of the well-known CJS patterns. The CJS checks
|
|
253
|
+
* run first so that re-exported CJS bundles with both `require` calls and an
|
|
254
|
+
* `export` declaration are conservatively treated as CJS.
|
|
255
|
+
*/
|
|
221
256
|
function looksLikeESM(output: string): boolean {
|
|
222
257
|
if (
|
|
223
258
|
/\bObject\.defineProperty\(exports\b/.test(output) ||
|