ttsc 0.26.1 → 0.27.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.
Files changed (119) hide show
  1. package/README.md +10 -1
  2. package/cmd/ttsc/api_transform.go +17 -3
  3. package/cmd/ttscgraph/auxiliary_identity_state_tracks_retargets_not_source_contents_test.go +85 -0
  4. package/cmd/ttscgraph/disk_realpath_other.go +16 -0
  5. package/cmd/ttscgraph/disk_realpath_windows.go +56 -0
  6. package/cmd/ttscgraph/serve.go +104 -35
  7. package/driver/diagnostics_preamble.go +284 -0
  8. package/driver/emit_plugin.go +71 -19
  9. package/driver/graph.go +64 -11
  10. package/driver/input_observation.go +273 -0
  11. package/driver/input_observation_test.go +149 -0
  12. package/driver/plugins.go +384 -4
  13. package/driver/program.go +81 -15
  14. package/driver/resolution_candidates.go +13 -5
  15. package/driver/rewrite.go +47 -4
  16. package/internal/graph/diagnostics.go +4 -3
  17. package/internal/graph/provenance.go +10 -1
  18. package/lib/TtscCompiler.d.ts +12 -11
  19. package/lib/TtscCompiler.js +44 -29
  20. package/lib/TtscCompiler.js.map +1 -1
  21. package/lib/compiler/internal/captureProcessOutput.js +2 -2
  22. package/lib/compiler/internal/captureProcessOutput.js.map +1 -1
  23. package/lib/compiler/internal/compileProjectInMemory.js +11 -3
  24. package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
  25. package/lib/compiler/internal/resolveEmittedJavaScript.d.ts +2 -0
  26. package/lib/compiler/internal/resolveEmittedJavaScript.js +3 -0
  27. package/lib/compiler/internal/resolveEmittedJavaScript.js.map +1 -1
  28. package/lib/compiler/internal/runBuild.d.ts +29 -1
  29. package/lib/compiler/internal/runBuild.js +117 -32
  30. package/lib/compiler/internal/runBuild.js.map +1 -1
  31. package/lib/compiler/internal/runSingleFileEmit.js +9 -2
  32. package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
  33. package/lib/compiler/internal/sharedHostHelpers.d.ts +28 -0
  34. package/lib/compiler/internal/sharedHostHelpers.js +39 -0
  35. package/lib/compiler/internal/sharedHostHelpers.js.map +1 -1
  36. package/lib/compiler/internal/startResidentTransform.js +12 -4
  37. package/lib/compiler/internal/startResidentTransform.js.map +1 -1
  38. package/lib/compiler/internal/transformProjectInMemory.d.ts +3 -0
  39. package/lib/compiler/internal/transformProjectInMemory.js +239 -35
  40. package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
  41. package/lib/flags/schema.js +33 -5
  42. package/lib/flags/schema.js.map +1 -1
  43. package/lib/internal/createCanonicalTempDirectory.d.ts +17 -0
  44. package/lib/internal/createCanonicalTempDirectory.js +42 -0
  45. package/lib/internal/createCanonicalTempDirectory.js.map +1 -0
  46. package/lib/internal/projectInputPathIdentity.d.ts +3 -0
  47. package/lib/internal/projectInputPathIdentity.js +11 -5
  48. package/lib/internal/projectInputPathIdentity.js.map +1 -1
  49. package/lib/internal/resolveNodeBinary.d.ts +14 -0
  50. package/lib/internal/resolveNodeBinary.js +150 -0
  51. package/lib/internal/resolveNodeBinary.js.map +1 -0
  52. package/lib/internal/resolveSafeCacheCleanupTargets.d.ts +15 -0
  53. package/lib/internal/resolveSafeCacheCleanupTargets.js +61 -0
  54. package/lib/internal/resolveSafeCacheCleanupTargets.js.map +1 -0
  55. package/lib/launcher/internal/assertNoSolutionBuild.d.ts +31 -0
  56. package/lib/launcher/internal/assertNoSolutionBuild.js +38 -0
  57. package/lib/launcher/internal/assertNoSolutionBuild.js.map +1 -0
  58. package/lib/launcher/internal/prepareExecution.d.ts +3 -0
  59. package/lib/launcher/internal/prepareExecution.js +73 -26
  60. package/lib/launcher/internal/prepareExecution.js.map +1 -1
  61. package/lib/launcher/internal/runTtsc.js +27 -13
  62. package/lib/launcher/internal/runTtsc.js.map +1 -1
  63. package/lib/launcher/internal/runTtscserver.js +18 -3
  64. package/lib/launcher/internal/runTtscserver.js.map +1 -1
  65. package/lib/launcher/internal/runTtsx.js +4 -0
  66. package/lib/launcher/internal/runTtsx.js.map +1 -1
  67. package/lib/launcher/internal/runtimeHooks.d.ts +37 -1
  68. package/lib/launcher/internal/runtimeHooks.js +660 -62
  69. package/lib/launcher/internal/runtimeHooks.js.map +1 -1
  70. package/lib/plugin/internal/buildSourcePlugin.d.ts +62 -8
  71. package/lib/plugin/internal/buildSourcePlugin.js +754 -72
  72. package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
  73. package/lib/plugin/internal/loadProjectPlugins.d.ts +17 -5
  74. package/lib/plugin/internal/loadProjectPlugins.js +1339 -77
  75. package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
  76. package/lib/register.d.ts +1 -0
  77. package/lib/register.js +46 -0
  78. package/lib/register.js.map +1 -0
  79. package/lib/structures/ITtscCompilerContext.d.ts +6 -3
  80. package/lib/structures/ITtscCompilerTransformation.d.ts +31 -0
  81. package/lib/structures/ITtscPlugin.d.ts +33 -0
  82. package/package.json +16 -9
  83. package/shim/checker/go.mod +9 -0
  84. package/shim/checker/go.sum +22 -0
  85. package/shim/checker/shim.go +75 -0
  86. package/shim/compiler/emit_sourcemap.go +56 -15
  87. package/shim/compiler/incremental.go +45 -8
  88. package/src/TtscCompiler.ts +55 -33
  89. package/src/compiler/internal/captureProcessOutput.ts +3 -2
  90. package/src/compiler/internal/compileProjectInMemory.ts +11 -3
  91. package/src/compiler/internal/resolveEmittedJavaScript.ts +6 -0
  92. package/src/compiler/internal/runBuild.ts +172 -36
  93. package/src/compiler/internal/runSingleFileEmit.ts +9 -2
  94. package/src/compiler/internal/sharedHostHelpers.ts +44 -0
  95. package/src/compiler/internal/startResidentTransform.ts +12 -3
  96. package/src/compiler/internal/transformProjectInMemory.ts +410 -39
  97. package/src/flags/schema.ts +35 -5
  98. package/src/internal/createCanonicalTempDirectory.ts +53 -0
  99. package/src/internal/projectInputPathIdentity.ts +17 -4
  100. package/src/internal/resolveNodeBinary.ts +173 -0
  101. package/src/internal/resolveSafeCacheCleanupTargets.ts +85 -0
  102. package/src/launcher/internal/assertNoSolutionBuild.ts +40 -0
  103. package/src/launcher/internal/prepareExecution.ts +78 -26
  104. package/src/launcher/internal/runTtsc.ts +26 -13
  105. package/src/launcher/internal/runTtscserver.ts +18 -3
  106. package/src/launcher/internal/runTtsx.ts +4 -0
  107. package/src/launcher/internal/runtimeHooks.ts +830 -66
  108. package/src/plugin/internal/buildSourcePlugin.ts +984 -79
  109. package/src/plugin/internal/loadProjectPlugins.ts +1718 -104
  110. package/src/register.ts +47 -0
  111. package/src/structures/ITtscCompilerContext.ts +6 -3
  112. package/src/structures/ITtscCompilerTransformation.ts +39 -0
  113. package/src/structures/ITtscPlugin.ts +36 -0
  114. package/tools/shim_audit/baseline.json +0 -1
  115. package/utility/host.go +9 -3
  116. package/lib/internal/assertSafeExplicitCacheDirectory.d.ts +0 -5
  117. package/lib/internal/assertSafeExplicitCacheDirectory.js +0 -26
  118. package/lib/internal/assertSafeExplicitCacheDirectory.js.map +0 -1
  119. package/src/internal/assertSafeExplicitCacheDirectory.ts +0 -29
