ttsc 0.22.0 → 0.24.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 (91) hide show
  1. package/cmd/ttscgraph/serve.go +264 -48
  2. package/cmd/ttscgraph/serve_early_error_encode_failure_is_observable_test.go +40 -0
  3. package/cmd/ttscgraph/serve_graph_snapshot_version_matches_typescript_client_test.go +32 -0
  4. package/cmd/ttscgraph/serve_phase_trace_accounts_for_load_failure_test.go +45 -0
  5. package/cmd/ttscgraph/serve_phase_trace_is_opt_in_and_payload_free_test.go +52 -0
  6. package/cmd/ttscgraph/serve_protocol_negotiates_incremental_shards_test.go +44 -0
  7. package/cmd/ttscgraph/serve_session_reloads_commonjs_package_entry_for_esm_test.go +2 -2
  8. package/cmd/ttscgraph/serve_session_reloads_superseding_module_candidates_test.go +46 -20
  9. package/cmd/ttscgraph/serve_session_retries_failed_dump_test.go +9 -9
  10. package/cmd/ttscgraph/serve_shards.go +1390 -0
  11. package/cmd/ttscgraph/serve_shards_abandoned_generation_converges_on_retry_test.go +92 -0
  12. package/cmd/ttscgraph/serve_shards_delete_removed_source_test.go +57 -0
  13. package/cmd/ttscgraph/serve_shards_external_endpoints_test.go +53 -0
  14. package/cmd/ttscgraph/serve_shards_keep_source_distributed_dependencies_at_the_boundary_test.go +108 -0
  15. package/cmd/ttscgraph/serve_shards_match_full_dump_oracle_test.go +88 -0
  16. package/cmd/ttscgraph/serve_shards_merge_pending_and_new_edits_test.go +50 -0
  17. package/cmd/ttscgraph/serve_shards_prune_unreferenced_external_endpoints_test.go +65 -0
  18. package/cmd/ttscgraph/serve_shards_publish_created_source_test.go +92 -0
  19. package/cmd/ttscgraph/serve_shards_rebuild_declaration_edit_test.go +43 -0
  20. package/cmd/ttscgraph/serve_shards_refresh_cross_file_implementation_test.go +63 -0
  21. package/cmd/ttscgraph/serve_shards_refresh_dependent_diagnostics_test.go +80 -0
  22. package/cmd/ttscgraph/serve_shards_rename_moves_source_identity_test.go +95 -0
  23. package/cmd/ttscgraph/serve_shards_retry_preserves_committed_generation_test.go +48 -0
  24. package/cmd/ttscgraph/serve_shards_reuse_unaffected_sources_test.go +121 -0
  25. package/driver/declaration_shape.go +85 -0
  26. package/driver/program.go +39 -10
  27. package/go.mod +1 -1
  28. package/internal/graph/build.go +62 -10
  29. package/internal/graph/build_files_reuses_committed_cross_file_endpoints_test.go +87 -0
  30. package/internal/graph/build_keeps_source_distributed_dependencies_at_the_external_boundary_test.go +74 -0
  31. package/internal/graph/dump.go +84 -43
  32. package/internal/graph/dump_path_mapper_caches_alias_resolution_test.go +29 -0
  33. package/internal/graph/dump_paths.go +134 -11
  34. package/internal/graph/dump_paths_canonicalize_windows_short_root_test.go +39 -0
  35. package/internal/graph/dump_rejects_provenance_only_path_errors_test.go +32 -0
  36. package/internal/graph/dump_serializes_the_full_graph_test.go +2 -2
  37. package/internal/graph/dump_symlink_project_publishes_matching_base_test.go +82 -0
  38. package/internal/graph/edges.go +58 -16
  39. package/internal/graph/exports.go +9 -2
  40. package/internal/graph/graph.go +47 -7
  41. package/internal/graph/graph_kind_contracts_match_their_producers_test.go +121 -0
  42. package/internal/graph/node_modifiers_emit_union_strings_test.go +1 -1
  43. package/internal/graph/provenance.go +11 -1
  44. package/internal/graph/resolve.go +1 -4
  45. package/internal/graph/source.go +23 -0
  46. package/internal/graph/wire_node_ids_share_alias_resolution_test.go +29 -0
  47. package/internal/lspserver/lsp_launcher_reload_directory_fingerprint_parity_windows_test.go +94 -0
  48. package/internal/lspserver/lsp_project_input_glob_path_other.go +16 -0
  49. package/internal/lspserver/lsp_project_input_glob_path_windows.go +36 -0
  50. package/internal/lspserver/lsp_project_input_path_key_other.go +17 -0
  51. package/internal/lspserver/lsp_project_input_path_key_windows.go +228 -0
  52. package/internal/lspserver/lsp_project_input_path_key_windows_test.go +460 -0
  53. package/internal/lspserver/lsp_project_inputs.go +117 -49
  54. package/internal/lspserver/lsp_reload_directories_separate_glob_territory_test.go +181 -0
  55. package/lib/flags/schema.js +1 -1
  56. package/lib/flags/schema.js.map +1 -1
  57. package/lib/internal/projectInputPathIdentity.d.ts +13 -5
  58. package/lib/internal/projectInputPathIdentity.js +95 -41
  59. package/lib/internal/projectInputPathIdentity.js.map +1 -1
  60. package/lib/internal/windowsDirectoryCaseSensitivity.d.ts +10 -0
  61. package/lib/internal/windowsDirectoryCaseSensitivity.js +34 -0
  62. package/lib/internal/windowsDirectoryCaseSensitivity.js.map +1 -0
  63. package/lib/launcher/internal/runTtsc.js +5 -0
  64. package/lib/launcher/internal/runTtsc.js.map +1 -1
  65. package/lib/launcher/internal/runTtscserver.js +59 -8
  66. package/lib/launcher/internal/runTtscserver.js.map +1 -1
  67. package/lib/launcher/internal/runTtsx.js +61 -7
  68. package/lib/launcher/internal/runTtsx.js.map +1 -1
  69. package/lib/launcher/internal/runtimeHooks.d.ts +6 -5
  70. package/lib/launcher/internal/runtimeHooks.js +7 -15
  71. package/lib/launcher/internal/runtimeHooks.js.map +1 -1
  72. package/lib/launcher/internal/watchTopology.d.ts +82 -8
  73. package/lib/launcher/internal/watchTopology.js +535 -187
  74. package/lib/launcher/internal/watchTopology.js.map +1 -1
  75. package/lib/plugin/internal/descriptorProcessFailure.d.ts +32 -0
  76. package/lib/plugin/internal/descriptorProcessFailure.js +73 -0
  77. package/lib/plugin/internal/descriptorProcessFailure.js.map +1 -0
  78. package/lib/plugin/internal/loadProjectPlugins.js +29 -8
  79. package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
  80. package/package.json +12 -8
  81. package/src/flags/schema.ts +2 -1
  82. package/src/internal/projectInputPathIdentity.ts +150 -46
  83. package/src/internal/windowsDirectoryCaseSensitivity.ts +33 -0
  84. package/src/launcher/internal/runTtsc.ts +7 -0
  85. package/src/launcher/internal/runTtscserver.ts +81 -11
  86. package/src/launcher/internal/runTtsx.ts +87 -10
  87. package/src/launcher/internal/runtimeHooks.ts +16 -16
  88. package/src/launcher/internal/watchTopology.ts +679 -208
  89. package/src/plugin/internal/descriptorProcessFailure.ts +100 -0
  90. package/src/plugin/internal/loadProjectPlugins.ts +41 -8
  91. package/tools/shim_audit/baseline.json +0 -9
