ttsc 0.18.3 → 0.19.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/README.md +5 -6
- package/cmd/graphbench/main.go +1 -1
- package/cmd/platform/main.go +1 -48
- package/cmd/ttsc/build_branches_test.go +5 -1
- package/cmd/ttsc/main.go +0 -50
- package/cmd/ttsc/main_alias_branches_test.go +6 -12
- package/cmd/ttscgraph/dump.go +13 -3
- package/cmd/ttscgraph/main.go +18 -12
- package/cmd/ttscgraph/run_help_version_and_bad_flags_exit_codes_test.go +23 -5
- package/cmd/ttscgraph/serve.go +863 -0
- package/cmd/ttscgraph/serve_protocol_rejects_invalid_request_line_test.go +43 -0
- package/cmd/ttscgraph/serve_protocol_retries_session_creation_test.go +83 -0
- package/cmd/ttscgraph/serve_protocol_reuses_session_test.go +35 -0
- package/cmd/ttscgraph/serve_session_applies_source_edit_incrementally_test.go +55 -0
- package/cmd/ttscgraph/serve_session_fails_closed_on_deleted_config_test.go +68 -0
- package/cmd/ttscgraph/serve_session_fails_closed_on_invalid_config_test.go +50 -0
- package/cmd/ttscgraph/serve_session_keeps_missing_literal_root_unchanged_test.go +46 -0
- package/cmd/ttscgraph/serve_session_rebuilds_import_graph_change_test.go +60 -0
- package/cmd/ttscgraph/serve_session_reloads_created_literal_root_test.go +44 -0
- package/cmd/ttscgraph/serve_session_reloads_extended_config_change_test.go +45 -0
- package/cmd/ttscgraph/serve_session_reloads_newly_resolved_conditional_export_test.go +60 -0
- package/cmd/ttscgraph/serve_session_reloads_newly_resolved_config_types_test.go +44 -0
- package/cmd/ttscgraph/serve_session_reloads_newly_resolved_excluded_import_test.go +62 -0
- package/cmd/ttscgraph/serve_session_reloads_newly_resolved_package_export_test.go +46 -0
- package/cmd/ttscgraph/serve_session_reloads_newly_resolved_package_import_test.go +46 -0
- package/cmd/ttscgraph/serve_session_reloads_newly_resolved_path_alias_test.go +47 -0
- package/cmd/ttscgraph/serve_session_reloads_newly_resolved_reference_path_test.go +42 -0
- package/cmd/ttscgraph/serve_session_reloads_newly_resolved_root_dirs_target_test.go +46 -0
- package/cmd/ttscgraph/serve_session_reloads_newly_resolved_type_reference_test.go +42 -0
- package/cmd/ttscgraph/serve_session_reloads_root_file_set_test.go +52 -0
- package/cmd/ttscgraph/serve_session_reloads_source_deleted_during_load_test.go +60 -0
- package/cmd/ttscgraph/serve_session_reloads_transitive_project_reference_test.go +55 -0
- package/cmd/ttscgraph/serve_session_reloads_when_program_plugin_linked_test.go +53 -0
- package/cmd/ttscgraph/serve_session_reuses_unchanged_preamble_source_test.go +45 -0
- package/cmd/ttscgraph/serve_session_reuses_unchanged_snapshot_test.go +52 -0
- package/cmd/ttscgraph/serve_session_revisits_source_edited_during_load_test.go +61 -0
- package/cmd/ttscgraph/serve_session_tolerates_os_invalid_resolution_candidate_test.go +56 -0
- package/cmd/ttscgraph/serve_session_tracks_all_module_specifier_forms_test.go +41 -0
- package/cmd/ttscgraph/serve_session_tracks_diamond_project_references_once_test.go +61 -0
- package/cmd/ttscserver/main.go +5 -3
- package/driver/lsp.go +13 -1
- package/driver/plugins.go +56 -5
- package/driver/program.go +25 -10
- package/driver/rewrite.go +381 -21
- package/driver/session.go +11 -3
- package/go.mod +1 -0
- package/internal/graph/build.go +297 -3
- package/internal/graph/build_records_a_node_per_top_level_declaration_test.go +16 -2
- package/internal/graph/diagnostics.go +5 -4
- package/internal/graph/dump.go +60 -4
- package/internal/graph/dump_is_a_function_of_the_source_test.go +71 -0
- package/internal/graph/dump_serializes_the_full_graph_test.go +16 -4
- package/internal/graph/edges.go +122 -11
- package/internal/graph/exports.go +74 -17
- package/internal/graph/graph.go +33 -1
- package/internal/graph/node_identity_is_position_invariant_test.go +4 -2
- package/internal/graph/resolve.go +24 -0
- package/internal/graphsymbols/provider.go +50 -14
- package/internal/lspserver/lsp_native_plugin_source.go +77 -23
- package/internal/lspserver/lsp_plugin.go +19 -2
- package/internal/lspserver/lsp_proxy.go +244 -52
- package/internal/lspserver/lsp_server.go +35 -27
- package/internal/lspserver/lsp_symbols.go +25 -16
- package/lib/TtscCompiler.d.ts +13 -2
- package/lib/TtscCompiler.js +30 -20
- package/lib/TtscCompiler.js.map +1 -1
- package/lib/TtscService.js +9 -7
- package/lib/TtscService.js.map +1 -1
- package/lib/compiler/internal/compileProjectInMemory.js +15 -1
- package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
- package/lib/compiler/internal/project/createNativeProjectContextArgs.d.ts +3 -0
- package/lib/compiler/internal/project/createNativeProjectContextArgs.js +14 -0
- package/lib/compiler/internal/project/createNativeProjectContextArgs.js.map +1 -0
- package/lib/compiler/internal/project/readProjectConfig.js +53 -4
- package/lib/compiler/internal/project/readProjectConfig.js.map +1 -1
- package/lib/compiler/internal/project/resolveProjectConfig.d.ts +9 -2
- package/lib/compiler/internal/project/resolveProjectConfig.js +45 -16
- package/lib/compiler/internal/project/resolveProjectConfig.js.map +1 -1
- package/lib/compiler/internal/residentTransformProcess.d.ts +16 -5
- package/lib/compiler/internal/residentTransformProcess.js +68 -20
- package/lib/compiler/internal/residentTransformProcess.js.map +1 -1
- package/lib/compiler/internal/runBuild.d.ts +18 -0
- package/lib/compiler/internal/runBuild.js +220 -24
- package/lib/compiler/internal/runBuild.js.map +1 -1
- package/lib/compiler/internal/runSingleFileEmit.js +7 -4
- package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
- package/lib/compiler/internal/sharedHostHelpers.d.ts +16 -0
- package/lib/compiler/internal/sharedHostHelpers.js +23 -0
- package/lib/compiler/internal/sharedHostHelpers.js.map +1 -1
- package/lib/compiler/internal/startResidentTransform.js +18 -1
- package/lib/compiler/internal/startResidentTransform.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.js +34 -8
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/flags/parser.d.ts +17 -0
- package/lib/flags/parser.js +11 -1
- package/lib/flags/parser.js.map +1 -1
- package/lib/flags/schema.js +7 -0
- package/lib/flags/schema.js.map +1 -1
- package/lib/launcher/internal/prepareExecution.js +21 -2
- package/lib/launcher/internal/prepareExecution.js.map +1 -1
- package/lib/launcher/internal/runTtsc.js +13 -53
- package/lib/launcher/internal/runTtsc.js.map +1 -1
- package/lib/launcher/internal/runTtscserver.js +11 -0
- package/lib/launcher/internal/runTtscserver.js.map +1 -1
- package/lib/launcher/internal/runTtsx.js +27 -11
- package/lib/launcher/internal/runTtsx.js.map +1 -1
- package/lib/launcher/internal/runtimeHooks.d.ts +81 -0
- package/lib/launcher/internal/runtimeHooks.js +632 -43
- package/lib/launcher/internal/runtimeHooks.js.map +1 -1
- package/lib/launcher/internal/servedSourceMap.d.ts +25 -0
- package/lib/launcher/internal/servedSourceMap.js +164 -0
- package/lib/launcher/internal/servedSourceMap.js.map +1 -0
- package/lib/plugin/internal/buildSourcePlugin.d.ts +146 -2
- package/lib/plugin/internal/buildSourcePlugin.js +651 -113
- package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/loadProjectPlugins.d.ts +7 -0
- package/lib/plugin/internal/loadProjectPlugins.js +33 -10
- package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
- package/lib/structures/ITtscCompilerContext.d.ts +16 -2
- package/lib/structures/ITtscCompilerResult.d.ts +8 -5
- package/lib/structures/ITtscPluginCapabilities.d.ts +8 -0
- package/lib/structures/ITtscPluginFactoryContext.d.ts +14 -0
- package/lib/structures/internal/ITtscParsedProjectConfig.d.ts +3 -0
- package/lib/structures/internal/ITtscProjectIdentity.d.ts +17 -0
- package/lib/structures/internal/ITtscProjectIdentity.js +3 -0
- package/lib/structures/internal/ITtscProjectIdentity.js.map +1 -0
- package/lib/structures/internal/TtscCommonOptions.d.ts +8 -0
- package/package.json +11 -8
- package/shim/ast/lint.go +10 -0
- package/shim/ast/shim.go +44 -0
- package/shim/checker/enums_gen.go +19 -0
- package/shim/checker/shim.go +130 -0
- package/shim/diagnosticwriter/lint.go +30 -3
- package/shim/printer/shim.go +22 -4
- package/shim/scanner/regexp.go +27 -0
- package/src/TtscCompiler.ts +29 -22
- package/src/TtscService.ts +15 -7
- package/src/compiler/internal/compileProjectInMemory.ts +18 -1
- package/src/compiler/internal/project/createNativeProjectContextArgs.ts +15 -0
- package/src/compiler/internal/project/readProjectConfig.ts +61 -5
- package/src/compiler/internal/project/resolveProjectConfig.ts +51 -21
- package/src/compiler/internal/residentTransformProcess.ts +95 -21
- package/src/compiler/internal/runBuild.ts +313 -32
- package/src/compiler/internal/runSingleFileEmit.ts +7 -4
- package/src/compiler/internal/sharedHostHelpers.ts +24 -0
- package/src/compiler/internal/startResidentTransform.ts +21 -1
- package/src/compiler/internal/transformProjectInMemory.ts +49 -6
- package/src/flags/parser.ts +28 -1
- package/src/flags/schema.ts +8 -0
- package/src/launcher/internal/prepareExecution.ts +22 -2
- package/src/launcher/internal/runTtsc.ts +13 -61
- package/src/launcher/internal/runTtscserver.ts +14 -0
- package/src/launcher/internal/runTtsx.ts +28 -13
- package/src/launcher/internal/runtimeHooks.ts +771 -53
- package/src/launcher/internal/servedSourceMap.ts +183 -0
- package/src/plugin/internal/buildSourcePlugin.ts +859 -122
- package/src/plugin/internal/loadProjectPlugins.ts +36 -6
- package/src/structures/ITtscCompilerContext.ts +17 -2
- package/src/structures/ITtscCompilerResult.ts +8 -5
- package/src/structures/ITtscPluginCapabilities.ts +9 -0
- package/src/structures/ITtscPluginFactoryContext.ts +15 -0
- package/src/structures/internal/ITtscParsedProjectConfig.ts +3 -0
- package/src/structures/internal/ITtscProjectIdentity.ts +17 -0
- package/src/structures/internal/TtscCommonOptions.ts +8 -0
- package/tools/shim_audit/baseline.json +16 -7
- package/tools/shim_audit/main.go +777 -71
- package/tools/shim_audit/main_test.go +28 -1
- package/tools/shim_audit/producer_exemptions_require_rationale_test.go +42 -0
- package/tools/shim_audit/producer_surface_includes_exposed_methods_test.go +154 -0
- package/tools/shim_audit/producer_surface_rejects_unproducible_reference_test.go +142 -0
- package/utility/host.go +46 -20
- package/utility/serve.go +1 -1
- package/shim/checker/signature_api_completeness.go +0 -58
|
@@ -7,15 +7,18 @@ import {
|
|
|
7
7
|
} from "../../plugin/internal/loadProjectPlugins";
|
|
8
8
|
import type { ITtscCompilerDiagnostic } from "../../structures/ITtscCompilerDiagnostic";
|
|
9
9
|
import type { ITtscLoadedNativePlugin } from "../../structures/internal/ITtscLoadedNativePlugin";
|
|
10
|
+
import type { ITtscParsedProjectConfig } from "../../structures/internal/ITtscParsedProjectConfig";
|
|
10
11
|
import type { TtscBuildOptions } from "../../structures/internal/TtscBuildOptions";
|
|
11
12
|
import type { TtscBuildResult } from "../../structures/internal/TtscBuildResult";
|
|
12
13
|
import type { TtscCommonOptions } from "../../structures/internal/TtscCommonOptions";
|
|
14
|
+
import { createNativeProjectContextArgs } from "./project/createNativeProjectContextArgs";
|
|
13
15
|
import { readProjectConfig } from "./project/readProjectConfig";
|
|
14
16
|
import { resolveBinary } from "./resolveBinary";
|
|
15
17
|
import { resolveTsgo } from "./resolveTsgo";
|
|
16
18
|
import {
|
|
17
19
|
assertSharedHostCompatibility,
|
|
18
20
|
linkedTransformPlugins,
|
|
21
|
+
resolvePluginConfigDir,
|
|
19
22
|
selectSharedHostPlugin,
|
|
20
23
|
} from "./sharedHostHelpers";
|
|
21
24
|
import { outputText, spawnNative } from "./spawnNative";
|
|
@@ -23,6 +26,16 @@ import { outputText, spawnNative } from "./spawnNative";
|
|
|
23
26
|
type RunBuildOptions = TtscBuildOptions & {
|
|
24
27
|
skipDiagnosticsCheck?: boolean;
|
|
25
28
|
forceListEmittedFiles?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Emit an external source map from the direct tsgo build lane even when the
|
|
31
|
+
* project configures none. Set by the ttsx runtime builds so a served emit
|
|
32
|
+
* carries a map to inline under the source URL (issue #353). Applied only to
|
|
33
|
+
* the plain tsgo emit — never forwarded to a native plugin host, whose own
|
|
34
|
+
* emit honours the project's `sourceMap` setting.
|
|
35
|
+
*/
|
|
36
|
+
forceRuntimeSourceMap?: boolean;
|
|
37
|
+
/** Retain an already selected project's lexical identity across API lanes. */
|
|
38
|
+
resolvedProject?: ITtscParsedProjectConfig;
|
|
26
39
|
};
|
|
27
40
|
|
|
28
41
|
type BuildTiming = {
|
|
@@ -119,9 +132,13 @@ function formatTimingSeconds(ms: number): string {
|
|
|
119
132
|
|
|
120
133
|
/**
|
|
121
134
|
* Build the environment for a native plugin spawn. Injects `TTSC_TSGO_BINARY`
|
|
122
|
-
* and `TTSC_TTSX_BINARY` alongside the base env from `mergeEnv
|
|
123
|
-
*
|
|
124
|
-
*
|
|
135
|
+
* and `TTSC_TTSX_BINARY` alongside the base env from `mergeEnv`, plus
|
|
136
|
+
* `TTSC_PLUGIN_CONFIG_DIR` when the caller declared a plugin config anchor (an
|
|
137
|
+
* embedder compiling through a generated wrapper tsconfig) so config-file
|
|
138
|
+
* discovery walks the real project instead of the wrapper's temp-dir ancestry.
|
|
139
|
+
* For transform-stage plugins, also passes `TTSC_LINKED_PLUGINS_JSON`
|
|
140
|
+
* containing any linked sources so they run inside the same process as the host
|
|
141
|
+
* plugin.
|
|
125
142
|
*/
|
|
126
143
|
function nativePluginEnv(
|
|
127
144
|
extra: NodeJS.ProcessEnv | undefined,
|
|
@@ -129,12 +146,25 @@ function nativePluginEnv(
|
|
|
129
146
|
plugin?: ITtscLoadedNativePlugin,
|
|
130
147
|
): NodeJS.ProcessEnv {
|
|
131
148
|
const env = mergeEnv({
|
|
149
|
+
...(execution.pluginConfigDir === undefined
|
|
150
|
+
? {}
|
|
151
|
+
: { TTSC_PLUGIN_CONFIG_DIR: execution.pluginConfigDir }),
|
|
132
152
|
TTSC_TSGO_BINARY: process.env.TTSC_TSGO_BINARY ?? execution.tsgo.binary,
|
|
133
153
|
TTSC_TTSX_BINARY:
|
|
134
154
|
process.env.TTSC_TTSX_BINARY ??
|
|
135
155
|
path.join(__dirname, "..", "..", "launcher", "ttsx.js"),
|
|
136
156
|
...extra,
|
|
137
157
|
});
|
|
158
|
+
// The anchor is per-invocation state owned by this host: when this run
|
|
159
|
+
// declared none (and the caller's env does not name one), drop any value
|
|
160
|
+
// inherited from an ancestor ttsc process so a nested build never
|
|
161
|
+
// mis-anchors its plugins at the outer project.
|
|
162
|
+
if (
|
|
163
|
+
execution.pluginConfigDir === undefined &&
|
|
164
|
+
extra?.TTSC_PLUGIN_CONFIG_DIR === undefined
|
|
165
|
+
) {
|
|
166
|
+
delete env.TTSC_PLUGIN_CONFIG_DIR;
|
|
167
|
+
}
|
|
138
168
|
if (plugin?.stage === "transform") {
|
|
139
169
|
const linked = linkedTransformPlugins(execution.nativePlugins);
|
|
140
170
|
if (linked.length !== 0) {
|
|
@@ -160,17 +190,31 @@ function runBuildTimed(
|
|
|
160
190
|
): TtscBuildResult {
|
|
161
191
|
const setupStartedAt = process.hrtime.bigint();
|
|
162
192
|
const execution = resolveExecutionContext(options);
|
|
163
|
-
if (
|
|
193
|
+
if (
|
|
194
|
+
execution.nativePlugins.length > 0 ||
|
|
195
|
+
execution.pluginSetupFailure !== undefined
|
|
196
|
+
) {
|
|
164
197
|
recordTiming(timing, "ttsc plugin setup time", setupStartedAt);
|
|
165
198
|
}
|
|
166
199
|
const buildOptions = applyProjectNoEmit(options, execution);
|
|
200
|
+
if (execution.pluginSetupFailure !== undefined) {
|
|
201
|
+
return appendTypeScriptDiagnosticsAfterPluginFailure(
|
|
202
|
+
execution.pluginSetupFailure,
|
|
203
|
+
buildOptions,
|
|
204
|
+
execution,
|
|
205
|
+
);
|
|
206
|
+
}
|
|
167
207
|
if (execution.nativePlugins.length > 0) {
|
|
168
208
|
const compilers = execution.nativePlugins.filter(
|
|
169
209
|
(plugin) => plugin.stage === "transform",
|
|
170
210
|
);
|
|
171
211
|
const checked = runNativeCheckPlugins(buildOptions, execution, timing);
|
|
172
212
|
if (checked.status !== 0) {
|
|
173
|
-
return
|
|
213
|
+
return appendTypeScriptDiagnosticsAfterPluginFailure(
|
|
214
|
+
checked,
|
|
215
|
+
buildOptions,
|
|
216
|
+
execution,
|
|
217
|
+
);
|
|
174
218
|
}
|
|
175
219
|
|
|
176
220
|
if (buildOptions.emit === false) {
|
|
@@ -191,15 +235,20 @@ function runBuildTimed(
|
|
|
191
235
|
}
|
|
192
236
|
if (compilers.length !== 0) {
|
|
193
237
|
assertSharedHostCompatibility(compilers, "emit");
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
compilers,
|
|
200
|
-
timing,
|
|
201
|
-
),
|
|
238
|
+
const compiled = buildWithNativeCompilerPlugins(
|
|
239
|
+
buildOptions,
|
|
240
|
+
execution,
|
|
241
|
+
compilers,
|
|
242
|
+
timing,
|
|
202
243
|
);
|
|
244
|
+
const result = appendBuildOutput(checked, compiled);
|
|
245
|
+
return compiled.status === 0
|
|
246
|
+
? result
|
|
247
|
+
: appendTypeScriptDiagnosticsAfterPluginFailure(
|
|
248
|
+
result,
|
|
249
|
+
buildOptions,
|
|
250
|
+
execution,
|
|
251
|
+
);
|
|
203
252
|
}
|
|
204
253
|
if (checkPluginsReportTypeScriptDiagnostics(execution.nativePlugins)) {
|
|
205
254
|
return checked;
|
|
@@ -213,15 +262,20 @@ function runBuildTimed(
|
|
|
213
262
|
let result: TtscBuildResult;
|
|
214
263
|
if (compilers.length !== 0) {
|
|
215
264
|
assertSharedHostCompatibility(compilers, "emit");
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
265
|
+
const compiled = buildWithNativeCompilerPlugins(
|
|
266
|
+
buildOptions,
|
|
267
|
+
execution,
|
|
268
|
+
compilers,
|
|
269
|
+
timing,
|
|
270
|
+
);
|
|
271
|
+
result = appendBuildOutput(checked, compiled);
|
|
272
|
+
if (compiled.status !== 0) {
|
|
273
|
+
result = appendTypeScriptDiagnosticsAfterPluginFailure(
|
|
274
|
+
result,
|
|
219
275
|
buildOptions,
|
|
220
276
|
execution,
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
),
|
|
224
|
-
);
|
|
277
|
+
);
|
|
278
|
+
}
|
|
225
279
|
} else {
|
|
226
280
|
if (
|
|
227
281
|
buildOptions.skipDiagnosticsCheck !== true &&
|
|
@@ -295,6 +349,165 @@ function checkPluginsReportTypeScriptDiagnostics(
|
|
|
295
349
|
);
|
|
296
350
|
}
|
|
297
351
|
|
|
352
|
+
/**
|
|
353
|
+
* Preserve a failed plugin's output and status while collecting TypeScript
|
|
354
|
+
* diagnostics through an independent no-emit pass.
|
|
355
|
+
*
|
|
356
|
+
* A sidecar can fail before it loads the project Program, including when a Go
|
|
357
|
+
* panic or another runtime error terminates the process. The plugin failure
|
|
358
|
+
* must still block emit, but it must not hide unrelated errors in the user's
|
|
359
|
+
* TypeScript source. The fallback runs only after a plugin failure, skips modes
|
|
360
|
+
* whose contract intentionally omits diagnostics, and avoids appending a batch
|
|
361
|
+
* the plugin already reported itself.
|
|
362
|
+
*/
|
|
363
|
+
function appendTypeScriptDiagnosticsAfterPluginFailure(
|
|
364
|
+
failure: TtscBuildResult,
|
|
365
|
+
options: RunBuildOptions,
|
|
366
|
+
execution: ReturnType<typeof resolveExecutionContext>,
|
|
367
|
+
): TtscBuildResult {
|
|
368
|
+
if (
|
|
369
|
+
options.format === true ||
|
|
370
|
+
options.skipDiagnosticsCheck === true ||
|
|
371
|
+
forwardsTerminalTsgoFlag(options)
|
|
372
|
+
) {
|
|
373
|
+
return failure;
|
|
374
|
+
}
|
|
375
|
+
const typechecked = runTsgo(
|
|
376
|
+
execution,
|
|
377
|
+
["--noEmit"],
|
|
378
|
+
createPluginFailureTypecheckOptions(options),
|
|
379
|
+
);
|
|
380
|
+
const fallback = filterReportedTypeScriptDiagnostics(
|
|
381
|
+
failure,
|
|
382
|
+
typechecked,
|
|
383
|
+
execution.projectRoot,
|
|
384
|
+
);
|
|
385
|
+
if (fallback === null) {
|
|
386
|
+
return failure;
|
|
387
|
+
}
|
|
388
|
+
// Structured consumers (the public API's `IFailure.diagnostics`) never see
|
|
389
|
+
// stdout/stderr, so a plugin failure that reported no parsable diagnostics
|
|
390
|
+
// must be seeded as one before recovered TypeScript diagnostics are appended
|
|
391
|
+
// — otherwise the recovery would replace the plugin error with unrelated
|
|
392
|
+
// type errors instead of surfacing both.
|
|
393
|
+
const seeded =
|
|
394
|
+
failure.diagnostics.length === 0
|
|
395
|
+
? { ...failure, diagnostics: [createProcessDiagnostic(failure)] }
|
|
396
|
+
: failure;
|
|
397
|
+
const status = failure.status;
|
|
398
|
+
return {
|
|
399
|
+
...appendBuildOutput(seeded, fallback),
|
|
400
|
+
status,
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Make the recovery pass parseable regardless of the user's display flags. This
|
|
406
|
+
* is an internal second pass, so plain output is required to remove only
|
|
407
|
+
* diagnostics that the failed plugin already printed.
|
|
408
|
+
*/
|
|
409
|
+
function createPluginFailureTypecheckOptions(
|
|
410
|
+
options: RunBuildOptions,
|
|
411
|
+
): RunBuildOptions {
|
|
412
|
+
const passthrough: string[] = [];
|
|
413
|
+
for (let i = 0; i < (options.passthrough?.length ?? 0); i++) {
|
|
414
|
+
const token = options.passthrough![i]!;
|
|
415
|
+
if (token === "--pretty") {
|
|
416
|
+
if (isBooleanLiteral(options.passthrough![i + 1] ?? "")) i++;
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
if (token.startsWith("--pretty=")) continue;
|
|
420
|
+
passthrough.push(token);
|
|
421
|
+
}
|
|
422
|
+
return {
|
|
423
|
+
...options,
|
|
424
|
+
passthrough,
|
|
425
|
+
structuredDiagnostics: true,
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/** Return only fallback diagnostics the failed plugin did not already report. */
|
|
430
|
+
function filterReportedTypeScriptDiagnostics(
|
|
431
|
+
failure: TtscBuildResult,
|
|
432
|
+
typechecked: TtscBuildResult,
|
|
433
|
+
cwd: string,
|
|
434
|
+
): TtscBuildResult | null {
|
|
435
|
+
if (typechecked.diagnostics.length === 0) {
|
|
436
|
+
return typechecked.status === 0 ? null : typechecked;
|
|
437
|
+
}
|
|
438
|
+
const diagnostics = typechecked.diagnostics.filter(
|
|
439
|
+
(diagnostic) =>
|
|
440
|
+
!failure.diagnostics.some((existing) =>
|
|
441
|
+
compilerDiagnosticsEqual(existing, diagnostic),
|
|
442
|
+
),
|
|
443
|
+
);
|
|
444
|
+
if (diagnostics.length === 0) return null;
|
|
445
|
+
if (diagnostics.length === typechecked.diagnostics.length) return typechecked;
|
|
446
|
+
return {
|
|
447
|
+
...typechecked,
|
|
448
|
+
diagnostics,
|
|
449
|
+
stderr: filterCompilerDiagnosticText(typechecked.stderr, diagnostics, cwd),
|
|
450
|
+
stdout: filterCompilerDiagnosticText(typechecked.stdout, diagnostics, cwd),
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/** Remove diagnostic lines absent from the selected structured result. */
|
|
455
|
+
function filterCompilerDiagnosticText(
|
|
456
|
+
text: string,
|
|
457
|
+
diagnostics: readonly ITtscCompilerDiagnostic[],
|
|
458
|
+
cwd: string,
|
|
459
|
+
): string {
|
|
460
|
+
const out: string[] = [];
|
|
461
|
+
let keepContinuation = true;
|
|
462
|
+
for (const line of text.split(/\r?\n/)) {
|
|
463
|
+
const plain = stripAnsi(line);
|
|
464
|
+
const diagnostic = parseDiagnosticLine(plain, cwd);
|
|
465
|
+
if (diagnostic !== null) {
|
|
466
|
+
keepContinuation = diagnostics.some((selected) =>
|
|
467
|
+
compilerDiagnosticsEqual(selected, diagnostic),
|
|
468
|
+
);
|
|
469
|
+
if (keepContinuation) out.push(line);
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
if (/^Found\s+\d+\s+errors?/i.test(plain)) continue;
|
|
473
|
+
if (!keepContinuation && /^\s+/.test(line)) continue;
|
|
474
|
+
keepContinuation = true;
|
|
475
|
+
out.push(line);
|
|
476
|
+
}
|
|
477
|
+
return out.join("\n");
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/** Compare normalized compiler diagnostics before appending fallback output. */
|
|
481
|
+
function compilerDiagnosticsEqual(
|
|
482
|
+
left: ITtscCompilerDiagnostic,
|
|
483
|
+
right: ITtscCompilerDiagnostic,
|
|
484
|
+
): boolean {
|
|
485
|
+
return (
|
|
486
|
+
left.category === right.category &&
|
|
487
|
+
left.code === right.code &&
|
|
488
|
+
left.file === right.file &&
|
|
489
|
+
diagnosticPositionsEqual(left, right) &&
|
|
490
|
+
diagnosticHeadline(left.messageText) ===
|
|
491
|
+
diagnosticHeadline(right.messageText)
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/** Compare offsets when available, otherwise compare rendered line/column. */
|
|
496
|
+
function diagnosticPositionsEqual(
|
|
497
|
+
left: ITtscCompilerDiagnostic,
|
|
498
|
+
right: ITtscCompilerDiagnostic,
|
|
499
|
+
): boolean {
|
|
500
|
+
if (left.start !== undefined && right.start !== undefined) {
|
|
501
|
+
return left.start === right.start;
|
|
502
|
+
}
|
|
503
|
+
return left.line === right.line && left.character === right.character;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/** Remove pretty-rendered source context from a diagnostic message. */
|
|
507
|
+
function diagnosticHeadline(message: string): string {
|
|
508
|
+
return message.split(/\r?\n/, 1)[0]!.trim();
|
|
509
|
+
}
|
|
510
|
+
|
|
298
511
|
/**
|
|
299
512
|
* Tsgo CLI flags that make `tsgo` print something and exit instead of building
|
|
300
513
|
* (`--showConfig`, `--listFilesOnly`, `--help`, …). ttsc must not add
|
|
@@ -481,6 +694,12 @@ function createTsgoBuildArgs(
|
|
|
481
694
|
if (execution.rewriteRelativeImportExtensionsForEmit) {
|
|
482
695
|
args.push("--rewriteRelativeImportExtensions");
|
|
483
696
|
}
|
|
697
|
+
// The ttsx runtime build asks for an external map when the project emits
|
|
698
|
+
// none, so its served emit carries a map to inline under the source URL.
|
|
699
|
+
// Pushed before passthrough so an explicit user `--sourceMap` still wins.
|
|
700
|
+
if (options.forceRuntimeSourceMap === true) {
|
|
701
|
+
args.push("--sourceMap", "true");
|
|
702
|
+
}
|
|
484
703
|
} else if (options.emit === false) {
|
|
485
704
|
args.push("--noEmit");
|
|
486
705
|
}
|
|
@@ -548,6 +767,16 @@ function createNativeBuildArgs(
|
|
|
548
767
|
"--plugins-json=" + serializeNativePlugins(plugins),
|
|
549
768
|
"--cwd=" + execution.projectRoot,
|
|
550
769
|
];
|
|
770
|
+
if (
|
|
771
|
+
selectSharedHostPlugin(plugins).capabilities?.projectContextArgs === true
|
|
772
|
+
) {
|
|
773
|
+
args.push(
|
|
774
|
+
...createNativeProjectContextArgs(
|
|
775
|
+
execution.project,
|
|
776
|
+
execution.pluginConfigDir,
|
|
777
|
+
),
|
|
778
|
+
);
|
|
779
|
+
}
|
|
551
780
|
if (options.emit === true) {
|
|
552
781
|
args.push("--emit");
|
|
553
782
|
}
|
|
@@ -580,6 +809,14 @@ function createNativeCheckArgs(
|
|
|
580
809
|
"--plugins-json=" + serializeNativePlugins(execution.nativePlugins),
|
|
581
810
|
"--cwd=" + execution.projectRoot,
|
|
582
811
|
];
|
|
812
|
+
if (plugin.capabilities?.projectContextArgs === true) {
|
|
813
|
+
args.push(
|
|
814
|
+
...createNativeProjectContextArgs(
|
|
815
|
+
execution.project,
|
|
816
|
+
execution.pluginConfigDir,
|
|
817
|
+
),
|
|
818
|
+
);
|
|
819
|
+
}
|
|
583
820
|
if (options.outDir) {
|
|
584
821
|
args.push("--outDir=" + path.resolve(execution.cwd, options.outDir));
|
|
585
822
|
}
|
|
@@ -850,37 +1087,81 @@ export function appendBuildOutput(
|
|
|
850
1087
|
});
|
|
851
1088
|
}
|
|
852
1089
|
|
|
1090
|
+
/**
|
|
1091
|
+
* Synthesize one structured diagnostic from a non-zero process result that
|
|
1092
|
+
* produced no parsable diagnostics, carrying the captured stderr/stdout as the
|
|
1093
|
+
* message. Shared by the public API result mapping and the plugin-failure
|
|
1094
|
+
* recovery pass so the failure text is never dropped from structured output.
|
|
1095
|
+
*/
|
|
1096
|
+
export function createProcessDiagnostic(
|
|
1097
|
+
result: TtscBuildResult,
|
|
1098
|
+
): ITtscCompilerDiagnostic {
|
|
1099
|
+
const messageText =
|
|
1100
|
+
(result.stderr || result.stdout).trim() ||
|
|
1101
|
+
`ttsc exited with status ${result.status}`;
|
|
1102
|
+
return {
|
|
1103
|
+
category: "error",
|
|
1104
|
+
code: "TTSC_PROCESS",
|
|
1105
|
+
file: null,
|
|
1106
|
+
messageText,
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
|
|
853
1110
|
/**
|
|
854
1111
|
* Resolve all runtime context needed for a build: cwd, tsconfig path, project
|
|
855
1112
|
* root, tsgo binary location, and the loaded native plugin list. Centralised
|
|
856
1113
|
* here so every code path in `runBuild` shares the same resolution logic.
|
|
857
1114
|
*/
|
|
858
1115
|
function resolveExecutionContext(
|
|
859
|
-
options: TtscCommonOptions & {
|
|
1116
|
+
options: TtscCommonOptions & {
|
|
1117
|
+
emit?: boolean;
|
|
1118
|
+
resolvedProject?: ITtscParsedProjectConfig;
|
|
1119
|
+
tsconfig?: string;
|
|
1120
|
+
},
|
|
860
1121
|
) {
|
|
861
1122
|
const cwd = path.resolve(options.cwd ?? process.cwd());
|
|
862
|
-
const project =
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
1123
|
+
const project =
|
|
1124
|
+
options.resolvedProject ??
|
|
1125
|
+
readProjectConfig({
|
|
1126
|
+
cwd,
|
|
1127
|
+
projectRoot: options.projectRoot,
|
|
1128
|
+
tsconfig: options.tsconfig,
|
|
1129
|
+
});
|
|
867
1130
|
const tsconfig = project.path;
|
|
868
1131
|
const projectRoot = project.root;
|
|
869
1132
|
const tsgo = resolveTsgo({ ...options, cwd: projectRoot });
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
1133
|
+
let pluginSetupFailure: TtscBuildResult | undefined;
|
|
1134
|
+
let nativePlugins: ITtscLoadedNativePlugin[] = [];
|
|
1135
|
+
try {
|
|
1136
|
+
if (hasProjectPluginEntries(project, options.plugins)) {
|
|
1137
|
+
nativePlugins = loadProjectPlugins({
|
|
873
1138
|
binary: resolveBinary(options) ?? "",
|
|
874
1139
|
cacheDir: options.cacheDir ?? options.env?.TTSC_CACHE_DIR,
|
|
875
1140
|
cwd,
|
|
876
1141
|
entries: options.plugins,
|
|
1142
|
+
env: { ...process.env, ...options.env },
|
|
1143
|
+
pluginConfigDir: options.pluginConfigDir,
|
|
877
1144
|
projectRoot,
|
|
878
1145
|
tsconfig,
|
|
879
|
-
})
|
|
880
|
-
|
|
1146
|
+
}).nativePlugins;
|
|
1147
|
+
}
|
|
1148
|
+
} catch (error) {
|
|
1149
|
+
pluginSetupFailure = {
|
|
1150
|
+
diagnostics: [],
|
|
1151
|
+
status: 2,
|
|
1152
|
+
stdout: "",
|
|
1153
|
+
stderr: `${error instanceof Error ? error.message : String(error)}\n`,
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
881
1156
|
return {
|
|
882
1157
|
cwd,
|
|
883
|
-
nativePlugins
|
|
1158
|
+
nativePlugins,
|
|
1159
|
+
pluginConfigDir: resolvePluginConfigDir({
|
|
1160
|
+
cwd,
|
|
1161
|
+
pluginConfigDir: options.pluginConfigDir,
|
|
1162
|
+
}),
|
|
1163
|
+
pluginSetupFailure,
|
|
1164
|
+
project,
|
|
884
1165
|
projectNoEmit: project.compilerOptions.noEmit === true,
|
|
885
1166
|
projectRoot,
|
|
886
1167
|
rewriteRelativeImportExtensionsForEmit:
|
|
@@ -3,7 +3,7 @@ import os from "node:os";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
|
|
5
5
|
import type { TtscSingleFileEmitOptions } from "../../structures/internal/TtscSingleFileEmitOptions";
|
|
6
|
-
import {
|
|
6
|
+
import { readProjectConfig } from "./project/readProjectConfig";
|
|
7
7
|
import { resolveEmittedJavaScript } from "./resolveEmittedJavaScript";
|
|
8
8
|
import { runBuild } from "./runBuild";
|
|
9
9
|
|
|
@@ -24,12 +24,14 @@ export function runSingleFileEmit(options: TtscSingleFileEmitOptions): string {
|
|
|
24
24
|
? options.file
|
|
25
25
|
: path.resolve(cwd, options.file),
|
|
26
26
|
);
|
|
27
|
-
const
|
|
27
|
+
const project = readProjectConfig({
|
|
28
28
|
cwd,
|
|
29
|
-
file:
|
|
29
|
+
file: options.file,
|
|
30
|
+
projectRoot: options.projectRoot,
|
|
30
31
|
tsconfig: options.tsconfig,
|
|
31
32
|
});
|
|
32
|
-
const
|
|
33
|
+
const tsconfig = project.path;
|
|
34
|
+
const projectRoot = project.root;
|
|
33
35
|
const outDir = fs.mkdtempSync(path.join(os.tmpdir(), "ttsc-single-file-"));
|
|
34
36
|
try {
|
|
35
37
|
const result = runBuild({
|
|
@@ -38,6 +40,7 @@ export function runSingleFileEmit(options: TtscSingleFileEmitOptions): string {
|
|
|
38
40
|
emit: true,
|
|
39
41
|
forceListEmittedFiles: true,
|
|
40
42
|
outDir,
|
|
43
|
+
resolvedProject: project,
|
|
41
44
|
tsconfig,
|
|
42
45
|
});
|
|
43
46
|
if (result.status !== 0) {
|
|
@@ -1,5 +1,29 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
1
3
|
import type { ITtscLoadedNativePlugin } from "../../structures/internal/ITtscLoadedNativePlugin";
|
|
2
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Resolve the caller-declared plugin config anchor to an absolute path, or
|
|
7
|
+
* `undefined` when the caller did not declare one.
|
|
8
|
+
*
|
|
9
|
+
* The anchor exists for embedders that compile through a generated tsconfig
|
|
10
|
+
* outside the project (the bundler adapters' alias overlay): they set
|
|
11
|
+
* `pluginConfigDir` to the real project directory and every native plugin spawn
|
|
12
|
+
* forwards it as `TTSC_PLUGIN_CONFIG_DIR`, so config-file discovery walks the
|
|
13
|
+
* project instead of the wrapper's temp-dir ancestry. Callers that point at a
|
|
14
|
+
* user-authored tsconfig (even a wrapper outside the project) leave it unset,
|
|
15
|
+
* keeping discovery anchored at the tsconfig's own directory.
|
|
16
|
+
*/
|
|
17
|
+
export function resolvePluginConfigDir(options: {
|
|
18
|
+
cwd?: string;
|
|
19
|
+
pluginConfigDir?: string;
|
|
20
|
+
}): string | undefined {
|
|
21
|
+
if (options.pluginConfigDir === undefined || options.pluginConfigDir === "") {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
return path.resolve(options.cwd ?? process.cwd(), options.pluginConfigDir);
|
|
25
|
+
}
|
|
26
|
+
|
|
3
27
|
/**
|
|
4
28
|
* Reports whether the given transform source is linked into another compiler
|
|
5
29
|
* host instead of owning the process itself.
|
|
@@ -10,6 +10,7 @@ import { resolveTsgo } from "./resolveTsgo";
|
|
|
10
10
|
import {
|
|
11
11
|
assertSharedHostCompatibility,
|
|
12
12
|
linkedTransformPlugins,
|
|
13
|
+
resolvePluginConfigDir,
|
|
13
14
|
selectSharedHostPlugin,
|
|
14
15
|
} from "./sharedHostHelpers";
|
|
15
16
|
|
|
@@ -51,6 +52,8 @@ export function startResidentTransform(
|
|
|
51
52
|
cacheDir: context.cacheDir ?? context.env?.TTSC_CACHE_DIR,
|
|
52
53
|
cwd,
|
|
53
54
|
entries: context.plugins,
|
|
55
|
+
env: { ...process.env, ...context.env },
|
|
56
|
+
pluginConfigDir: context.pluginConfigDir,
|
|
54
57
|
projectRoot: context.projectRoot,
|
|
55
58
|
tsconfig: project.path,
|
|
56
59
|
});
|
|
@@ -84,7 +87,10 @@ export function startResidentTransform(
|
|
|
84
87
|
/**
|
|
85
88
|
* Build the environment for the resident host spawn. Matches the per-call
|
|
86
89
|
* transform spawn: injects the Node, tsgo, and ttsx binaries so the host never
|
|
87
|
-
* searches PATH,
|
|
90
|
+
* searches PATH, sets `TTSC_PLUGIN_CONFIG_DIR` when the caller declared a
|
|
91
|
+
* plugin config anchor (an embedder compiling through a generated wrapper
|
|
92
|
+
* tsconfig) so config-file discovery walks the real project instead of the
|
|
93
|
+
* wrapper's temp-dir ancestry, and forwards linked transform plugins via
|
|
88
94
|
* `TTSC_LINKED_PLUGINS_JSON`.
|
|
89
95
|
*/
|
|
90
96
|
function residentEnv(
|
|
@@ -92,15 +98,29 @@ function residentEnv(
|
|
|
92
98
|
tsgoBinary: string,
|
|
93
99
|
nativePlugins: readonly ITtscLoadedNativePlugin[],
|
|
94
100
|
): NodeJS.ProcessEnv {
|
|
101
|
+
const pluginConfigDir = resolvePluginConfigDir(context);
|
|
95
102
|
const env: NodeJS.ProcessEnv = {
|
|
96
103
|
...process.env,
|
|
97
104
|
TTSC_NODE_BINARY: process.env.TTSC_NODE_BINARY ?? process.execPath,
|
|
105
|
+
...(pluginConfigDir === undefined
|
|
106
|
+
? {}
|
|
107
|
+
: { TTSC_PLUGIN_CONFIG_DIR: pluginConfigDir }),
|
|
98
108
|
TTSC_TSGO_BINARY: process.env.TTSC_TSGO_BINARY ?? tsgoBinary,
|
|
99
109
|
TTSC_TTSX_BINARY:
|
|
100
110
|
process.env.TTSC_TTSX_BINARY ??
|
|
101
111
|
path.join(__dirname, "..", "..", "launcher", "ttsx.js"),
|
|
102
112
|
...context.env,
|
|
103
113
|
};
|
|
114
|
+
// The anchor is per-invocation state owned by this host: when this run
|
|
115
|
+
// declared none (and the caller's env does not name one), drop any value
|
|
116
|
+
// inherited from an ancestor ttsc process so a nested build never
|
|
117
|
+
// mis-anchors its plugins at the outer project.
|
|
118
|
+
if (
|
|
119
|
+
pluginConfigDir === undefined &&
|
|
120
|
+
context.env?.TTSC_PLUGIN_CONFIG_DIR === undefined
|
|
121
|
+
) {
|
|
122
|
+
delete env.TTSC_PLUGIN_CONFIG_DIR;
|
|
123
|
+
}
|
|
104
124
|
const linked = linkedTransformPlugins(nativePlugins);
|
|
105
125
|
if (linked.length !== 0) {
|
|
106
126
|
env.TTSC_LINKED_PLUGINS_JSON = serializeNativePlugins(linked);
|