@@ -0,0 +1,47 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ import { prepareExecution } from "./launcher/internal/prepareExecution";
5
+ import {
6
+ type RuntimeManifest,
7
+ installRuntimeHooks,
8
+ } from "./launcher/internal/runtimeHooks";
9
+
10
+ const cleanupDirectories = new Set<string>();
11
+ let runtimeSequence = 0;
12
+
13
+ /**
14
+ * Prepare one TypeScript root with the same checked compiler pipeline as ttsx,
15
+ * then expose its transient emit to the already-installed runtime hooks.
16
+ */
17
+ function prepareEntry(filename: string): RuntimeManifest {
18
+ const execution = prepareExecution(filename, {
19
+ runtimeCacheKey: `register-${process.pid}-${++runtimeSequence}`,
20
+ });
21
+ cleanupDirectories.add(execution.cleanupDir);
22
+ return {
23
+ depCacheDir: path.join(execution.cleanupDir, "deps"),
24
+ emitDir: execution.emitDir,
25
+ emittedFiles: execution.emittedFiles,
26
+ entryFile: execution.entryFile,
27
+ entrySource: execution.entrySource,
28
+ moduleOptions: execution.moduleOptions,
29
+ projectRoot: execution.projectRoot,
30
+ rootDir: execution.rootDir,
31
+ };
32
+ }
33
+
34
+ /** Remove every register-owned transient emit when the JavaScript host exits. */
35
+ function cleanupRuntimeOutputs(): void {
36
+ for (const directory of cleanupDirectories) {
37
+ try {
38
+ fs.rmSync(directory, { force: true, recursive: true });
39
+ } catch {
40
+ // Best effort: cleanup must not replace the host process exit status.
41
+ }
42
+ }
43
+ cleanupDirectories.clear();
44
+ }
45
+
46
+ process.once("exit", cleanupRuntimeOutputs);
47
+ installRuntimeHooks({ prepareEntry });
@@ -76,11 +76,14 @@ export interface ITtscCompilerContext {
76
76
  binary?: string;
77
77
 
78
78
  /**
79
- * Additional environment variables for child compiler processes.
79
+ * Additional environment variables for child compiler and plugin-descriptor
80
+ * processes.
80
81
  *
81
82
  * Values are merged over `process.env` before ttsc starts TypeScript-Go,
82
- * native plugin binaries, or the native compiler host used by
83
- * {@link TtscCompiler.compile}.
83
+ * native plugin binaries, isolated descriptor evaluators (including the
84
+ * `ttsx` fallback), or the native compiler host used by
85
+ * {@link TtscCompiler.compile}. Descriptor output is diagnostic text and is
86
+ * forwarded to stderr so it cannot corrupt compiler/API protocol stdout.
84
87
  */
85
88
  env?: NodeJS.ProcessEnv;
86
89
 
@@ -65,6 +65,17 @@ export namespace ITtscCompilerTransformation {
65
65
  * the same observation on the wire and after decoding.
66
66
  */
67
67
  candidates?: Record<string, string[]>;
68
+
69
+ /**
70
+ * SHA-256/null states returned by the compiler filesystem while this graph
71
+ * was being resolved, keyed in the same vocabulary as {@link edges}.
72
+ * Persistent hosts use them to reject a graph whose external file or
73
+ * superseding candidate changed during compilation.
74
+ */
75
+ inputHashes?: Record<string, string | null>;
76
+
77
+ /** Compiler-time physical identities paired with {@link inputHashes}. */
78
+ inputRealpaths?: Record<string, string | null>;
68
79
  }
69
80
 
70
81
  /** Successful source-to-source transformation result. */
@@ -140,6 +151,25 @@ export namespace ITtscCompilerTransformation {
140
151
  */
141
152
  graph?: IReferenceGraph;
142
153
 
154
+ /**
155
+ * Host-wide files consulted before the native transform starts, such as
156
+ * JavaScript plugin descriptors and explicitly selected plugin config
157
+ * files. Unlike {@link dependencies}, these affect every transformed file.
158
+ * Bundler adapters register and validate them as universal inputs without
159
+ * treating arbitrary unclassified project files as configuration.
160
+ */
161
+ hostInputs?: string[];
162
+
163
+ /**
164
+ * SHA-256 fingerprints captured by the plugin loader at the instant each
165
+ * host input influenced this generation. Internal cache validators use
166
+ * these to reject a result raced by a concurrent config/module change.
167
+ */
168
+ hostInputHashes?: Record<string, string | null>;
169
+
170
+ /** Evaluation-time physical identities paired with {@link hostInputs}. */
171
+ hostInputRealpaths?: Record<string, string | null>;
172
+
143
173
  /**
144
174
  * Transformed files (keyed like {@link typescript}) whose output depends on
145
175
  * non-file inputs (environment, time, network) as declared by the transform
@@ -188,6 +218,15 @@ export namespace ITtscCompilerTransformation {
188
218
  */
189
219
  graph?: IReferenceGraph;
190
220
 
221
+ /** Host-wide transform inputs; same contract as {@link ISuccess.hostInputs}. */
222
+ hostInputs?: string[];
223
+
224
+ /** Generation-time host-input fingerprints. */
225
+ hostInputHashes?: Record<string, string | null>;
226
+
227
+ /** Generation-time physical host-input identities. */
228
+ hostInputRealpaths?: Record<string, string | null>;
229
+
191
230
  /**
192
231
  * Volatile transformed files. Same shape and semantics as
193
232
  * {@link ISuccess.volatile}.
@@ -22,6 +22,42 @@ export interface ITtscPlugin {
22
22
  */
23
23
  name?: string;
24
24
 
25
+ /**
26
+ * Absolute files whose contents or presence influence this descriptor or its
27
+ * native transform for every project file.
28
+ *
29
+ * Ttsc automatically records the descriptor's CommonJS module graph, tsconfig
30
+ * ancestry, package-discovery manifest, and an explicit `configFile`. Use
31
+ * this field for additional implicit config discovery and for files a native
32
+ * plugin reads outside the TypeScript reference graph. Missing paths are
33
+ * valid: they represent higher-priority discovery candidates whose later
34
+ * creation must invalidate a resident transform.
35
+ */
36
+ hostInputs?: string[];
37
+
38
+ /**
39
+ * Evaluation-time SHA-256 fingerprints for entries in {@link hostInputs}.
40
+ *
41
+ * Use a lowercase 64-digit digest for a file observed during descriptor
42
+ * evaluation and `null` for a missing candidate. Ttsc's generated resolution
43
+ * loaders also digest the stable kind marker for an existing directory
44
+ * candidate, so replacing that directory with a file invalidates the
45
+ * generation. The map is optional: ttsc still watches unhashed inputs, but
46
+ * persistent adapters conservatively decline narrow generation reuse because
47
+ * a later host snapshot cannot prove which state produced the descriptor.
48
+ */
49
+ hostInputHashes?: Record<string, string | null>;
50
+
51
+ /**
52
+ * Evaluation-time physical paths for entries in {@link hostInputs}.
53
+ *
54
+ * Use the canonical path returned by `fs.realpathSync.native`, or `null` when
55
+ * the input was missing. Persistent adapters pair this with
56
+ * {@link hostInputHashes} so retargeting a symlink or junction cannot attach
57
+ * output evaluated from one target to equal bytes at another target.
58
+ */
59
+ hostInputRealpaths?: Record<string, string | null>;
60
+
25
61
  /**
26
62
  * Go package directory, or a `go.mod` file, that ttsc lazily builds.
27
63
  *
@@ -29,7 +29,6 @@
29
29
  "ESCAPE|checker|TupleType",
30
30
  "ESCAPE|checker|TypeFormatFlags",
31
31
  "ESCAPE|checker|TypeId",
32
- "ESCAPE|checker|TypeMapper",
33
32
  "ESCAPE|checker|TypeParameter",
34
33
  "ESCAPE|checker|TypePredicate",
35
34
  "ESCAPE|checker|TypeReference",
package/utility/host.go CHANGED
@@ -46,9 +46,12 @@ type hostOptions struct {
46
46
  // so cache layers can register every file whose content can influence a
47
47
  // transformed module without per-plugin reporting.
48
48
  type transformResult struct {
49
- Diagnostics []any `json:"diagnostics,omitempty"`
50
- TypeScript map[string]string `json:"typescript"`
51
- Graph *driver.TransformGraph `json:"graph,omitempty"`
49
+ Diagnostics []any `json:"diagnostics,omitempty"`
50
+ Graph *driver.TransformGraph `json:"graph,omitempty"`
51
+ HostInputs []string `json:"hostInputs,omitempty"`
52
+ HostInputHashes map[string]*string `json:"hostInputHashes,omitempty"`
53
+ HostInputRealpaths map[string]*string `json:"hostInputRealpaths,omitempty"`
54
+ TypeScript map[string]string `json:"typescript"`
52
55
  }
53
56
 
54
57
  // RunCheck validates the project and linked plugin configuration without
@@ -150,6 +153,9 @@ func RunTransformWithIO(args []string, stdout, stderr io.Writer) int {
150
153
  text := shimprinter.EmitSourceFile(printer, file)
151
154
  out.TypeScript[apiOutputKey(opts.cwd, file.FileName())] = text
152
155
  }
156
+ out.HostInputs = prog.PluginHostInputs()
157
+ out.HostInputHashes = prog.PluginHostInputHashes()
158
+ out.HostInputRealpaths = prog.PluginHostInputRealpaths()
153
159
  data, _ := json.Marshal(out)
154
160
  fmt.Fprintln(opts.stdout, string(data))
155
161
  return 0
@@ -1,5 +0,0 @@
1
- /**
2
- * Refuse an explicit cache directory whose wholesale removal could delete the
3
- * project or an entire filesystem volume.
4
- */
5
- export declare function assertSafeExplicitCacheDirectory(projectRoot: string, cacheDirectory: string): void;
@@ -1,26 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.assertSafeExplicitCacheDirectory = assertSafeExplicitCacheDirectory;
7
- const node_path_1 = __importDefault(require("node:path"));
8
- /**
9
- * Refuse an explicit cache directory whose wholesale removal could delete the
10
- * project or an entire filesystem volume.
11
- */
12
- function assertSafeExplicitCacheDirectory(projectRoot, cacheDirectory) {
13
- const project = node_path_1.default.resolve(projectRoot);
14
- const cache = node_path_1.default.resolve(cacheDirectory);
15
- if (cache === node_path_1.default.parse(cache).root) {
16
- throw new Error(`ttsc: refusing to clean cache directory ${JSON.stringify(cache)} because filesystem roots are never valid cache directories`);
17
- }
18
- const relative = node_path_1.default.relative(cache, project);
19
- if (relative === "" ||
20
- (relative !== ".." &&
21
- !relative.startsWith(`..${node_path_1.default.sep}`) &&
22
- !node_path_1.default.isAbsolute(relative))) {
23
- throw new Error(`ttsc: refusing to clean cache directory ${JSON.stringify(cache)} because it equals or contains project root ${JSON.stringify(project)}; choose a dedicated cache directory`);
24
- }
25
- }
26
- //# sourceMappingURL=assertSafeExplicitCacheDirectory.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"assertSafeExplicitCacheDirectory.js","sourceRoot":"","sources":["../../src/internal/assertSafeExplicitCacheDirectory.ts"],"names":[],"mappings":";;;;;;AAAA,0DAA6B;AAE7B;;;GAGG;AACH,0CACE,WAAmB,EACnB,cAAsB;IAEtB,MAAM,OAAO,GAAG,mBAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,mBAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IAC3C,IAAI,KAAK,KAAK,mBAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CACb,2CAA2C,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,6DAA6D,CAC9H,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,mBAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC/C,IACE,QAAQ,KAAK,EAAE;QACf,CAAC,QAAQ,KAAK,IAAI;YAChB,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,mBAAI,CAAC,GAAG,EAAE,CAAC;YACrC,CAAC,mBAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,EAC7B,CAAC;QACD,MAAM,IAAI,KAAK,CACb,2CAA2C,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,+CAA+C,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,sCAAsC,CAC7K,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -1,29 +0,0 @@
1
- import path from "node:path";
2
-
3
- /**
4
- * Refuse an explicit cache directory whose wholesale removal could delete the
5
- * project or an entire filesystem volume.
6
- */
7
- export function assertSafeExplicitCacheDirectory(
8
- projectRoot: string,
9
- cacheDirectory: string,
10
- ): void {
11
- const project = path.resolve(projectRoot);
12
- const cache = path.resolve(cacheDirectory);
13
- if (cache === path.parse(cache).root) {
14
- throw new Error(
15
- `ttsc: refusing to clean cache directory ${JSON.stringify(cache)} because filesystem roots are never valid cache directories`,
16
- );
17
- }
18
- const relative = path.relative(cache, project);
19
- if (
20
- relative === "" ||
21
- (relative !== ".." &&
22
- !relative.startsWith(`..${path.sep}`) &&
23
- !path.isAbsolute(relative))
24
- ) {
25
- throw new Error(
26
- `ttsc: refusing to clean cache directory ${JSON.stringify(cache)} because it equals or contains project root ${JSON.stringify(project)}; choose a dedicated cache directory`,
27
- );
28
- }
29
- }