@@ -0,0 +1,100 @@
1
+ export const PLUGIN_DESCRIPTOR_MAX_BUFFER_BYTES = 16 * 1024 * 1024;
2
+ export const PLUGIN_DESCRIPTOR_TIMEOUT_MS = 60_000;
3
+ export const PLUGIN_DESCRIPTOR_TEARDOWN_GRACE_MS = 5_000;
4
+ export const PLUGIN_DESCRIPTOR_STATUS_FD = 3;
5
+ export const PLUGIN_DESCRIPTOR_PROCESS_OPTIONS = Object.freeze({
6
+ killSignal: "SIGKILL" as const,
7
+ maxBuffer: PLUGIN_DESCRIPTOR_MAX_BUFFER_BYTES,
8
+ timeout: PLUGIN_DESCRIPTOR_TIMEOUT_MS + PLUGIN_DESCRIPTOR_TEARDOWN_GRACE_MS,
9
+ });
10
+
11
+ interface DescriptorProcessResult {
12
+ error?: Error;
13
+ output?: readonly (string | null)[] | null;
14
+ signal: NodeJS.Signals | null;
15
+ status: number | null;
16
+ stderr: string | null | undefined;
17
+ stdout: string | null | undefined;
18
+ }
19
+
20
+ /**
21
+ * Classify the ways the isolated TypeScript descriptor evaluator can stop.
22
+ *
23
+ * Node reports both timeout and max-buffer termination with the configured
24
+ * signal, so the process error code must take precedence over the signal. The
25
+ * evaluator uses `SIGKILL`: Node's synchronous process API otherwise keeps
26
+ * waiting when a POSIX child handles the default `SIGTERM` without exiting.
27
+ */
28
+ export function pluginDescriptorProcessFailure(
29
+ result: DescriptorProcessResult,
30
+ request: string,
31
+ ): Error | undefined {
32
+ const code = (result.error as NodeJS.ErrnoException | undefined)?.code;
33
+ const nestedCode = result.output?.[PLUGIN_DESCRIPTOR_STATUS_FD]?.trim() ?? "";
34
+ if (code === "ETIMEDOUT" || nestedCode === "ETIMEDOUT") {
35
+ return new Error(
36
+ `ttsc: plugin descriptor "${request}" evaluation through ttsx timed out after ` +
37
+ `${PLUGIN_DESCRIPTOR_TIMEOUT_MS / 1_000} seconds. ` +
38
+ "Descriptor modules and factories must finish their setup within that window.",
39
+ );
40
+ }
41
+ if (code === "ENOBUFS" || nestedCode === "ENOBUFS") {
42
+ return new Error(
43
+ `ttsc: plugin descriptor "${request}" evaluation through ttsx exceeded the ` +
44
+ `${PLUGIN_DESCRIPTOR_MAX_BUFFER_BYTES / (1024 * 1024)} MiB process output limit. ` +
45
+ "Reduce stdout and stderr from the descriptor and its dependencies.",
46
+ );
47
+ }
48
+ if (result.error) {
49
+ return new Error(
50
+ `ttsc: failed to launch ttsx for plugin descriptor "${request}": ${result.error.message}`,
51
+ );
52
+ }
53
+ if (result.signal) {
54
+ return new Error(
55
+ `ttsc: plugin descriptor "${request}" evaluation through ttsx was killed by signal ${result.signal}.`,
56
+ );
57
+ }
58
+ if (result.status !== 0) {
59
+ const reason = descriptorFailureReason(
60
+ hasText(result.stderr) ? result.stderr : result.stdout,
61
+ );
62
+ return new Error(
63
+ `ttsc: plugin descriptor "${request}" evaluation through ttsx failed with exit code ${String(result.status)}` +
64
+ (reason === "" ? "" : "\n" + reason),
65
+ );
66
+ }
67
+ return undefined;
68
+ }
69
+
70
+ /**
71
+ * Pass the semantic deadline and private status pipe through the `ttsx` wrapper
72
+ * to the runtime child that actually executes the descriptor.
73
+ */
74
+ export function pluginDescriptorBoundaryEnvironment(
75
+ now: number = Date.now(),
76
+ ): NodeJS.ProcessEnv {
77
+ return {
78
+ TTSC_TTSX_EVALUATOR_DEADLINE_MS: String(now + PLUGIN_DESCRIPTOR_TIMEOUT_MS),
79
+ TTSC_TTSX_EVALUATOR_MAX_BUFFER_BYTES: String(
80
+ PLUGIN_DESCRIPTOR_MAX_BUFFER_BYTES,
81
+ ),
82
+ TTSC_TTSX_EVALUATOR_STATUS_FD: String(PLUGIN_DESCRIPTOR_STATUS_FD),
83
+ };
84
+ }
85
+
86
+ function hasText(value: string | null | undefined): value is string {
87
+ return value !== null && value !== undefined && value.trim() !== "";
88
+ }
89
+
90
+ function descriptorFailureReason(stderr: string | null | undefined): string {
91
+ const bounded = (stderr ?? "").slice(-PLUGIN_DESCRIPTOR_REASON_MAX_CHARS);
92
+ const lines = bounded
93
+ .split(/\r?\n/)
94
+ .map((line) => line.trimEnd())
95
+ .filter((line) => line.trim() !== "");
96
+ return lines.slice(-PLUGIN_DESCRIPTOR_REASON_LINES).join("\n");
97
+ }
98
+
99
+ const PLUGIN_DESCRIPTOR_REASON_LINES = 5;
100
+ const PLUGIN_DESCRIPTOR_REASON_MAX_CHARS = 8 * 1024;
@@ -15,6 +15,13 @@ import type { TtscPluginStage } from "../../structures/TtscPluginStage";
15
15
  import type { ITtscLoadedNativePlugin } from "../../structures/internal/ITtscLoadedNativePlugin";
