ttsc 0.20.1 → 0.22.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 (95) hide show
  1. package/cmd/ttscserver/main.go +79 -3
  2. package/cmd/ttscserver/run_lsp_uses_native_plugin_manifest_source_test.go +96 -16
  3. package/driver/lsp.go +4 -0
  4. package/internal/lspserver/lsp_document_diagnostics_omits_cached_project_when_current_result_has_none_test.go +48 -0
  5. package/internal/lspserver/lsp_executable_project_input_change_requests_launcher_restart_test.go +98 -0
  6. package/internal/lspserver/lsp_external_watched_change_retains_program_test.go +53 -0
  7. package/internal/lspserver/lsp_hints_refresh_scheduled_by_editor_events_test.go +9 -0
  8. package/internal/lspserver/lsp_native_plugin_source.go +171 -55
  9. package/internal/lspserver/lsp_native_resident.go +110 -9
  10. package/internal/lspserver/lsp_plugin.go +6 -0
  11. package/internal/lspserver/lsp_project_context_transport_identity_test.go +43 -0
  12. package/internal/lspserver/lsp_project_diagnostics.go +235 -0
  13. package/internal/lspserver/lsp_project_diagnostics_capability_is_independent_test.go +67 -0
  14. package/internal/lspserver/lsp_project_diagnostics_program_input_overlap_refreshes_all_producers_test.go +78 -0
  15. package/internal/lspserver/lsp_project_diagnostics_refresh_accumulates_owner_freshness_test.go +65 -0
  16. package/internal/lspserver/lsp_project_diagnostics_refresh_keeps_each_producer_last_good_test.go +90 -0
  17. package/internal/lspserver/lsp_project_diagnostics_refreshes_only_input_owners_test.go +62 -0
  18. package/internal/lspserver/lsp_project_diagnostics_resident_unsupported_falls_back_test.go +123 -0
  19. package/internal/lspserver/lsp_project_diagnostics_resume_preserves_generation_test.go +52 -0
  20. package/internal/lspserver/lsp_project_diagnostics_translates_relative_client_project_test.go +90 -0
  21. package/internal/lspserver/lsp_project_input_ownership_resolves_declared_spellings_test.go +95 -0
  22. package/internal/lspserver/lsp_project_input_registration.go +504 -0
  23. package/internal/lspserver/lsp_project_input_registration_rechecks_selection_baseline_test.go +71 -0
  24. package/internal/lspserver/lsp_project_input_registration_reconciles_rejected_pending_request_test.go +268 -0
  25. package/internal/lspserver/lsp_project_input_registration_shapes_patterns_test.go +94 -0
  26. package/internal/lspserver/lsp_project_input_watchers_anchor_missing_paths_test.go +48 -0
  27. package/internal/lspserver/lsp_project_inputs.go +944 -0
  28. package/internal/lspserver/lsp_project_inputs_match_missing_exact_and_glob_test.go +129 -0
  29. package/internal/lspserver/lsp_project_inputs_reject_invalid_and_foreign_snapshots_test.go +110 -0
  30. package/internal/lspserver/lsp_proxy.go +591 -28
  31. package/internal/lspserver/lsp_reload_directories_compare_immediate_topology_test.go +188 -0
  32. package/internal/lspserver/lsp_reload_file_fingerprint_preserves_raw_symlink_target_test.go +47 -0
  33. package/internal/lspserver/lsp_resident_falls_back_when_serve_unsupported_test.go +1 -1
  34. package/internal/lspserver/lsp_resident_invalidation_broadcasts_program_input_overlap_test.go +60 -0
  35. package/internal/lspserver/lsp_resident_invalidation_targets_project_input_owners_test.go +51 -0
  36. package/internal/lspserver/lsp_same_transport_entries_are_deduplicated_test.go +66 -0
  37. package/lib/compiler/internal/project/readProjectConfig.d.ts +5 -3
  38. package/lib/compiler/internal/project/readProjectConfig.js +46 -14
  39. package/lib/compiler/internal/project/readProjectConfig.js.map +1 -1
  40. package/lib/compiler/internal/residentCheckProcess.d.ts +46 -0
  41. package/lib/compiler/internal/residentCheckProcess.js +227 -0
  42. package/lib/compiler/internal/residentCheckProcess.js.map +1 -0
  43. package/lib/compiler/internal/resolveEmittedJavaScript.d.ts +2 -1
  44. package/lib/compiler/internal/resolveEmittedJavaScript.js +35 -18
  45. package/lib/compiler/internal/resolveEmittedJavaScript.js.map +1 -1
  46. package/lib/compiler/internal/runBuild.d.ts +64 -1
  47. package/lib/compiler/internal/runBuild.js +484 -7
  48. package/lib/compiler/internal/runBuild.js.map +1 -1
  49. package/lib/compiler/internal/runSingleFileEmit.js +1 -0
  50. package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
  51. package/lib/flags/parser.js +13 -17
  52. package/lib/flags/parser.js.map +1 -1
  53. package/lib/flags/schema.d.ts +10 -3
  54. package/lib/flags/schema.js +99 -0
  55. package/lib/flags/schema.js.map +1 -1
  56. package/lib/internal/projectInputPathIdentity.d.ts +23 -0
  57. package/lib/internal/projectInputPathIdentity.js +222 -0
  58. package/lib/internal/projectInputPathIdentity.js.map +1 -0
  59. package/lib/launcher/internal/runTtsc.d.ts +17 -0
  60. package/lib/launcher/internal/runTtsc.js +121 -88
  61. package/lib/launcher/internal/runTtsc.js.map +1 -1
  62. package/lib/launcher/internal/runTtscserver.d.ts +13 -1
  63. package/lib/launcher/internal/runTtscserver.js +415 -45
  64. package/lib/launcher/internal/runTtscserver.js.map +1 -1
  65. package/lib/launcher/internal/singleFileOutput.d.ts +16 -0
  66. package/lib/launcher/internal/singleFileOutput.js +103 -0
  67. package/lib/launcher/internal/singleFileOutput.js.map +1 -0
  68. package/lib/launcher/internal/watchTopology.d.ts +214 -2
  69. package/lib/launcher/internal/watchTopology.js +1560 -41
  70. package/lib/launcher/internal/watchTopology.js.map +1 -1
  71. package/lib/plugin/internal/loadProjectPlugins.d.ts +1 -0
  72. package/lib/plugin/internal/loadProjectPlugins.js +5 -0
  73. package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
  74. package/lib/structures/ITtscPluginCapabilities.d.ts +31 -0
  75. package/lib/structures/internal/ITtscProjectInputSnapshot.d.ts +29 -0
  76. package/lib/structures/internal/ITtscProjectInputSnapshot.js +3 -0
  77. package/lib/structures/internal/ITtscProjectInputSnapshot.js.map +1 -0
  78. package/lib/structures/internal/TtscSingleFileEmitOptions.d.ts +5 -0
  79. package/package.json +8 -8
  80. package/src/compiler/internal/project/readProjectConfig.ts +62 -8
  81. package/src/compiler/internal/residentCheckProcess.ts +279 -0
  82. package/src/compiler/internal/resolveEmittedJavaScript.ts +43 -21
  83. package/src/compiler/internal/runBuild.ts +728 -12
  84. package/src/compiler/internal/runSingleFileEmit.ts +1 -0
  85. package/src/flags/parser.ts +17 -17
  86. package/src/flags/schema.ts +111 -3
  87. package/src/internal/projectInputPathIdentity.ts +273 -0
  88. package/src/launcher/internal/runTtsc.ts +141 -117
  89. package/src/launcher/internal/runTtscserver.ts +561 -54
  90. package/src/launcher/internal/singleFileOutput.ts +133 -0
  91. package/src/launcher/internal/watchTopology.ts +2008 -59
  92. package/src/plugin/internal/loadProjectPlugins.ts +8 -0
  93. package/src/structures/ITtscPluginCapabilities.ts +34 -0
  94. package/src/structures/internal/ITtscProjectInputSnapshot.ts +29 -0
  95. package/src/structures/internal/TtscSingleFileEmitOptions.ts +5 -0
