ttsc 0.31.4 → 0.32.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 (140) hide show
  1. package/cmd/ttsc/compiler_argument_cwd_test.go +38 -38
  2. package/cmd/ttscserver/main.go +2 -12
  3. package/cmd/ttscserver/resolve_launch_uses_native_flag_authority_test.go +7 -7
  4. package/driver/lsp.go +4 -43
  5. package/driver/rewrite.go +1 -1
  6. package/internal/e2etrace/completion_hints.go +3 -3
  7. package/internal/e2etrace/completion_hints_test.go +26 -12
  8. package/internal/graph/build.go +5 -6
  9. package/internal/graph/graph.go +3 -3
  10. package/internal/graph/line_model.go +2 -35
  11. package/internal/lspserver/lsp_clean_didopen_refreshes_compiler_state_test.go +13 -36
  12. package/internal/lspserver/lsp_hints_refresh_ignores_a_superseded_generation_test.go +9 -3
  13. package/internal/lspserver/lsp_plugin.go +19 -0
  14. package/internal/lspserver/lsp_proxy.go +9 -129
  15. package/internal/lspserver/lsp_server.go +0 -8
  16. package/internal/lspserver/lsp_watched_file_changes_reach_compiler_caches_test.go +6 -36
  17. package/internal/sourceprocess/windows_target_owns_suspended_admission_test.go +5 -5
  18. package/lib/compiler/internal/build/BuildExecution.js +11 -3
  19. package/lib/compiler/internal/build/BuildExecution.js.map +1 -1
  20. package/lib/compiler/internal/build/TsgoArguments.js.map +1 -1
  21. package/lib/compiler/internal/project/CompilerProjectSelection.d.ts +9 -8
  22. package/lib/compiler/internal/project/CompilerProjectSelection.js +11 -9
  23. package/lib/compiler/internal/project/CompilerProjectSelection.js.map +1 -1
  24. package/lib/compiler/internal/project/resolveOwningProjectConfig.d.ts +20 -8
  25. package/lib/compiler/internal/project/resolveOwningProjectConfig.js +21 -12
  26. package/lib/compiler/internal/project/resolveOwningProjectConfig.js.map +1 -1
  27. package/lib/compiler/internal/runSingleFileEmit.d.ts +5 -4
  28. package/lib/compiler/internal/runSingleFileEmit.js +5 -4
  29. package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
  30. package/lib/flags/ParseOptions.d.ts +2 -2
  31. package/lib/internal/E2ETrace.d.ts +1 -0
  32. package/lib/internal/E2ETrace.js.map +1 -1
  33. package/lib/internal/OwnedNativeProcess.d.ts +2 -2
  34. package/lib/internal/OwnedNativeProcess.js +2 -2
  35. package/lib/internal/SourceNativeRetirement.d.ts +8 -7
  36. package/lib/internal/SourceNativeRetirement.js +19 -10
  37. package/lib/internal/SourceNativeRetirement.js.map +1 -1
  38. package/lib/internal/TtsxNodeOptions.d.ts +79 -0
  39. package/lib/internal/TtsxNodeOptions.js +121 -0
  40. package/lib/internal/TtsxNodeOptions.js.map +1 -0
  41. package/lib/internal/javascriptRuntimeCapabilities.js +4 -1
  42. package/lib/internal/javascriptRuntimeCapabilities.js.map +1 -1
  43. package/lib/internal/parseWindowsDirectoryCaseSensitivity.d.ts +5 -5
  44. package/lib/internal/parseWindowsDirectoryCaseSensitivity.js +5 -5
  45. package/lib/internal/pathIdentity/createCaseSensitivityObservations.d.ts +35 -0
  46. package/lib/internal/pathIdentity/createCaseSensitivityObservations.js +209 -0
  47. package/lib/internal/pathIdentity/createCaseSensitivityObservations.js.map +1 -0
  48. package/lib/internal/pathIdentity/createFilesystemPathIdentityContext.js +2 -143
  49. package/lib/internal/pathIdentity/createFilesystemPathIdentityContext.js.map +1 -1
  50. package/lib/internal/probeLocalProcess.d.ts +5 -1
  51. package/lib/internal/probeLocalProcess.js +9 -7
  52. package/lib/internal/probeLocalProcess.js.map +1 -1
  53. package/lib/internal/projectInputPathIdentity.d.ts +1 -0
  54. package/lib/internal/projectInputPathIdentity.js +1 -0
  55. package/lib/internal/projectInputPathIdentity.js.map +1 -1
  56. package/lib/launcher/internal/parseTtsxCLI.d.ts +5 -4
  57. package/lib/launcher/internal/parseTtsxCLI.js +5 -4
  58. package/lib/launcher/internal/parseTtsxCLI.js.map +1 -1
  59. package/lib/launcher/internal/prepareExecution.js.map +1 -1
  60. package/lib/launcher/internal/resolveSingleFileOutput.d.ts +8 -9
  61. package/lib/launcher/internal/resolveSingleFileOutput.js +8 -9
  62. package/lib/launcher/internal/resolveSingleFileOutput.js.map +1 -1
  63. package/lib/launcher/internal/runTtsc.js +5 -5
  64. package/lib/launcher/internal/runTtsx.js +5 -2
  65. package/lib/launcher/internal/runTtsx.js.map +1 -1
  66. package/lib/launcher/internal/runtime/ProcessOwnedDirectory.d.ts +2 -0
  67. package/lib/launcher/internal/runtime/ProcessOwnedDirectory.js +2 -1
  68. package/lib/launcher/internal/runtime/ProcessOwnedDirectory.js.map +1 -1
  69. package/lib/launcher/internal/runtime/RuntimeEntrySources.d.ts +40 -0
  70. package/lib/launcher/internal/runtime/RuntimeEntrySources.js +57 -0
  71. package/lib/launcher/internal/runtime/RuntimeEntrySources.js.map +1 -0
  72. package/lib/launcher/internal/runtime/RuntimeProjectOwnership.d.ts +5 -4
  73. package/lib/launcher/internal/runtime/RuntimeProjectOwnership.js +8 -6
  74. package/lib/launcher/internal/runtime/RuntimeProjectOwnership.js.map +1 -1
  75. package/lib/launcher/internal/runtime/commonJsExportNames.d.ts +2 -1
  76. package/lib/launcher/internal/runtime/commonJsExportNames.js +2 -1
  77. package/lib/launcher/internal/runtime/commonJsExportNames.js.map +1 -1
  78. package/lib/launcher/internal/runtime/installRuntimeHooks.js +35 -9
  79. package/lib/launcher/internal/runtime/installRuntimeHooks.js.map +1 -1
  80. package/lib/launcher/internal/runtime/isLocalProcessGone.d.ts +1 -1
  81. package/lib/launcher/internal/runtime/isLocalProcessGone.js +4 -4
  82. package/lib/launcher/internal/runtime/isLocalProcessGone.js.map +1 -1
  83. package/lib/launcher/internal/runtime/resolveRuntimeCleanTargets.js +3 -1
  84. package/lib/launcher/internal/runtime/resolveRuntimeCleanTargets.js.map +1 -1
  85. package/lib/launcher/internal/watch/FseventsStreams.d.ts +2 -0
  86. package/lib/launcher/internal/watch/FseventsStreams.js +19 -0
  87. package/lib/launcher/internal/watch/FseventsStreams.js.map +1 -1
  88. package/lib/launcher/internal/watch/WatchTopology.d.ts +74 -12
  89. package/lib/launcher/internal/watch/WatchTopology.js +301 -92
  90. package/lib/launcher/internal/watch/WatchTopology.js.map +1 -1
  91. package/lib/launcher/internal/watch/projectInputReloadEventShouldNotify.d.ts +4 -1
  92. package/lib/launcher/internal/watch/projectInputReloadEventShouldNotify.js +3 -2
  93. package/lib/launcher/internal/watch/projectInputReloadEventShouldNotify.js.map +1 -1
  94. package/lib/plugin/internal/load/loadProjectPlugins.js +17 -9
  95. package/lib/plugin/internal/load/loadProjectPlugins.js.map +1 -1
  96. package/lib/plugin/internal/load/resolveNativeSource.js +2 -3
  97. package/lib/plugin/internal/load/resolveNativeSource.js.map +1 -1
  98. package/lib/plugin/internal/source/pluginModuleReplaceDirectories.d.ts +4 -1
  99. package/lib/plugin/internal/source/pluginModuleReplaceDirectories.js +9 -2
  100. package/lib/plugin/internal/source/pluginModuleReplaceDirectories.js.map +1 -1
  101. package/lib/structures/internal/TtscCommonOptions.d.ts +2 -2
  102. package/package.json +9 -9
  103. package/src/compiler/internal/build/BuildExecution.ts +15 -6
  104. package/src/compiler/internal/build/TsgoArguments.ts +4 -1
  105. package/src/compiler/internal/project/CompilerProjectSelection.ts +14 -14
  106. package/src/compiler/internal/project/resolveOwningProjectConfig.ts +29 -14
  107. package/src/compiler/internal/runSingleFileEmit.ts +11 -7
  108. package/src/flags/ParseOptions.ts +2 -2
  109. package/src/internal/E2ETrace.ts +5 -1
  110. package/src/internal/OwnedNativeProcess.ts +2 -2
  111. package/src/internal/SourceNativeRetirement.ts +42 -19
  112. package/src/internal/TtsxNodeOptions.ts +124 -0
  113. package/src/internal/javascriptRuntimeCapabilities.ts +6 -1
  114. package/src/internal/parseWindowsDirectoryCaseSensitivity.ts +5 -5
  115. package/src/internal/pathIdentity/createCaseSensitivityObservations.ts +242 -0
  116. package/src/internal/pathIdentity/createFilesystemPathIdentityContext.ts +2 -169
  117. package/src/internal/probeLocalProcess.ts +13 -8
  118. package/src/internal/projectInputPathIdentity.ts +1 -0
  119. package/src/launcher/internal/parseTtsxCLI.ts +5 -4
  120. package/src/launcher/internal/prepareExecution.ts +4 -1
  121. package/src/launcher/internal/resolveSingleFileOutput.ts +8 -9
  122. package/src/launcher/internal/runTtsc.ts +5 -5
  123. package/src/launcher/internal/runTtsx.ts +17 -8
  124. package/src/launcher/internal/runtime/ProcessOwnedDirectory.ts +5 -1
  125. package/src/launcher/internal/runtime/RuntimeEntrySources.ts +57 -0
  126. package/src/launcher/internal/runtime/RuntimeProjectOwnership.ts +23 -10
  127. package/src/launcher/internal/runtime/commonJsExportNames.ts +11 -4
  128. package/src/launcher/internal/runtime/installRuntimeHooks.ts +55 -13
  129. package/src/launcher/internal/runtime/isLocalProcessGone.ts +5 -3
  130. package/src/launcher/internal/runtime/resolveRuntimeCleanTargets.ts +17 -5
  131. package/src/launcher/internal/watch/FseventsStreams.ts +22 -0
  132. package/src/launcher/internal/watch/WatchTopology.ts +387 -99
  133. package/src/launcher/internal/watch/projectInputReloadEventShouldNotify.ts +14 -9
  134. package/src/plugin/internal/load/loadProjectPlugins.ts +17 -3
  135. package/src/plugin/internal/load/resolveNativeSource.ts +10 -4
  136. package/src/plugin/internal/source/pluginModuleReplaceDirectories.ts +10 -1
  137. package/src/structures/internal/TtscCommonOptions.ts +2 -2
  138. package/internal/graphsymbols/position_helpers_follow_ecma_line_terminators_test.go +0 -78
  139. package/internal/graphsymbols/provider.go +0 -650
  140. package/internal/lspserver/lsp_symbols.go +0 -212