16
16
  import type { ITtscParsedProjectConfig } from "../../structures/internal/ITtscParsedProjectConfig";
17
17
  import { buildSourcePlugin } from "./buildSourcePlugin";
18
+ import {
19
+ PLUGIN_DESCRIPTOR_MAX_BUFFER_BYTES,
20
+ PLUGIN_DESCRIPTOR_PROCESS_OPTIONS,
21
+ PLUGIN_DESCRIPTOR_STATUS_FD,
22
+ pluginDescriptorBoundaryEnvironment,
23
+ pluginDescriptorProcessFailure,
24
+ } from "./descriptorProcessFailure";
18
25
 
19
26
  const GO_MOD_SEARCH_MAX_DEPTH = 3;
20
27
 
@@ -766,25 +773,51 @@ function loadDescriptorViaTtsx(
766
773
  TTSC_PLUGIN_DESCRIPTOR_LOAD: "1",
767
774
  TTSC_PLUGIN_DESCRIPTOR_OUT: out,
768
775
  TTSC_PLUGIN_ENTRY: request,
776
+ ...pluginDescriptorBoundaryEnvironment(),
769
777
  },
778
+ ...PLUGIN_DESCRIPTOR_PROCESS_OPTIONS,
779
+ stdio: [
780
+ "ignore",
781
+ "pipe",
782
+ "pipe",
783
+ ...Array.from(
784
+ { length: PLUGIN_DESCRIPTOR_STATUS_FD - 2 },
785
+ () => "pipe" as const,
786
+ ),
787
+ ],
770
788
  windowsHide: true,