@@ -0,0 +1,129 @@
1
+ package lspserver
2
+
3
+ import (
4
+ "net/url"
5
+ "path/filepath"
6
+ "strings"
7
+ "testing"
8
+ )
9
+
10
+ // TestProjectInputsMatchMissingExactAndGlob verifies URI matching consumes the
11
+ // declaration snapshot rather than the set of files that happened to exist.
12
+ //
13
+ // Exact missing paths and zero-match glob populations must match future
14
+ // create/change/delete notifications. Unrelated files and remote URIs remain
15
+ // outside the filesystem contract.
16
+ //
17
+ // 1. Normalize one missing exact path and two zero-match globs as a producer
18
+ // publishes them, plus executable reload paths, then install that snapshot
19
+ // in a source.
20
+ // 2. Match URI spellings for future files without creating them.
21
+ // 3. Match only exact files, directory identity, or immediate topology
22
+ // entries as executable-selection input scope.
23
+ // 4. Reject an unrelated Markdown file and an HTTPS resource.
24
+ func TestProjectInputsMatchMissingExactAndGlob(t *testing.T) {
25
+ root := t.TempDir()
26
+ publishedPath := func(location string) string {
27
+ return filepath.ToSlash(realProjectInputPath(location))
28
+ }
29
+ snapshot, err := normalizeLSPProjectInputSnapshot(
30
+ LSPProjectInputSnapshot{
31
+ Root: publishedPath(root),
32
+ Files: []string{
33
+ publishedPath(filepath.Join(root, "docs", "missing.md")),
34
+ },
35
+ Globs: []string{
36
+ publishedPath(filepath.Join(root, "api", "**", "*.json")),
37
+ publishedPath(filepath.Join(
38
+ root,
39
+ "api",
40
+ "**",
41
+ "v[12]",
42
+ "{openapi,swagger}.yaml",
43
+ )),
44
+ },
45
+ ReloadDirectories: []string{
46
+ publishedPath(filepath.Join(root, "config-deps")),
47
+ },
48
+ ReloadFiles: []string{
49
+ publishedPath(filepath.Join(root, "lint.config.ts")),
50
+ },
51
+ },
52
+ root,
53
+ )
54
+ if err != nil {
55
+ t.Fatalf("normalize project input snapshot: %v", err)
56
+ }
57
+ source := &NativePluginSource{
58
+ projectInputs: snapshot,
59
+ }
60
+
61
+ cases := []struct {
62
+ location string
63
+ want bool
64
+ }{
65
+ {filepath.Join(root, "docs", "missing.md"), true},
66
+ {filepath.Join(root, "api", "openapi.json"), true},
67
+ {filepath.Join(root, "api", "nested", "swagger.json"), true},
68
+ {
69
+ filepath.Join(
70
+ root,
71
+ "api",
72
+ "nested",
73
+ "v[12]",
74
+ "{openapi,swagger}.yaml",
75
+ ),
76
+ true,
77
+ },
78
+ {filepath.Join(root, "api", "nested", "v1", "openapi.yaml"), false},
79
+ {filepath.Join(root, "README.md"), false},
80
+ }
81
+ for _, tc := range cases {
82
+ uriPath := filepath.ToSlash(tc.location)
83
+ if filepath.VolumeName(tc.location) != "" &&
84
+ !strings.HasPrefix(uriPath, "/") {
85
+ uriPath = "/" + uriPath
86
+ }
87
+ uri := (&url.URL{
88
+ Scheme: "file",
89
+ Path: uriPath,
90
+ }).String()
91
+ if got := source.ProjectInputMatchesURI(uri); got != tc.want {
92
+ t.Fatalf("ProjectInputMatchesURI(%q) = %v, want %v", uri, got, tc.want)
93
+ }
94
+ }
95
+ if source.ProjectInputMatchesURI("https://example.com/openapi.json") {
96
+ t.Fatal("remote URL matched the local filesystem dependency contract")
97
+ }
98
+
99
+ reloadCases := []struct {
100
+ location string
101
+ want bool
102
+ }{
103
+ {filepath.Join(root, "lint.config.ts"), true},
104
+ {filepath.Join(root, "config-deps"), true},
105
+ {filepath.Join(root, "config-deps", "package.json"), true},
106
+ {filepath.Join(root, "config-deps", "nested", "package.json"), false},
107
+ {filepath.Join(root, "config-deps-other", "package.json"), false},
108
+ {filepath.Join(root, "README.md"), false},
109
+ }
110
+ for _, tc := range reloadCases {
111
+ uriPath := filepath.ToSlash(tc.location)
112
+ if filepath.VolumeName(tc.location) != "" &&
113
+ !strings.HasPrefix(uriPath, "/") {
114
+ uriPath = "/" + uriPath
115
+ }
116
+ uri := (&url.URL{Scheme: "file", Path: uriPath}).String()
117
+ if got := source.ProjectInputReloadMatchesURI(uri); got != tc.want {
118
+ t.Fatalf(
119
+ "ProjectInputReloadMatchesURI(%q) = %v, want %v",
120
+ uri,
121
+ got,
122
+ tc.want,
123
+ )
124
+ }
125
+ }
126
+ if source.ProjectInputReloadMatchesURI("https://example.com/package.json") {
127
+ t.Fatal("remote URL matched the executable reload contract")
128
+ }
129
+ }
@@ -0,0 +1,110 @@
1
+ package lspserver
2
+
3
+ import (
4
+ "path/filepath"
5
+ "testing"
6
+ )
7
+
8
+ // TestLSPProjectInputsRejectInvalidAndForeignSnapshots verifies the editor
9
+ // consumer enforces the same absolute-local, selected-root contract as the CLI
10
+ // watch consumer.
11
+ //
12
+ // The LSP manifest is an independent consumer of the sidecar protocol. It must
13
+ // reject malformed paths before a broad editor watcher can be redirected to an
14
+ // unrelated root or a Windows device namespace.
15
+ //
16
+ // 1. Normalize one valid snapshot under the selected physical root.
17
+ // 2. Reject relative paths, remote URLs, and a different project root.
18
+ // 3. Reject Windows device namespaces and malformed UNC volumes while
19
+ // retaining fixed drive and UNC paths.
20
+ // 4. Reject incomplete and malformed launcher-owned reload fingerprints.
21
+ func TestLSPProjectInputsRejectInvalidAndForeignSnapshots(t *testing.T) {
22
+ root := t.TempDir()
23
+ valid := LSPProjectInputSnapshot{
24
+ Root: root,
25
+ Files: []string{filepath.Join(root, "docs", "spec.md")},
26
+ Globs: []string{filepath.Join(root, "api", "**", "*.json")},
27
+ ReloadFiles: []string{filepath.Join(root, "lint.config.ts")},
28
+ ReloadDirectories: []string{filepath.Join(root, "config-deps")},
29
+ }
30
+ normalized, err := normalizeLSPProjectInputSnapshot(valid, root)
31
+ if err != nil {
32
+ t.Fatalf("valid snapshot: %v", err)
33
+ }
34
+ if len(normalized.Files) != 1 ||
35
+ len(normalized.Globs) != 1 ||
36
+ len(normalized.ReloadFiles) != 1 ||
37
+ len(normalized.ReloadDirectories) != 1 {
38
+ t.Fatalf("normalized snapshot = %#v", normalized)
39
+ }
40
+
41
+ cases := []LSPProjectInputSnapshot{
42
+ {Root: "relative", Files: []string{}, Globs: []string{}},
43
+ {Root: root, Files: []string{"docs/spec.md"}, Globs: []string{}},
44
+ {Root: root, Files: []string{}, Globs: []string{"https://example.com/openapi.json"}},
45
+ {Root: root, ReloadFiles: []string{"lint.config.ts"}},
46
+ {Root: root, ReloadDirectories: []string{"config-deps"}},
47
+ {Root: filepath.Join(root, "foreign"), Files: []string{}, Globs: []string{}},
48
+ }
49
+ for _, snapshot := range cases {
50
+ if _, err := normalizeLSPProjectInputSnapshot(snapshot, root); err == nil {
51
+ t.Fatalf("invalid snapshot was accepted: %#v", snapshot)
52
+ }
53
+ }
54
+
55
+ malformedFingerprintCases := []LSPProjectInputSnapshot{
56
+ {
57
+ Root: root,
58
+ ReloadDirectories: valid.ReloadDirectories,
59
+ ReloadDirectoryDigests: map[string]string{},
60
+ },
61
+ {
62
+ Root: root,
63
+ ReloadDirectories: valid.ReloadDirectories,
64
+ ReloadDirectoryDigests: map[string]string{
65
+ valid.ReloadDirectories[0]: "not-a-sha256-digest",
66
+ },
67
+ },
68
+ {
69
+ Root: root,
70
+ ReloadFiles: valid.ReloadFiles,
71
+ ReloadFileDigests: map[string]string{},
72
+ },
73
+ }
74
+ for _, snapshot := range malformedFingerprintCases {
75
+ if _, err := normalizeLSPProjectInputSnapshot(snapshot, root); err == nil {
76
+ t.Fatalf("malformed selection fingerprint was accepted: %#v", snapshot)
77
+ }
78
+ }
79
+
80
+ windowsCases := []struct {
81
+ location string
82
+ want bool
83
+ }{
84
+ {location: `C:\project\docs\spec.md`, want: true},
85
+ {location: `\\server\share\docs\spec.md`, want: true},
86
+ {location: `\\?\C:\project\docs\spec.md`, want: true},
87
+ {location: `\\?\UNC\server\share\docs\spec.md`, want: true},
88
+ {location: `\root-only\docs\spec.md`, want: false},
89
+ {location: "/root-only/docs/spec.md", want: false},
90
+ {location: "\\\\server\\*\\docs\\spec.md", want: false},
91
+ {location: "\\\\server\\..\\docs\\spec.md", want: false},
92
+ {location: "\\\\?\\UNC\\server\\?\\docs\\spec.md", want: false},
93
+ {location: "C:\\project\\docs\\spec.md\x00ignored", want: false},
94
+ {location: `\\?\GLOBALROOT\Device\HarddiskVolume1`, want: false},
95
+ {location: `\\.\pipe\ttsc`, want: false},
96
+ }
97
+ for _, tc := range windowsCases {
98
+ if got := isAbsoluteLocalLSPProjectInputPath(tc.location, "windows"); got != tc.want {
99
+ t.Fatalf(
100
+ "isAbsoluteLocalLSPProjectInputPath(%q, windows) = %v, want %v",
101
+ tc.location,
102
+ got,
103
+ tc.want,
104
+ )
105
+ }
106
+ }
107
+ if !isAbsoluteLocalLSPProjectInputPath("/project/docs/spec.md", "linux") {
108
+ t.Fatal("POSIX absolute path was rejected under a non-Windows target")
109
+ }
110
+ }