@@ -34,14 +34,15 @@ import type { OwningModuleOptions } from "./OwningModuleOptions";
34
34
  import { PluginDescriptorInputObservation } from "./PluginDescriptorInputObservation";
35
35
  import type { ResolveResult } from "./ResolveResult";
36
36
  import { RuntimeEmitProvenance } from "./RuntimeEmitProvenance";
37
+ import { RuntimeEntrySources } from "./RuntimeEntrySources";
37
38
  import { RuntimeFilesystem } from "./RuntimeFilesystem";
38
39
  import type { RuntimeHookOptions } from "./RuntimeHookOptions";
39
40
  import { RuntimeIsolatedEmit } from "./RuntimeIsolatedEmit";
40
41
  import { RuntimeLoaderCapabilities } from "./RuntimeLoaderCapabilities";
41
42
  import type { RuntimeManifest } from "./RuntimeManifest";
42
43
  import { RuntimeManifestRegistry } from "./RuntimeManifestRegistry";
43
- import { RuntimeProjectOwnership } from "./RuntimeProjectOwnership";
44
44
  import { RuntimeModuleFormat } from "./RuntimeModuleFormat";
45
+ import { RuntimeProjectOwnership } from "./RuntimeProjectOwnership";
45
46
  import { checkNodeRuntimeSupport } from "./checkNodeRuntimeSupport";