771
789
  });
772
- if (result.status !== 0 || !fs.existsSync(out)) {
790
+ const processFailure = pluginDescriptorProcessFailure(result, request);
791
+ if (processFailure) throw processFailure;
792
+ if (!fs.existsSync(out)) {
793
+ throw new Error(
794
+ `ttsc: plugin descriptor "${request}" evaluation through ttsx produced no descriptor output.`,
795
+ );
796
+ }
797
+ const outputSize = fs.statSync(out).size;
798
+ if (outputSize > PLUGIN_DESCRIPTOR_MAX_BUFFER_BYTES) {
799
+ throw new Error(
800
+ `ttsc: plugin descriptor "${request}" produced ${outputSize} bytes of JSON, ` +
801
+ `exceeding the ${PLUGIN_DESCRIPTOR_MAX_BUFFER_BYTES / (1024 * 1024)} MiB descriptor output limit.`,
802
+ );
803
+ }
804
+ const text = fs.readFileSync(out, "utf8");
805
+ try {
806
+ return JSON.parse(text);
807
+ } catch (error) {
773
808
  throw new Error(
774
- [
775
- `ttsc: failed to load plugin descriptor "${request}" through ttsx`,
776
- result.stderr || result.stdout || "",
777
- ]
778
- .filter((line) => line.trim().length !== 0)
779
- .join("\n"),
809
+ `ttsc: plugin descriptor "${request}" produced invalid JSON: ${errorMessage(error)}`,
780
810
  );
781
811
  }
782
- return JSON.parse(fs.readFileSync(out, "utf8"));
783
812
  } finally {
784
813
  fs.rmSync(dir, { force: true, recursive: true });
785
814
  }
