ttsc 0.19.3 → 0.20.1
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 +36 -34
- package/cmd/graphdump/main.go +2 -4
- package/cmd/ttsc/filter.go +12 -4
- package/cmd/ttsc/filter_resolves_flag_names_case_insensitively_test.go +53 -0
- package/cmd/ttsc/flags_gen.go +3 -3
- package/cmd/ttscgraph/dump.go +5 -7
- package/cmd/ttscgraph/run_dump_emits_only_checker_verified_member_relations_test.go +118 -0
- package/cmd/ttscgraph/serve.go +58 -308
- package/cmd/ttscgraph/serve_session_keeps_base_url_fallback_unchanged_test.go +49 -0
- package/cmd/ttscgraph/serve_session_keeps_esm_directory_candidate_unchanged_test.go +61 -0
- package/cmd/ttscgraph/serve_session_keeps_exports_blocked_file_candidates_unchanged_test.go +64 -0
- package/cmd/ttscgraph/serve_session_keeps_inactive_conditional_export_unchanged_test.go +66 -0
- package/cmd/ttscgraph/serve_session_keeps_lower_priority_module_candidate_unchanged_test.go +67 -0
- package/cmd/ttscgraph/serve_session_keeps_lower_priority_paths_pattern_unchanged_test.go +58 -0
- package/cmd/ttscgraph/serve_session_keeps_nonlongest_root_dirs_candidate_unchanged_test.go +54 -0
- package/cmd/ttscgraph/serve_session_reloads_commonjs_package_entry_for_esm_test.go +50 -0
- package/cmd/ttscgraph/serve_session_reloads_module_suffix_candidate_test.go +41 -0
- package/cmd/ttscgraph/serve_session_reloads_superseding_module_candidates_test.go +216 -0
- package/cmd/ttscgraph/serve_session_retries_failed_dump_test.go +103 -0
- package/driver/graph.go +12 -6
- package/driver/lsp.go +30 -0
- package/driver/program.go +37 -1
- package/driver/resolution_candidates.go +819 -0
- package/driver/windowsjunction/windowsjunction.go +40 -0
- package/go.mod +2 -0
- package/internal/graph/build.go +45 -11
- package/internal/graph/dump.go +276 -100
- package/internal/graph/dump_checkout_paths_are_stable_test.go +210 -0
- package/internal/graph/dump_diagnostics_ride_the_generation_that_built_it_test.go +9 -3
- package/internal/graph/dump_paths.go +172 -0
- package/internal/graph/dump_paths_are_portable_and_injective_test.go +93 -0
- package/internal/graph/dump_uses_ecma_line_terminators_test.go +87 -0
- package/internal/graph/duplicate_variable_object_members_keep_first_declaration_test.go +61 -0
- package/internal/graph/edges.go +208 -0
- package/internal/graph/graph.go +143 -5
- package/internal/graph/line_model.go +122 -0
- package/internal/graph/member_relation_edges_follow_checker_validity_test.go +85 -0
- package/internal/graph/member_relation_edges_preserve_checker_boundaries_test.go +191 -0
- package/internal/graph/member_relation_edges_reject_checker_invalid_pairs_test.go +119 -0
- package/internal/graph/node_ids_preserve_hash_bearing_components_test.go +41 -0
- package/internal/graph/node_modifiers_emit_union_strings_test.go +4 -1
- package/internal/graph/object_literal_members_ride_on_the_snapshot_test.go +192 -0
- package/internal/graph/object_member_signatures_preserve_literal_whitespace_test.go +67 -0
- package/internal/graph/object_members.go +229 -0
- package/internal/graph/provenance.go +88 -30
- package/internal/graph/source_texts_cover_every_resident_program_source_test.go +73 -0
- package/internal/graphsymbols/position_helpers_follow_ecma_line_terminators_test.go +66 -0
- package/internal/graphsymbols/provider.go +26 -91
- package/internal/lspserver/lsp_clean_didopen_refreshes_compiler_state_test.go +144 -0
- package/internal/lspserver/lsp_completion.go +109 -0
- package/internal/lspserver/lsp_completion_gate_never_refuses_a_matching_line_test.go +50 -0
- package/internal/lspserver/lsp_completion_hints_longest_trigger_wins_test.go +149 -0
- package/internal/lspserver/lsp_completion_hints_nearest_trigger_wins_test.go +37 -0
- package/internal/lspserver/lsp_completion_merges_into_upstream_response_test.go +149 -0
- package/internal/lspserver/lsp_completion_nearest_hint_replaces_nearest_filter_test.go +43 -0
- package/internal/lspserver/lsp_completion_preserves_completion_list_extensions_test.go +99 -0
- package/internal/lspserver/lsp_completion_refuses_hints_inside_a_string_literal_test.go +69 -0
- package/internal/lspserver/lsp_completion_replaces_full_filter_in_rank_order_test.go +85 -0
- package/internal/lspserver/lsp_completion_request.go +455 -0
- package/internal/lspserver/lsp_completion_scope.go +530 -0
- package/internal/lspserver/lsp_completion_scope_bench_test.go +41 -0
- package/internal/lspserver/lsp_completion_scope_classifies_regex_statement_and_operator_boundaries_test.go +39 -0
- package/internal/lspserver/lsp_completion_scope_ignores_jsdoc_bytes_in_literals_test.go +108 -0
- package/internal/lspserver/lsp_completion_scope_refuses_regex_hints_test.go +52 -0
- package/internal/lspserver/lsp_completion_trigger_uses_last_rune_test.go +24 -0
- package/internal/lspserver/lsp_deleted_watched_file_withdraws_plugin_diagnostics_test.go +110 -0
- package/internal/lspserver/lsp_didsave_keeps_the_incremental_changed_uri_path_test.go +78 -0
- package/internal/lspserver/lsp_hints_absence_is_not_an_error_test.go +46 -0
- package/internal/lspserver/lsp_hints_refresh_coalesces_concurrent_requests_test.go +82 -0
- package/internal/lspserver/lsp_hints_refresh_ignores_a_superseded_generation_test.go +40 -0
- package/internal/lspserver/lsp_hints_refresh_keeps_each_producer_isolated_test.go +64 -0
- package/internal/lspserver/lsp_hints_refresh_replaces_the_session_snapshot_test.go +66 -0
- package/internal/lspserver/lsp_hints_refresh_scheduled_by_editor_events_test.go +90 -0
- package/internal/lspserver/lsp_hints_refresh_serves_completion_while_running_test.go +91 -0
- package/internal/lspserver/lsp_index_byte_from_bounds_its_search_start_test.go +38 -0
- package/internal/lspserver/lsp_initialize_constrains_position_encoding_to_utf16_test.go +205 -0
- package/internal/lspserver/lsp_late_completion_trigger_is_reported_once_test.go +105 -0
- package/internal/lspserver/lsp_native_completion_hints_decode_flat_lint_wire_test.go +66 -0
- package/internal/lspserver/lsp_native_completion_hints_grouped_compatibility_boundary_test.go +60 -0
- package/internal/lspserver/lsp_native_plugin_source.go +315 -2
- package/internal/lspserver/lsp_native_resident.go +304 -0
- package/internal/lspserver/lsp_plugin.go +85 -8
- package/internal/lspserver/lsp_plugin_completion_resolve_stays_local_test.go +82 -0
- package/internal/lspserver/lsp_position_conversions_span_astral_and_combining_runes_test.go +119 -0
- package/internal/lspserver/lsp_proxy.go +601 -9
- package/internal/lspserver/lsp_refresh.go +70 -0
- package/internal/lspserver/lsp_resident_falls_back_when_serve_unsupported_test.go +43 -0
- package/internal/lspserver/lsp_resident_maps_verb_args_test.go +34 -0
- package/internal/lspserver/lsp_server.go +13 -1
- package/internal/lspserver/lsp_watched_file_changes_reach_compiler_caches_test.go +172 -0
- package/lib/TtscCompiler.d.ts +3 -1
- package/lib/TtscCompiler.js +5 -1
- package/lib/TtscCompiler.js.map +1 -1
- package/lib/TtscService.d.ts +13 -3
- package/lib/TtscService.js +6 -6
- package/lib/TtscService.js.map +1 -1
- package/lib/compiler/internal/project/readConfigJson.d.ts +30 -0
- package/lib/compiler/internal/project/readConfigJson.js +208 -0
- package/lib/compiler/internal/project/readConfigJson.js.map +1 -0
- package/lib/compiler/internal/project/readProjectConfig.js +53 -149
- package/lib/compiler/internal/project/readProjectConfig.js.map +1 -1
- package/lib/compiler/internal/residentTransformProcess.d.ts +15 -2
- package/lib/compiler/internal/residentTransformProcess.js +159 -39
- package/lib/compiler/internal/residentTransformProcess.js.map +1 -1
- package/lib/compiler/internal/runBuild.d.ts +6 -0
- package/lib/compiler/internal/runBuild.js +143 -44
- package/lib/compiler/internal/runBuild.js.map +1 -1
- package/lib/compiler/internal/startResidentTransform.d.ts +5 -1
- package/lib/compiler/internal/startResidentTransform.js +3 -1
- package/lib/compiler/internal/startResidentTransform.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.js +12 -2
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/flags/parser.d.ts +19 -0
- package/lib/flags/parser.js +78 -36
- package/lib/flags/parser.js.map +1 -1
- package/lib/flags/schema.d.ts +49 -11
- package/lib/flags/schema.js +94 -22
- package/lib/flags/schema.js.map +1 -1
- package/lib/internal/assertSafeExplicitCacheDirectory.d.ts +5 -0
- package/lib/internal/assertSafeExplicitCacheDirectory.js +26 -0
- package/lib/internal/assertSafeExplicitCacheDirectory.js.map +1 -0
- package/lib/launcher/internal/runTtsc.js +107 -69
- package/lib/launcher/internal/runTtsc.js.map +1 -1
- package/lib/launcher/internal/runTtsx.js +28 -41
- package/lib/launcher/internal/runTtsx.js.map +1 -1
- package/lib/launcher/internal/runtimeHooks.d.ts +15 -0
- package/lib/launcher/internal/runtimeHooks.js +18 -1
- package/lib/launcher/internal/runtimeHooks.js.map +1 -1
- package/lib/launcher/internal/watchTopology.d.ts +43 -0
- package/lib/launcher/internal/watchTopology.js +360 -0
- package/lib/launcher/internal/watchTopology.js.map +1 -0
- package/lib/plugin/internal/buildSourcePlugin.d.ts +14 -3
- package/lib/plugin/internal/buildSourcePlugin.js +247 -61
- package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/loadProjectPlugins.js +63 -2
- package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
- package/lib/structures/ITtscCompilerTransformation.d.ts +16 -0
- package/lib/structures/internal/ITtscParsedProjectConfig.d.ts +2 -0
- package/package.json +8 -8
- package/shim/ast/shim.go +48 -3
- package/shim/astnav/go.mod +14 -0
- package/shim/astnav/go.sum +20 -0
- package/shim/astnav/shim.go +15 -0
- package/shim/checker/shim.go +100 -0
- package/shim/core/shim.go +47 -0
- package/shim/diagnosticwriter/lint.go +50 -0
- package/src/TtscCompiler.ts +5 -1
- package/src/TtscService.ts +37 -10
- package/src/compiler/internal/project/readConfigJson.ts +209 -0
- package/src/compiler/internal/project/readProjectConfig.ts +62 -158
- package/src/compiler/internal/residentTransformProcess.ts +197 -39
- package/src/compiler/internal/runBuild.ts +169 -47
- package/src/compiler/internal/startResidentTransform.ts +12 -1
- package/src/compiler/internal/transformProjectInMemory.ts +12 -1
- package/src/flags/parser.ts +113 -42
- package/src/flags/schema.ts +113 -31
- package/src/internal/assertSafeExplicitCacheDirectory.ts +29 -0
- package/src/launcher/internal/runTtsc.ts +117 -68
- package/src/launcher/internal/runTtsx.ts +29 -44
- package/src/launcher/internal/runtimeHooks.ts +30 -2
- package/src/launcher/internal/watchTopology.ts +466 -0
- package/src/plugin/internal/buildSourcePlugin.ts +326 -64
- package/src/plugin/internal/loadProjectPlugins.ts +80 -2
- package/src/structures/ITtscCompilerTransformation.ts +17 -0
- package/src/structures/internal/ITtscParsedProjectConfig.ts +2 -0
- package/tools/shim_audit/baseline.json +0 -3
- package/tools/shim_audit/main.go +42 -14
- package/tools/shim_audit/shim_dir_coverage_test.go +25 -0
- package/utility/flags_gen.go +3 -3
- package/utility/host.go +9 -3
|
@@ -8,6 +8,7 @@ import fs from "node:fs";
|
|
|
8
8
|
import { createRequire } from "node:module";
|
|
9
9
|
import os from "node:os";
|
|
10
10
|
import path from "node:path";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
11
12
|
|
|
12
13
|
import { findNearestGoMod } from "../../compiler/internal/paths";
|
|
13
14
|
|
|
@@ -193,7 +194,7 @@ export function buildSourcePlugin(opts: {
|
|
|
193
194
|
const { dir, entry, source } = resolveSourceBuildTarget(opts);
|
|
194
195
|
const overlayDirs = [...(opts.overlayDirs ?? findTtscOverlayDirs())].sort();
|
|
195
196
|
const contributors = opts.contributors ?? [];
|
|
196
|
-
const goBinary = resolveGoCompiler(env);
|
|
197
|
+
const goBinary = resolveGoToolForBuild(resolveGoCompiler(env), env, dir);
|
|
197
198
|
ensureExecutableGoToolchain(goBinary);
|
|
198
199
|
const key = computeCacheKey({
|
|
199
200
|
contributors,
|
|
@@ -267,7 +268,8 @@ function compileSourcePlugin(opts: {
|
|
|
267
268
|
.join(", ")}`;
|
|
268
269
|
process.stderr.write(
|
|
269
270
|
`ttsc: building ${opts.label} "${opts.pluginName}" from ${opts.source}${extra} ` +
|
|
270
|
-
`(this runs once per cache key and can take several minutes on a cold Go cache)
|
|
271
|
+
`(this runs once per cache key and can take several minutes on a cold Go cache) ` +
|
|
272
|
+
`See https://ttsc.dev/docs/ttsc/compile#plugin-cache to persist it across builds.\n`,
|
|
271
273
|
);
|
|
272
274
|
}
|
|
273
275
|
|
|
@@ -1462,6 +1464,13 @@ function sourceBuildWorkspaceReplacements(
|
|
|
1462
1464
|
* `/` (the workspace convention) and then delegate to
|
|
1463
1465
|
* {@link autoQuoteGoModToken}, which mirrors `modfile.AutoQuote`.
|
|
1464
1466
|
*
|
|
1467
|
+
* Separator normalization is itself a quoting trigger. A Windows UNC
|
|
1468
|
+
* (`\\server\share\...`) or extended-length (`\\?\C:\...`) path normalizes into
|
|
1469
|
+
* a token that starts with `//`, and the modfile lexer reads `//` as a line
|
|
1470
|
+
* comment wherever it appears. Emitted bare, such a token turns its whole
|
|
1471
|
+
* `use`/`replace` line into a comment: `go` exits 0, reports nothing, and the
|
|
1472
|
+
* overlay module simply disappears from the workspace.
|
|
1473
|
+
*
|
|
1465
1474
|
* Exported for unit tests.
|
|
1466
1475
|
*/
|
|
1467
1476
|
export function formatGoWorkPath(p: string): string {
|
|
@@ -1472,9 +1481,9 @@ export function formatGoWorkPath(p: string): string {
|
|
|
1472
1481
|
* Quote `token` for a `go.mod`/`go.work` line exactly as
|
|
1473
1482
|
* `golang.org/x/mod/modfile`'s `AutoQuote` does: return it unchanged when it is
|
|
1474
1483
|
* already a clean bare token, otherwise return its Go double-quoted form so the
|
|
1475
|
-
* value round-trips through the modfile lexer. A
|
|
1476
|
-
* emitted byte-for-byte as before; only tokens that would otherwise
|
|
1477
|
-
*
|
|
1484
|
+
* value round-trips through the modfile lexer. A clean bare token is therefore
|
|
1485
|
+
* emitted byte-for-byte as before; only tokens that would otherwise be split or
|
|
1486
|
+
* interpreted as comments are quoted.
|
|
1478
1487
|
*
|
|
1479
1488
|
* Exported for unit tests.
|
|
1480
1489
|
*/
|
|
@@ -1505,11 +1514,11 @@ function mustQuoteGoModToken(s: string): boolean {
|
|
|
1505
1514
|
}
|
|
1506
1515
|
continue;
|
|
1507
1516
|
}
|
|
1508
|
-
if (!
|
|
1517
|
+
if (!isGoPrintable(ch)) {
|
|
1509
1518
|
return true;
|
|
1510
1519
|
}
|
|
1511
1520
|
}
|
|
1512
|
-
return s === "" || s
|
|
1521
|
+
return s === "" || s.includes("//") || s.includes("/*");
|
|
1513
1522
|
}
|
|
1514
1523
|
|
|
1515
1524
|
// Mirror `strconv.Quote`: wrap in double quotes, backslash-escape `"` and `\`,
|
|
@@ -1562,13 +1571,6 @@ function escapeGoRune(ch: string): string {
|
|
|
1562
1571
|
}
|
|
1563
1572
|
}
|
|
1564
1573
|
|
|
1565
|
-
// `unicode.IsGraphic`: categories L, M, N, P, S, Zs (all spacing).
|
|
1566
|
-
const GO_GRAPHIC_RE = /^[\p{L}\p{M}\p{N}\p{P}\p{S}\p{Zs}]$/u;
|
|
1567
|
-
|
|
1568
|
-
function isGoGraphic(ch: string): boolean {
|
|
1569
|
-
return GO_GRAPHIC_RE.test(ch);
|
|
1570
|
-
}
|
|
1571
|
-
|
|
1572
1574
|
// `strconv.IsPrint`: the graphic categories except that the ONLY spacing
|
|
1573
1575
|
// character is the ASCII space (U+0020); other Unicode spaces are escaped.
|
|
1574
1576
|
const GO_PRINTABLE_RE = /^[\p{L}\p{M}\p{N}\p{P}\p{S}]$/u;
|
|
@@ -1761,24 +1763,85 @@ function goToolchainNotFoundMessage(pluginName: string): string {
|
|
|
1761
1763
|
);
|
|
1762
1764
|
}
|
|
1763
1765
|
|
|
1764
|
-
function spawnGoTool(
|
|
1766
|
+
export function spawnGoTool(
|
|
1765
1767
|
goBinary: string,
|
|
1766
1768
|
args: readonly string[],
|
|
1767
1769
|
options: SpawnSyncOptionsWithStringEncoding,
|
|
1768
1770
|
): SpawnSyncReturns<string> {
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1771
|
+
if (process.platform !== "win32") {
|
|
1772
|
+
return spawnSync(goBinary, [...args], options);
|
|
1773
|
+
}
|
|
1774
|
+
const inheritedEnv = options.env ?? process.env;
|
|
1775
|
+
const resolved = resolveWindowsGoTool(
|
|
1776
|
+
goBinary,
|
|
1777
|
+
inheritedEnv,
|
|
1778
|
+
spawnWorkingDirectory(options.cwd),
|
|
1779
|
+
);
|
|
1780
|
+
if (!resolved.wrapper) {
|
|
1781
|
+
return spawnSync(goBinary, [...args], options);
|
|
1782
|
+
}
|
|
1783
|
+
// Preserve the native spawn ENOENT contract before cmd.exe becomes the
|
|
1784
|
+
// actual child process. The callers use that code for the install guidance.
|
|
1785
|
+
if (resolved.location === null) {
|
|
1786
|
+
return spawnSync(goBinary, [...args], options);
|
|
1787
|
+
}
|
|
1788
|
+
const shim = createWindowsGoCommandShim([resolved.location, ...args]);
|
|
1789
|
+
return spawnSync(
|
|
1790
|
+
readWindowsEnvironmentValue(inheritedEnv, "COMSPEC") ??
|
|
1791
|
+
readWindowsEnvironmentValue(process.env, "COMSPEC") ??
|
|
1792
|
+
"cmd.exe",
|
|
1793
|
+
windowsGoCommandArgs(shim.payload),
|
|
1794
|
+
{
|
|
1795
|
+
...options,
|
|
1796
|
+
env: { ...inheritedEnv, ...shim.environment },
|
|
1797
|
+
shell: false,
|
|
1798
|
+
// The /c payload is already one fully quoted Windows command line.
|
|
1799
|
+
windowsVerbatimArguments: true,
|
|
1800
|
+
},
|
|
1801
|
+
);
|
|
1778
1802
|
}
|
|
1779
1803
|
|
|
1780
|
-
|
|
1781
|
-
|
|
1804
|
+
/** Build the fixed cmd.exe switch sequence for one already quoted payload. */
|
|
1805
|
+
export function windowsGoCommandArgs(payload: string): string[] {
|
|
1806
|
+
return ["/d", "/v:off", "/s", "/c", payload];
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1809
|
+
function spawnWorkingDirectory(
|
|
1810
|
+
cwd: SpawnSyncOptionsWithStringEncoding["cwd"],
|
|
1811
|
+
): string {
|
|
1812
|
+
if (cwd === undefined) return process.cwd();
|
|
1813
|
+
return path.resolve(typeof cwd === "string" ? cwd : fileURLToPath(cwd));
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
function isWindowsCommandWrapper(location: string): boolean {
|
|
1817
|
+
return process.platform === "win32" && /\.(?:bat|cmd)$/i.test(location);
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
/** Pass volatile cmd wrapper arguments through one-pass environment expansion. */
|
|
1821
|
+
function createWindowsGoCommandShim(args: readonly string[]): {
|
|
1822
|
+
environment: NodeJS.ProcessEnv;
|
|
1823
|
+
payload: string;
|
|
1824
|
+
} {
|
|
1825
|
+
const prefix = `TTSC_GO_COMMAND_SHIM_${crypto
|
|
1826
|
+
.randomBytes(8)
|
|
1827
|
+
.toString("hex")
|
|
1828
|
+
.toUpperCase()}_ARG_`;
|
|
1829
|
+
const environment = Object.fromEntries(
|
|
1830
|
+
args.map((arg, index) => [prefix + index, quoteWindowsCommandArg(arg)]),
|
|
1831
|
+
);
|
|
1832
|
+
return {
|
|
1833
|
+
environment,
|
|
1834
|
+
// cmd expands each placeholder exactly once. Percent-shaped text inside an
|
|
1835
|
+
// expanded value is not scanned as a second environment reference.
|
|
1836
|
+
payload: `"${args.map((_, index) => `%${prefix}${index}%`).join(" ")}"`,
|
|
1837
|
+
};
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
/** Quote one argv value for the Windows command-line parser used by cmd. */
|
|
1841
|
+
function quoteWindowsCommandArg(arg: string): string {
|
|
1842
|
+
return `"${String(arg)
|
|
1843
|
+
.replace(/(\\*)"/g, '$1$1\\"')
|
|
1844
|
+
.replace(/(\\*)$/, "$1$1")}"`;
|
|
1782
1845
|
}
|
|
1783
1846
|
|
|
1784
1847
|
function goBuildEnv(
|
|
@@ -2228,15 +2291,19 @@ export function computeCacheKey(inputs: {
|
|
|
2228
2291
|
tsgoVersion: string;
|
|
2229
2292
|
}): string {
|
|
2230
2293
|
const env = inputs.env ?? process.env;
|
|
2294
|
+
const goBinary =
|
|
2295
|
+
inputs.goBinary === undefined
|
|
2296
|
+
? undefined
|
|
2297
|
+
: resolveGoToolForBuild(inputs.goBinary, env, inputs.dir);
|
|
2231
2298
|
const hash = crypto.createHash("sha256");
|
|
2232
2299
|
hash.update(`ttsc=${inputs.ttscVersion}\n`);
|
|
2233
2300
|
hash.update(`tsgo=${inputs.tsgoVersion}\n`);
|
|
2234
2301
|
hash.update(`platform=${process.platform}/${process.arch}\n`);
|
|
2235
2302
|
hash.update(`entry=${inputs.entry}\n`);
|
|
2236
|
-
if (
|
|
2237
|
-
hash.update(`go=${resolveGoCompilerIdentity(
|
|
2303
|
+
if (goBinary !== undefined) {
|
|
2304
|
+
hash.update(`go=${resolveGoCompilerIdentity(goBinary, env, inputs.dir)}\n`);
|
|
2238
2305
|
}
|
|
2239
|
-
hashGoBuildEnvironment(hash,
|
|
2306
|
+
hashGoBuildEnvironment(hash, goBinary, inputs.dir, env);
|
|
2240
2307
|
hashExternalGoBuildEnvironment(hash, env);
|
|
2241
2308
|
hashSourceDirectory(hash, "plugin", inputs.dir);
|
|
2242
2309
|
for (const [index, dir] of [...(inputs.overlayDirs ?? [])].sort().entries()) {
|
|
@@ -2328,23 +2395,42 @@ function isHashableFile(name: string): boolean {
|
|
|
2328
2395
|
// content signature (byte size + nanosecond mtime). That signature changes if
|
|
2329
2396
|
// a long-lived host rewrites the binary in place between calls, so the memo
|
|
2330
2397
|
// re-derives the identity exactly as the un-memoized code would and the
|
|
2331
|
-
// cache-key bytes stay byte-for-byte identical to today.
|
|
2332
|
-
//
|
|
2398
|
+
// cache-key bytes stay byte-for-byte identical to today. The selected compiler
|
|
2399
|
+
// path is shared by every build subprocess on Windows, while `go version` uses
|
|
2400
|
+
// the same effective cwd and environment as the cache-key `go env` query. The
|
|
2401
|
+
// memo key includes that context so an environment-sensitive wrapper cannot
|
|
2402
|
+
// lend its version result to another compiler invocation.
|
|
2333
2403
|
const goCompilerIdentityCache = new Map<string, string>();
|
|
2334
2404
|
|
|
2335
2405
|
function resolveGoCompilerIdentity(
|
|
2336
2406
|
goBinary: string,
|
|
2337
2407
|
env: NodeJS.ProcessEnv = process.env,
|
|
2408
|
+
cwd: string = process.cwd(),
|
|
2338
2409
|
): string {
|
|
2339
|
-
const
|
|
2340
|
-
const
|
|
2410
|
+
const selected = resolveGoToolForBuild(goBinary, env, cwd);
|
|
2411
|
+
const resolved =
|
|
2412
|
+
process.platform === "win32"
|
|
2413
|
+
? resolveRealPath(selected)
|
|
2414
|
+
: resolveExecutableIdentityPath(selected, env, cwd);
|
|
2415
|
+
const compilerEnv = goBuildEnv(selected, undefined, env);
|
|
2416
|
+
const memoKey = goCompilerIdentityMemoKey(
|
|
2417
|
+
goBinary,
|
|
2418
|
+
resolved,
|
|
2419
|
+
compilerEnv,
|
|
2420
|
+
cwd,
|
|
2421
|
+
);
|
|
2341
2422
|
if (memoKey !== null) {
|
|
2342
2423
|
const cached = goCompilerIdentityCache.get(memoKey);
|
|
2343
2424
|
if (cached !== undefined) {
|
|
2344
2425
|
return cached;
|
|
2345
2426
|
}
|
|
2346
2427
|
}
|
|
2347
|
-
const identity = computeGoCompilerIdentity(
|
|
2428
|
+
const identity = computeGoCompilerIdentity(
|
|
2429
|
+
selected,
|
|
2430
|
+
resolved,
|
|
2431
|
+
compilerEnv,
|
|
2432
|
+
cwd,
|
|
2433
|
+
);
|
|
2348
2434
|
if (memoKey !== null) {
|
|
2349
2435
|
goCompilerIdentityCache.set(memoKey, identity);
|
|
2350
2436
|
}
|
|
@@ -2357,21 +2443,38 @@ function resolveGoCompilerIdentity(
|
|
|
2357
2443
|
function goCompilerIdentityMemoKey(
|
|
2358
2444
|
goBinary: string,
|
|
2359
2445
|
resolved: string,
|
|
2446
|
+
env: NodeJS.ProcessEnv,
|
|
2447
|
+
cwd: string,
|
|
2360
2448
|
): string | null {
|
|
2361
2449
|
try {
|
|
2362
2450
|
const stat = fs.statSync(resolved);
|
|
2363
|
-
|
|
2451
|
+
const context = crypto.createHash("sha256");
|
|
2452
|
+
context.update(cwd);
|
|
2453
|
+
for (const [key, value] of Object.entries(env).sort(([left], [right]) =>
|
|
2454
|
+
left === right ? 0 : left < right ? -1 : 1,
|
|
2455
|
+
)) {
|
|
2456
|
+
if (value === undefined) continue;
|
|
2457
|
+
context.update(`\0${key.length}:${key}${value.length}:${value}`);
|
|
2458
|
+
}
|
|
2459
|
+
return `${goBinary}\0${resolved}\0${stat.size}\0${stat.mtimeMs}\0${context.digest("hex")}`;
|
|
2364
2460
|
} catch {
|
|
2365
2461
|
return null;
|
|
2366
2462
|
}
|
|
2367
2463
|
}
|
|
2368
2464
|
|
|
2369
|
-
function computeGoCompilerIdentity(
|
|
2465
|
+
function computeGoCompilerIdentity(
|
|
2466
|
+
goBinary: string,
|
|
2467
|
+
resolved: string,
|
|
2468
|
+
env: NodeJS.ProcessEnv,
|
|
2469
|
+
cwd: string,
|
|
2470
|
+
): string {
|
|
2370
2471
|
if (!fs.existsSync(resolved)) {
|
|
2371
2472
|
return "missing";
|
|
2372
2473
|
}
|
|
2373
2474
|
const version = spawnGoTool(goBinary, ["version"], {
|
|
2475
|
+
cwd,
|
|
2374
2476
|
encoding: "utf8",
|
|
2477
|
+
env,
|
|
2375
2478
|
windowsHide: true,
|
|
2376
2479
|
});
|
|
2377
2480
|
const versionText =
|
|
@@ -2385,48 +2488,207 @@ function computeGoCompilerIdentity(goBinary: string, resolved: string): string {
|
|
|
2385
2488
|
function resolveExecutableIdentityPath(
|
|
2386
2489
|
binary: string,
|
|
2387
2490
|
env: NodeJS.ProcessEnv = process.env,
|
|
2491
|
+
cwd: string = process.cwd(),
|
|
2388
2492
|
): string {
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2493
|
+
const resolved = findExecutablePath(binary, env, cwd);
|
|
2494
|
+
return resolved === null ? binary : resolveRealPath(resolved);
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2497
|
+
/** Pin Windows PATH and command-wrapper lookup to one build-wide target. */
|
|
2498
|
+
function resolveGoToolForBuild(
|
|
2499
|
+
binary: string,
|
|
2500
|
+
env: NodeJS.ProcessEnv,
|
|
2501
|
+
cwd: string,
|
|
2502
|
+
): string {
|
|
2503
|
+
if (process.platform !== "win32") return binary;
|
|
2504
|
+
return resolveWindowsGoTool(binary, env, cwd).location ?? binary;
|
|
2505
|
+
}
|
|
2506
|
+
|
|
2507
|
+
function findExecutablePath(
|
|
2508
|
+
binary: string,
|
|
2509
|
+
env: NodeJS.ProcessEnv,
|
|
2510
|
+
cwd: string,
|
|
2511
|
+
): string | null {
|
|
2512
|
+
for (const candidate of executableSearchBases(binary, env, cwd)) {
|
|
2513
|
+
const resolved = findExecutableCandidate(candidate, env);
|
|
2514
|
+
if (resolved !== null) return resolved;
|
|
2515
|
+
}
|
|
2516
|
+
return null;
|
|
2517
|
+
}
|
|
2518
|
+
|
|
2519
|
+
interface IWindowsGoToolResolution {
|
|
2520
|
+
location: string | null;
|
|
2521
|
+
wrapper: boolean;
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2524
|
+
/** Preserve libuv's native target before falling back to cmd/bat wrappers. */
|
|
2525
|
+
function resolveWindowsGoTool(
|
|
2526
|
+
binary: string,
|
|
2527
|
+
env: NodeJS.ProcessEnv,
|
|
2528
|
+
cwd: string,
|
|
2529
|
+
): IWindowsGoToolResolution {
|
|
2530
|
+
const candidates = executableSearchBases(binary, env, cwd);
|
|
2531
|
+
if (isWindowsCommandWrapper(binary)) {
|
|
2532
|
+
return {
|
|
2533
|
+
location: candidates.find(isExecutableFile) ?? null,
|
|
2534
|
+
wrapper: true,
|
|
2535
|
+
};
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2538
|
+
const hasExtension = windowsFileNameHasExtension(binary);
|
|
2539
|
+
for (const candidate of candidates) {
|
|
2540
|
+
if (hasExtension && isExecutableFile(candidate)) {
|
|
2541
|
+
return { location: candidate, wrapper: false };
|
|
2542
|
+
}
|
|
2543
|
+
for (const extension of [".com", ".exe"]) {
|
|
2544
|
+
const executable = candidate + extension;
|
|
2545
|
+
if (isExecutableFile(executable)) {
|
|
2546
|
+
return { location: executable, wrapper: false };
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2550
|
+
|
|
2551
|
+
const wrapperExtensions = windowsExecutableExtensions(env).filter((ext) =>
|
|
2552
|
+
/\.(?:bat|cmd)$/i.test(ext),
|
|
2553
|
+
);
|
|
2554
|
+
for (const candidate of candidates) {
|
|
2555
|
+
for (const extension of wrapperExtensions) {
|
|
2556
|
+
const executable = candidate + extension;
|
|
2557
|
+
if (isExecutableFile(executable)) {
|
|
2558
|
+
return { location: executable, wrapper: true };
|
|
2411
2559
|
}
|
|
2412
2560
|
}
|
|
2413
2561
|
}
|
|
2414
|
-
return
|
|
2562
|
+
return { location: null, wrapper: false };
|
|
2563
|
+
}
|
|
2564
|
+
|
|
2565
|
+
function executableSearchBases(
|
|
2566
|
+
binary: string,
|
|
2567
|
+
env: NodeJS.ProcessEnv,
|
|
2568
|
+
cwd: string,
|
|
2569
|
+
): string[] {
|
|
2570
|
+
if (path.isAbsolute(binary)) return [binary];
|
|
2571
|
+
if (hasPathQualifier(binary)) return [path.resolve(cwd, binary)];
|
|
2572
|
+
|
|
2573
|
+
const directories =
|
|
2574
|
+
process.platform === "win32"
|
|
2575
|
+
? splitWindowsSearchPath(readPathEnvironment(env))
|
|
2576
|
+
// libuv skips only genuinely empty slices. A quoted-empty slice
|
|
2577
|
+
// survives that check, unquotes to "", and therefore names cwd.
|
|
2578
|
+
.filter((entry) => entry.length > 0)
|
|
2579
|
+
.map(unquoteWindowsSearchEntry)
|
|
2580
|
+
: readPathEnvironment(env).split(path.delimiter);
|
|
2581
|
+
const noDefaultCurrentDirectory =
|
|
2582
|
+
process.platform === "win32"
|
|
2583
|
+
? readWindowsEnvironmentValue(
|
|
2584
|
+
process.env,
|
|
2585
|
+
"NoDefaultCurrentDirectoryInExePath",
|
|
2586
|
+
)
|
|
2587
|
+
: undefined;
|
|
2588
|
+
if (process.platform === "win32" && noDefaultCurrentDirectory === undefined) {
|
|
2589
|
+
directories.unshift(cwd);
|
|
2590
|
+
}
|
|
2591
|
+
return directories.map((dir) => path.resolve(cwd, dir, binary));
|
|
2592
|
+
}
|
|
2593
|
+
|
|
2594
|
+
function findExecutableCandidate(
|
|
2595
|
+
candidate: string,
|
|
2596
|
+
env: NodeJS.ProcessEnv,
|
|
2597
|
+
): string | null {
|
|
2598
|
+
if (isExecutableFile(candidate)) return candidate;
|
|
2599
|
+
if (process.platform !== "win32") return null;
|
|
2600
|
+
// Probe every PATHEXT extension, not just `.exe`, so a compiler backed by a
|
|
2601
|
+
// `.cmd`/`.bat` wrapper is both launched correctly and hashed into the cache
|
|
2602
|
+
// key. Otherwise the wrapper reads as missing and changes do not invalidate
|
|
2603
|
+
// the cached plugin binary.
|
|
2604
|
+
for (const ext of windowsExecutableExtensions(env)) {
|
|
2605
|
+
const executable = `${candidate}${ext}`;
|
|
2606
|
+
if (isExecutableFile(executable)) return executable;
|
|
2607
|
+
}
|
|
2608
|
+
return null;
|
|
2609
|
+
}
|
|
2610
|
+
|
|
2611
|
+
function isExecutableFile(location: string): boolean {
|
|
2612
|
+
try {
|
|
2613
|
+
return fs.statSync(location).isFile();
|
|
2614
|
+
} catch {
|
|
2615
|
+
return false;
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
|
|
2619
|
+
function hasPathQualifier(location: string): boolean {
|
|
2620
|
+
return (
|
|
2621
|
+
location.includes(path.sep) ||
|
|
2622
|
+
(process.platform === "win32" &&
|
|
2623
|
+
(location.includes("/") || /^[a-zA-Z]:/.test(location)))
|
|
2624
|
+
);
|
|
2625
|
+
}
|
|
2626
|
+
|
|
2627
|
+
function windowsFileNameHasExtension(location: string): boolean {
|
|
2628
|
+
const name = path.basename(location);
|
|
2629
|
+
const dot = name.indexOf(".");
|
|
2630
|
+
return dot >= 0 && dot < name.length - 1;
|
|
2631
|
+
}
|
|
2632
|
+
|
|
2633
|
+
function splitWindowsSearchPath(value: string): string[] {
|
|
2634
|
+
const entries: string[] = [];
|
|
2635
|
+
let start = 0;
|
|
2636
|
+
let quote = "";
|
|
2637
|
+
for (let index = 0; index < value.length; index++) {
|
|
2638
|
+
const character = value[index]!;
|
|
2639
|
+
if (quote !== "") {
|
|
2640
|
+
if (character === quote) quote = "";
|
|
2641
|
+
} else if ((character === '"' || character === "'") && index === start) {
|
|
2642
|
+
quote = character;
|
|
2643
|
+
} else if (character === ";") {
|
|
2644
|
+
entries.push(value.slice(start, index));
|
|
2645
|
+
start = index + 1;
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
entries.push(value.slice(start));
|
|
2649
|
+
return entries;
|
|
2650
|
+
}
|
|
2651
|
+
|
|
2652
|
+
function unquoteWindowsSearchEntry(location: string): string {
|
|
2653
|
+
const first = location[0];
|
|
2654
|
+
const withoutFirst =
|
|
2655
|
+
first === '"' || first === "'" ? location.slice(1) : location;
|
|
2656
|
+
const last = withoutFirst[withoutFirst.length - 1];
|
|
2657
|
+
return last === '"' || last === "'"
|
|
2658
|
+
? withoutFirst.slice(0, -1)
|
|
2659
|
+
: withoutFirst;
|
|
2415
2660
|
}
|
|
2416
2661
|
|
|
2417
2662
|
function windowsExecutableExtensions(
|
|
2418
2663
|
env: NodeJS.ProcessEnv = process.env,
|
|
2419
2664
|
): readonly string[] {
|
|
2420
|
-
const pathext = env
|
|
2665
|
+
const pathext = readWindowsEnvironmentValue(env, "PATHEXT");
|
|
2421
2666
|
const raw = pathext && pathext.length > 0 ? pathext : ".COM;.EXE;.BAT;.CMD";
|
|
2422
|
-
return raw
|
|
2423
|
-
.
|
|
2424
|
-
.map((ext) => ext.
|
|
2667
|
+
return splitWindowsSearchPath(raw)
|
|
2668
|
+
.map(unquoteWindowsSearchEntry)
|
|
2669
|
+
.map((ext) => ext.toLowerCase())
|
|
2425
2670
|
.filter((ext) => ext.length > 0);
|
|
2426
2671
|
}
|
|
2427
2672
|
|
|
2428
2673
|
function readPathEnvironment(env: NodeJS.ProcessEnv = process.env): string {
|
|
2429
|
-
return
|
|
2674
|
+
return process.platform === "win32"
|
|
2675
|
+
? (readWindowsEnvironmentValue(env, "PATH") ??
|
|
2676
|
+
readWindowsEnvironmentValue(process.env, "PATH") ??
|
|
2677
|
+
"")
|
|
2678
|
+
: (env.PATH ?? "/usr/bin:/bin");
|
|
2679
|
+
}
|
|
2680
|
+
|
|
2681
|
+
function readWindowsEnvironmentValue(
|
|
2682
|
+
env: NodeJS.ProcessEnv,
|
|
2683
|
+
name: string,
|
|
2684
|
+
): string | undefined {
|
|
2685
|
+
const exact = env[name];
|
|
2686
|
+
if (exact !== undefined) return exact;
|
|
2687
|
+
const normalized = name.toLowerCase();
|
|
2688
|
+
const key = Object.keys(env)
|
|
2689
|
+
.filter((candidate) => candidate.toLowerCase() === normalized)
|
|
2690
|
+
.sort()[0];
|
|
2691
|
+
return key === undefined ? undefined : env[key];
|
|
2430
2692
|
}
|
|
2431
2693
|
|
|
2432
2694
|
function resolveRealPath(location: string): string {
|
|
@@ -5,6 +5,7 @@ import os from "node:os";
|
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
|
|
7
7
|
import { findNearestGoMod } from "../../compiler/internal/paths";
|
|
8
|
+
import { readJsonFile } from "../../compiler/internal/project/readConfigJson";
|
|
8
9
|
import { readProjectConfig } from "../../compiler/internal/project/readProjectConfig";
|
|
9
10
|
import type { ITtscPlugin } from "../../structures/ITtscPlugin";
|
|
10
11
|
import type { ITtscPluginContributor } from "../../structures/ITtscPluginContributor";
|
|
@@ -541,11 +542,17 @@ function findNearestPackageJson(location: string): string | undefined {
|
|
|
541
542
|
}
|
|
542
543
|
}
|
|
543
544
|
|
|
545
|
+
/**
|
|
546
|
+
* Read a package manifest, or `undefined` when the file is absent or is not a
|
|
547
|
+
* JSON object. A malformed manifest throws naming the file: these are usually
|
|
548
|
+
* files the user did not author, which makes an unattributed `JSON.parse`
|
|
549
|
+
* message worse here than anywhere else.
|
|
550
|
+
*/
|
|
544
551
|
function readPackageManifest(file: string): PackageManifest | undefined {
|
|
545
552
|
if (!fs.existsSync(file)) {
|
|
546
553
|
return undefined;
|
|
547
554
|
}
|
|
548
|
-
const parsed =
|
|
555
|
+
const parsed = readJsonFile(file);
|
|
549
556
|
return isRecord(parsed) ? (parsed as PackageManifest) : undefined;
|
|
550
557
|
}
|
|
551
558
|
|
|
@@ -1157,7 +1164,78 @@ function selectExportTarget(exportsField: unknown, subpath: string): unknown {
|
|
|
1157
1164
|
// Conditions object: the whole value is the `.` target.
|
|
1158
1165
|
return subpath === "." ? exportsField : undefined;
|
|
1159
1166
|
}
|
|
1160
|
-
|
|
1167
|
+
if (
|
|
1168
|
+
Object.prototype.hasOwnProperty.call(record, subpath) &&
|
|
1169
|
+
!subpath.includes("*") &&
|
|
1170
|
+
!subpath.endsWith("/")
|
|
1171
|
+
) {
|
|
1172
|
+
return record[subpath];
|
|
1173
|
+
}
|
|
1174
|
+
const patterns = Object.keys(record)
|
|
1175
|
+
.filter((key) => exportPatternReplacement(key, subpath) !== undefined)
|
|
1176
|
+
.sort(compareExportPatternKeys);
|
|
1177
|
+
if (patterns.length === 0) {
|
|
1178
|
+
return undefined;
|
|
1179
|
+
}
|
|
1180
|
+
const pattern = patterns[0]!;
|
|
1181
|
+
return substituteExportTarget(
|
|
1182
|
+
record[pattern],
|
|
1183
|
+
exportPatternReplacement(pattern, subpath)!,
|
|
1184
|
+
);
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
/** Capture the middle of one valid single-star exports key. */
|
|
1188
|
+
function exportPatternReplacement(
|
|
1189
|
+
pattern: string,
|
|
1190
|
+
subpath: string,
|
|
1191
|
+
): string | undefined {
|
|
1192
|
+
const star = pattern.indexOf("*");
|
|
1193
|
+
if (
|
|
1194
|
+
!pattern.startsWith("./") ||
|
|
1195
|
+
star === -1 ||
|
|
1196
|
+
pattern.indexOf("*", star + 1) !== -1
|
|
1197
|
+
) {
|
|
1198
|
+
return undefined;
|
|
1199
|
+
}
|
|
1200
|
+
const prefix = pattern.slice(0, star);
|
|
1201
|
+
const suffix = pattern.slice(star + 1);
|
|
1202
|
+
if (
|
|
1203
|
+
subpath.length < pattern.length ||
|
|
1204
|
+
!subpath.startsWith(prefix) ||
|
|
1205
|
+
!subpath.endsWith(suffix)
|
|
1206
|
+
) {
|
|
1207
|
+
return undefined;
|
|
1208
|
+
}
|
|
1209
|
+
return subpath.slice(prefix.length, subpath.length - suffix.length);
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
/** Node exports patterns rank longer prefixes, then longer full keys, first. */
|
|
1213
|
+
function compareExportPatternKeys(left: string, right: string): number {
|
|
1214
|
+
const leftPrefix = left.indexOf("*");
|
|
1215
|
+
const rightPrefix = right.indexOf("*");
|
|
1216
|
+
if (leftPrefix !== rightPrefix) {
|
|
1217
|
+
return rightPrefix - leftPrefix;
|
|
1218
|
+
}
|
|
1219
|
+
return right.length - left.length;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
/** Substitute the selected pattern capture into every string target branch. */
|
|
1223
|
+
function substituteExportTarget(target: unknown, replacement: string): unknown {
|
|
1224
|
+
if (typeof target === "string") {
|
|
1225
|
+
return target.split("*").join(replacement);
|
|
1226
|
+
}
|
|
1227
|
+
if (Array.isArray(target)) {
|
|
1228
|
+
return target.map((entry) => substituteExportTarget(entry, replacement));
|
|
1229
|
+
}
|
|
1230
|
+
if (typeof target !== "object" || target === null) {
|
|
1231
|
+
return target;
|
|
1232
|
+
}
|
|
1233
|
+
return Object.fromEntries(
|
|
1234
|
+
Object.entries(target).map(([condition, value]) => [
|
|
1235
|
+
condition,
|
|
1236
|
+
substituteExportTarget(value, replacement),
|
|
1237
|
+
]),
|
|
1238
|
+
);
|
|
1161
1239
|
}
|
|
1162
1240
|
|
|
1163
1241
|
/** True when condition key `condition` appears anywhere in a (nested) target. */
|
|
@@ -48,6 +48,23 @@ export namespace ITtscCompilerTransformation {
|
|
|
48
48
|
|
|
49
49
|
/** The project tsconfig followed by its `extends` ancestry. */
|
|
50
50
|
configs: string[];
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Resolution candidates that would outrank the selected target, keyed by
|
|
54
|
+
* importing file. The compiler already resolved the import to a graph edge;
|
|
55
|
+
* a listed path can be absent now or can be an existing unsuccessful probe,
|
|
56
|
+
* and its appearance or change can alter that edge without editing the
|
|
57
|
+
* importer or a recorded file.
|
|
58
|
+
*
|
|
59
|
+
* Hosts watch and hash these paths in addition to realized graph members. A
|
|
60
|
+
* candidate strictly below the selected target is deliberately absent: its
|
|
61
|
+
* creation cannot change resolution and must not invalidate a cache.
|
|
62
|
+
*
|
|
63
|
+
* A host with nothing to report leaves the whole property out rather than
|
|
64
|
+
* sending an empty map, so `undefined` and "no superseding candidate" are
|
|
65
|
+
* the same observation on the wire and after decoding.
|
|
66
|
+
*/
|
|
67
|
+
candidates?: Record<string, string[]>;
|
|
51
68
|
}
|
|
52
69
|
|
|
53
70
|
/** Successful source-to-source transformation result. */
|
|
@@ -3,6 +3,8 @@ import type { ITtscProjectIdentity } from "./ITtscProjectIdentity";
|
|
|
3
3
|
|
|
4
4
|
/** Resolved project config subset used inside the ttsc host. */
|
|
5
5
|
export interface ITtscParsedProjectConfig {
|
|
6
|
+
/** Every resolved tsconfig/jsconfig in the inherited `extends` chain. */
|
|
7
|
+
configPaths: readonly string[];
|
|
6
8
|
/** Compiler options after extends inheritance has been applied. */
|
|
7
9
|
compilerOptions: {
|
|
8
10
|
/** Absolute output directory when configured. */
|