46
47
  import { commonJsExportNames } from "./commonJsExportNames";
47
48
  import { commonJsImportFacade } from "./commonJsImportFacade";
@@ -390,7 +391,9 @@ function observePluginDescriptorResolutionCandidates(
390
391
  appendPluginDescriptorInputs(
391
392
  observation
392
393
  .commit(
393
- selectedURL === undefined ? undefined : runtimeFilePath(selectedURL),
394
+ selectedURL === undefined
395
+ ? undefined
396
+ : runtimeFilePath(selectedURL),
394
397
  )
395
398
  .map((record) => `${JSON.stringify({ parent, ...record })}\n`),
396
399
  );
@@ -1003,13 +1006,17 @@ function servesCommonJsFromSource(url: string): boolean {
1003
1006
  }
1004
1007
 
1005
1008
  /** Scan both facade lanes from source paths using their actual require policy. */
1006
- function runtimeCommonJsExportNames(filename: string, source: string): string[] {
1009
+ function runtimeCommonJsExportNames(
1010
+ filename: string,
1011
+ source: string,
1012
+ ): string[] {
1007
1013
  return commonJsExportNames(
1008
1014
  source,
1009
1015
  filename,
1010
- (target) => isTypeScriptSource(target)
1011
- ? emitCommonJsForNameScan(target)
1012
- : readFileOrNull(target),
1016
+ (target) =>
1017
+ isTypeScriptSource(target)
1018
+ ? emitCommonJsForNameScan(target)
1019
+ : readFileOrNull(target),
1013
1020
  (parent, specifier) => {
1014
1021
  const native = createRequire(parent).resolve;
1015
1022
  return resolveCommonJsRequest(native, specifier, undefined, parent);
@@ -1227,20 +1234,20 @@ function resolveServedSource(
1227
1234
  prepareAsEntry: boolean = false,
1228
1235
  ): ServedSource {
1229
1236
  const real = realPath(filename);
1230
- let served = serveEntryEmit(real);
1237
+ let served = serveInlinedEntryEmit(real, prepareAsEntry);
1231
1238
  if (served !== null) {
1232
- return withInlineSourceMap(served);
1239
+ return served;
1233
1240
  }
1234
1241
  // Only the public preload can prepare a newly discovered root; direct ttsx
1235
1242
  // prepared its one entry before the child started.
1236
1243
  const prepareEntry = prepareAsEntry ? prepareRuntimeEntry : undefined;
1237
1244
  if (prepareEntry !== undefined) {
1238
1245
  RuntimeManifestRegistry.registerManifest(prepareEntry(real));
1239
- served = serveEntryEmit(real);
1246
+ served = serveInlinedEntryEmit(real, true);
1240
1247
  if (served === null) {
1241
1248
  throw new Error(`ttsx: prepared entry emit not found for ${filename}`);
1242
1249
  }
1243
- return withInlineSourceMap(served);
1250
+ return served;
1244
1251
  }
1245
1252
  const built = serveProjectEmit(real);
1246
1253
  if (built !== null) {
@@ -1723,10 +1730,36 @@ class RuntimeEmitOwnershipError extends Error {}
1723
1730
  * next lane and run something else.
1724
1731
  */
1725
1732
  function serveEntryEmit(real: string): ServedSource | null {
1733
+ const owner = RuntimeManifestRegistry.findEntryEmit(real);
1734
+ return owner === null ? null : entryEmitSource(owner, real);
1735
+ }
1736
+
1737
+ /**
1738
+ * {@link serveEntryEmit} with the emit's source map inlined, as a module load
1739
+ * serves it. A checked entry build's emit is immutable for the run, so an entry
1740
+ * load, which Node 22.15 repeats for the process entry, reads and source-maps
1741
+ * each emitted file once (`RuntimeEntrySources`, samchon/ttsc#1749). Other
1742
+ * modules are not remembered: Node keeps each loaded module, and holding every
1743
+ * served text beside it would retain the whole program's emit.
1744
+ */
1745
+ function serveInlinedEntryEmit(
1746
+ real: string,
1747
+ entry: boolean,
1748
+ ): ServedSource | null {
1726
1749
  const owner = RuntimeManifestRegistry.findEntryEmit(real);
1727
1750
  if (owner === null) {
1728
1751
  return null;
1729
1752
  }
1753
+ const prepare = () => withInlineSourceMap(entryEmitSource(owner, real));
1754
+ return entry
1755
+ ? RuntimeEntrySources.serve(owner.manifest, owner.emittedFile, prepare)
1756
+ : prepare();
1757
+ }
1758
+
1759
+ function entryEmitSource(
1760
+ owner: NonNullable<ReturnType<typeof RuntimeManifestRegistry.findEntryEmit>>,
1761
+ real: string,
1762
+ ): ServedSource {
1730
1763
  return {
1731
1764
  emittedFile: owner.emittedFile,
1732
1765
  moduleOptions: owner.manifest.moduleOptions ?? {},
@@ -2339,16 +2372,25 @@ function owningTsconfig(real: string): string | null {
2339
2372
  recordPluginDescriptorProjectInputs,
2340
2373
  );
2341
2374
  if (nearest === null) return null;
2342
- // Config spelling and target identity do not prove that inherited options,
2343
- // reference roots or directory membership are unchanged. The resolver owns
2344
- // lookup-scoped reuse; a later import must ask it for a current answer.
2375
+ // The project this selects is built once per process (`ensureProjectBuilt`),
2376
+ // so the reference roots that select it are kept for the process as well;
2377
+ // re-expanding them for every module cost a compiler run per referenced
2378
+ // project (samchon/ttsc#1747). A file created after an expansion is still
2379
+ // expanded for afresh.
2345
2380
  return resolveOwningProjectConfig({
2381
+ expansions: ownerExpansions,
2346
2382
  file: real,
2347
2383
  onConfig: (config) => recordPluginDescriptorProjectInputs([config]),
2348
2384
  tsconfig: nearest,
2349
2385
  });
2350
2386
  }
2351
2387
 
2388
+ /** Reference roots `owningTsconfig` expanded in this process, by config. */
2389
+ const ownerExpansions = new Map<
2390
+ string,
2391
+ { files: readonly string[]; takenAt: number }
2392
+ >();
2393
+
2352
2394
  function readFileOrNull(file: string | null): string | null {
2353
2395
  if (file === null) {
2354
2396
  return null;
@@ -40,14 +40,16 @@ export function isLocalProcessGone(
40
40
  observe?: (
41
41
  result: "remote" | "present" | "absent" | "unknown",
42
42
  errorCode?: string,
43
+ state?: string,
43
44
  ) => void,
44
45
  ): boolean {
45
46
  const report = (
46
47
  result: "remote" | "present" | "absent" | "unknown",
47
48
  errorCode?: string,
49
+ state?: string,
48
50
  ): void => {
49
51
  try {
50
- observe?.(result, errorCode);
52
+ observe?.(result, errorCode, state);
51
53
  } catch {
52
54
  // Diagnostics own no policy.
53
55
  }
@@ -56,7 +58,7 @@ export function isLocalProcessGone(
56
58
  report("remote");
57
59
  return false;
58
60
  }
59
- const { result, errorCode } = probeLocalProcess(owner.pid);
60
- report(result, errorCode);
61
+ const { result, errorCode, state } = probeLocalProcess(owner.pid);
62
+ report(result, errorCode, state);
61
63
  return result === "absent";
62
64
  }
@@ -67,13 +67,22 @@ export function resolveRuntimeCleanTargets(cacheRoot: string): {
67
67
  const removable: string[] = [];
68
68
  for (const entry of entries) {
69
69
  const directory = path.join(physicalRuns, entry);
70
- const observe = E2ETrace.runtimeCleanup(directory, runtime, "runtime-clean-selection");
70
+ const observe = E2ETrace.runtimeCleanup(
71
+ directory,
72
+ runtime,
73
+ "runtime-clean-selection",
74
+ );
71
75
  observe?.("selection-started");
72
76
  let ownership: ReturnType<typeof ProcessOwnedDirectory.ownership>;
73
77
  try {
74
- ownership = ProcessOwnedDirectory.ownership(directory, false,
75
- observe === undefined ? undefined : (observation) =>
76
- observe("owner-observation", undefined, undefined, observation));
78
+ ownership = ProcessOwnedDirectory.ownership(
79
+ directory,
80
+ false,
81
+ observe === undefined
82
+ ? undefined
83
+ : (observation) =>
84
+ observe("owner-observation", undefined, undefined, observation),
85
+ );
77
86
  } catch (cause) {
78
87
  observe?.("selection-failed", undefined, cause);
79
88
  throw cause;
@@ -81,7 +90,10 @@ export function resolveRuntimeCleanTargets(cacheRoot: string): {
81
90
  observe?.("ownership", ownership);
82
91
  if (ownership !== "abandoned") kept.push(directory);
83
92
  else removable.push(directory);
84
- observe?.(ownership === "abandoned" ? "removal-selected" : "retention-selected", ownership);
93
+ observe?.(
94
+ ownership === "abandoned" ? "removal-selected" : "retention-selected",
95
+ ownership,
96
+ );
85
97
  }
86
98
  return {
87
99
  kept,
@@ -1,4 +1,5 @@
1
1
  import { EventEmitter } from "node:events";
2
+ import fs from "node:fs";
2
3
  import path from "node:path";
3
4
 
4
5
  import type { DirectoryWatcher } from "./DirectoryWatcher";
@@ -116,6 +117,7 @@ export class FseventsStreams {
116
117
  const displaced = [...(this.descendants.get(directory) ?? [])];
117
118
  const stream: Stream = {
118
119
  active: true,
120
+ openedAt: Date.now(),
119
121
  root: directory,
120
122
  stop: () => undefined,
121
123
  watches: new Map(),
@@ -209,6 +211,9 @@ type Watch = {
209
211
 
210
212
  type Stream = {
211
213
  active: boolean;
214
+
215
+ /** When the stream opened; nothing born before it was created in it. */
216
+ openedAt: number;
212
217
  root: string;
213
218
  stop: () => unknown;
214
219
  watches: Map<string, Set<Watch>>;
@@ -218,6 +223,8 @@ type Stream = {
218
223
  const GAP = 0x1 | 0x2 | 0x4 | 0x8 | 0x20 | 0x40 | 0x80;
219
224
  const MODIFIED = 0x400 | 0x1000 | 0x2000 | 0x4000 | 0x8000;
220
225
  const RENAMED = 0x100 | 0x200 | 0x800;
226
+ const CREATED = 0x100;
227
+ const MOVED = 0x200 | 0x800;
221
228
 
222
229
  function addWatch(stream: Stream, watch: Watch): void {
223
230
  const watches = stream.watches.get(watch.directory) ?? new Set<Watch>();
@@ -248,6 +255,21 @@ function deliver(stream: Stream, file: string, flags: number): void {
248
255
  deliverGap(stream);
249
256
  return;
250
257
  }
258
+ // FSEvents keeps ItemCreated on later writes to a path it saw created, so a
259
+ // plain edit of a file older than this stream arrived as a rename. An object
260
+ // born before the stream opened was not created in it; its other flags
261
+ // decide. A removal or a rename keeps the event structural.
262
+ if (
263
+ (flags & CREATED) !== 0 &&
264
+ (flags & MOVED) === 0 &&
265
+ (flags & MODIFIED) !== 0
266
+ ) {
267
+ try {
268
+ if (fs.lstatSync(target).birthtimeMs < stream.openedAt) flags &= ~CREATED;
269
+ } catch {
270
+ // A path gone by now keeps its creation flag.
271
+ }
272
+ }
251
273
  const event =
252
274
  (flags & MODIFIED) !== 0 && (flags & RENAMED) === 0 ? "change" : "rename";
253
275
  const deliveries: Array<{ name: string; watch: Watch }> = [];