786
815
  }
787
816
 
817
+ function errorMessage(error: unknown): string {
818
+ return error instanceof Error ? error.message : String(error);
819
+ }
820
+
788
821
  function withPluginLoaderEnv<T>(run: () => T): T {
789
822
  const previousNode = process.env.TTSC_NODE_BINARY;
790
823
  const previousTtsx = process.env.TTSC_TTSX_BINARY;
@@ -40,7 +40,6 @@
40
40
  "ESCAPE|checker|VerbosityContext",
41
41
  "ESCAPE|core|LimitedSemaphore",
42
42
  "ESCAPE|core|ModuleDetectionKind",
43
- "ESCAPE|core|ModuleResolutionKind",
44
43
  "ESCAPE|core|NewLineKind",
45
44
  "ESCAPE|core|ParsedOptions",
46
45
  "ESCAPE|core|Pattern",
@@ -194,8 +193,6 @@
194
193
  "FUNC|ast|IsBindableStaticAccessExpression",
195
194
  "FUNC|ast|IsBindableStaticElementAccessExpression",
196
195
  "FUNC|ast|IsBindableStaticNameExpression",
197
- "FUNC|ast|IsBindingElement",
198
- "FUNC|ast|IsBindingPattern",
199
196
  "FUNC|ast|IsBitwiseOperator",
200
197
  "FUNC|ast|IsBitwiseOperatorOrHigher",
201
198
  "FUNC|ast|IsBlock",
@@ -239,10 +236,8 @@
239
236
  "FUNC|ast|IsContextualKeyword",
240
237
  "FUNC|ast|IsContinueStatement",
241
238
  "FUNC|ast|IsDebuggerStatement",
242
- "FUNC|ast|IsDeclaration",
243
239
  "FUNC|ast|IsDeclarationBindingElement",
244
240
  "FUNC|ast|IsDeclarationName",
245
- "FUNC|ast|IsDeclarationNameOrImportPropertyName",
246
241
  "FUNC|ast|IsDeclarationNode",
247
242
  "FUNC|ast|IsDeclarationStatement",
248
243
  "FUNC|ast|IsDecorator",
@@ -279,7 +274,6 @@
279
274
  "FUNC|ast|IsExportSpecifier",
280
275
  "FUNC|ast|IsExportsIdentifier",
281
276
  "FUNC|ast|IsExpression",
282
- "FUNC|ast|IsExpressionNode",
283
277
  "FUNC|ast|IsExpressionOfOptionalChainRoot",
284
278
  "FUNC|ast|IsExpressionStatement",
285
279
  "FUNC|ast|IsExpressionWithTypeArguments",
@@ -567,15 +561,12 @@
567
561
  "FUNC|ast|IsThisTypeNode",
568
562
  "FUNC|ast|IsThrowStatement",
569
563
  "FUNC|ast|IsToken",
570
- "FUNC|ast|IsTokenKind",
571
564
  "FUNC|ast|IsTrivia",
572
565
  "FUNC|ast|IsTriviaKind",
573
566
  "FUNC|ast|IsTryStatement",
574
567
  "FUNC|ast|IsTupleTypeNode",
575
568
  "FUNC|ast|IsTypeAliasDeclaration",
576
569
  "FUNC|ast|IsTypeAssertion",
577
- "FUNC|ast|IsTypeDeclaration",
578
- "FUNC|ast|IsTypeDeclarationName",
579
570
  "FUNC|ast|IsTypeElement",
580
571
  "FUNC|ast|IsTypeKeywordToken",
581
572
  "FUNC|ast|IsTypeLiteralNode",