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.
- package/cmd/ttscserver/main.go +79 -3
- package/cmd/ttscserver/run_lsp_uses_native_plugin_manifest_source_test.go +96 -16
- package/driver/lsp.go +4 -0
- package/internal/lspserver/lsp_document_diagnostics_omits_cached_project_when_current_result_has_none_test.go +48 -0
- package/internal/lspserver/lsp_executable_project_input_change_requests_launcher_restart_test.go +98 -0
- package/internal/lspserver/lsp_external_watched_change_retains_program_test.go +53 -0
- package/internal/lspserver/lsp_hints_refresh_scheduled_by_editor_events_test.go +9 -0
- package/internal/lspserver/lsp_native_plugin_source.go +171 -55
- package/internal/lspserver/lsp_native_resident.go +110 -9
- package/internal/lspserver/lsp_plugin.go +6 -0
- package/internal/lspserver/lsp_project_context_transport_identity_test.go +43 -0
- package/internal/lspserver/lsp_project_diagnostics.go +235 -0
- package/internal/lspserver/lsp_project_diagnostics_capability_is_independent_test.go +67 -0
- package/internal/lspserver/lsp_project_diagnostics_program_input_overlap_refreshes_all_producers_test.go +78 -0
- package/internal/lspserver/lsp_project_diagnostics_refresh_accumulates_owner_freshness_test.go +65 -0
- package/internal/lspserver/lsp_project_diagnostics_refresh_keeps_each_producer_last_good_test.go +90 -0
- package/internal/lspserver/lsp_project_diagnostics_refreshes_only_input_owners_test.go +62 -0
- package/internal/lspserver/lsp_project_diagnostics_resident_unsupported_falls_back_test.go +123 -0
- package/internal/lspserver/lsp_project_diagnostics_resume_preserves_generation_test.go +52 -0
- package/internal/lspserver/lsp_project_diagnostics_translates_relative_client_project_test.go +90 -0
- package/internal/lspserver/lsp_project_input_ownership_resolves_declared_spellings_test.go +95 -0
- package/internal/lspserver/lsp_project_input_registration.go +504 -0
- package/internal/lspserver/lsp_project_input_registration_rechecks_selection_baseline_test.go +71 -0
- package/internal/lspserver/lsp_project_input_registration_reconciles_rejected_pending_request_test.go +268 -0
- package/internal/lspserver/lsp_project_input_registration_shapes_patterns_test.go +94 -0
- package/internal/lspserver/lsp_project_input_watchers_anchor_missing_paths_test.go +48 -0
- package/internal/lspserver/lsp_project_inputs.go +944 -0
- package/internal/lspserver/lsp_project_inputs_match_missing_exact_and_glob_test.go +129 -0
- package/internal/lspserver/lsp_project_inputs_reject_invalid_and_foreign_snapshots_test.go +110 -0
- package/internal/lspserver/lsp_proxy.go +591 -28
- package/internal/lspserver/lsp_reload_directories_compare_immediate_topology_test.go +188 -0
- package/internal/lspserver/lsp_reload_file_fingerprint_preserves_raw_symlink_target_test.go +47 -0
- package/internal/lspserver/lsp_resident_falls_back_when_serve_unsupported_test.go +1 -1
- package/internal/lspserver/lsp_resident_invalidation_broadcasts_program_input_overlap_test.go +60 -0
- package/internal/lspserver/lsp_resident_invalidation_targets_project_input_owners_test.go +51 -0
- package/internal/lspserver/lsp_same_transport_entries_are_deduplicated_test.go +66 -0
- package/lib/compiler/internal/project/readProjectConfig.d.ts +5 -3
- package/lib/compiler/internal/project/readProjectConfig.js +46 -14
- package/lib/compiler/internal/project/readProjectConfig.js.map +1 -1
- package/lib/compiler/internal/residentCheckProcess.d.ts +46 -0
- package/lib/compiler/internal/residentCheckProcess.js +227 -0
- package/lib/compiler/internal/residentCheckProcess.js.map +1 -0
- package/lib/compiler/internal/resolveEmittedJavaScript.d.ts +2 -1
- package/lib/compiler/internal/resolveEmittedJavaScript.js +35 -18
- package/lib/compiler/internal/resolveEmittedJavaScript.js.map +1 -1
- package/lib/compiler/internal/runBuild.d.ts +64 -1
- package/lib/compiler/internal/runBuild.js +484 -7
- package/lib/compiler/internal/runBuild.js.map +1 -1
- package/lib/compiler/internal/runSingleFileEmit.js +1 -0
- package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
- package/lib/flags/parser.js +13 -17
- package/lib/flags/parser.js.map +1 -1
- package/lib/flags/schema.d.ts +10 -3
- package/lib/flags/schema.js +99 -0
- package/lib/flags/schema.js.map +1 -1
- package/lib/internal/projectInputPathIdentity.d.ts +23 -0
- package/lib/internal/projectInputPathIdentity.js +222 -0
- package/lib/internal/projectInputPathIdentity.js.map +1 -0
- package/lib/launcher/internal/runTtsc.d.ts +17 -0
- package/lib/launcher/internal/runTtsc.js +121 -88
- package/lib/launcher/internal/runTtsc.js.map +1 -1
- package/lib/launcher/internal/runTtscserver.d.ts +13 -1
- package/lib/launcher/internal/runTtscserver.js +415 -45
- package/lib/launcher/internal/runTtscserver.js.map +1 -1
- package/lib/launcher/internal/singleFileOutput.d.ts +16 -0
- package/lib/launcher/internal/singleFileOutput.js +103 -0
- package/lib/launcher/internal/singleFileOutput.js.map +1 -0
- package/lib/launcher/internal/watchTopology.d.ts +214 -2
- package/lib/launcher/internal/watchTopology.js +1560 -41
- package/lib/launcher/internal/watchTopology.js.map +1 -1
- package/lib/plugin/internal/loadProjectPlugins.d.ts +1 -0
- package/lib/plugin/internal/loadProjectPlugins.js +5 -0
- package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
- package/lib/structures/ITtscPluginCapabilities.d.ts +31 -0
- package/lib/structures/internal/ITtscProjectInputSnapshot.d.ts +29 -0
- package/lib/structures/internal/ITtscProjectInputSnapshot.js +3 -0
- package/lib/structures/internal/ITtscProjectInputSnapshot.js.map +1 -0
- package/lib/structures/internal/TtscSingleFileEmitOptions.d.ts +5 -0
- package/package.json +8 -8
- package/src/compiler/internal/project/readProjectConfig.ts +62 -8
- package/src/compiler/internal/residentCheckProcess.ts +279 -0
- package/src/compiler/internal/resolveEmittedJavaScript.ts +43 -21
- package/src/compiler/internal/runBuild.ts +728 -12
- package/src/compiler/internal/runSingleFileEmit.ts +1 -0
- package/src/flags/parser.ts +17 -17
- package/src/flags/schema.ts +111 -3
- package/src/internal/projectInputPathIdentity.ts +273 -0
- package/src/launcher/internal/runTtsc.ts +141 -117
- package/src/launcher/internal/runTtscserver.ts +561 -54
- package/src/launcher/internal/singleFileOutput.ts +133 -0
- package/src/launcher/internal/watchTopology.ts +2008 -59
- package/src/plugin/internal/loadProjectPlugins.ts +8 -0
- package/src/structures/ITtscPluginCapabilities.ts +34 -0
- package/src/structures/internal/ITtscProjectInputSnapshot.ts +29 -0
- package/src/structures/internal/TtscSingleFileEmitOptions.ts +5 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
package lspserver
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"net/url"
|
|
5
|
+
"os"
|
|
6
|
+
"path/filepath"
|
|
7
|
+
"testing"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
// TestLSPReloadDirectoriesCompareImmediateTopology verifies reload-directory
|
|
11
|
+
// notifications restart only when the declared non-recursive topology changes.
|
|
12
|
+
//
|
|
13
|
+
// A directory fingerprint represents resolution identity, not the contents of
|
|
14
|
+
// every child. Treating every descendant event as a restart turns ordinary
|
|
15
|
+
// edits into crashes, while ignoring directory identity or symlink targets
|
|
16
|
+
// leaves contributor selection stale.
|
|
17
|
+
//
|
|
18
|
+
// 1. Record a directory with one file and one nested directory.
|
|
19
|
+
// 2. Prove child-content and nested-descendant edits leave its digest stable.
|
|
20
|
+
// 3. Prove immediate creation and deletion change the digest.
|
|
21
|
+
// 4. Prove deleting the watched directory itself changes the digest.
|
|
22
|
+
// 5. Where supported, retarget a symlink without renaming it and prove the raw
|
|
23
|
+
// link target participates in the digest.
|
|
24
|
+
// 6. Replace an empty directory with the same topology and prove its identity
|
|
25
|
+
// event still restarts selection.
|
|
26
|
+
// 7. Nest one reload directory in another and prove the unchanged parent
|
|
27
|
+
// cannot hide an immediate topology change in the child.
|
|
28
|
+
// 8. Rediscover project inputs after topology drift and prove refresh retains
|
|
29
|
+
// the selection-time baseline until the server restarts.
|
|
30
|
+
func TestLSPReloadDirectoriesCompareImmediateTopology(t *testing.T) {
|
|
31
|
+
root := t.TempDir()
|
|
32
|
+
reloadDirectory := filepath.Join(root, "config-deps")
|
|
33
|
+
nested := filepath.Join(reloadDirectory, "nested")
|
|
34
|
+
if err := os.MkdirAll(nested, 0o755); err != nil {
|
|
35
|
+
t.Fatal(err)
|
|
36
|
+
}
|
|
37
|
+
selection := filepath.Join(reloadDirectory, "selection.cjs")
|
|
38
|
+
nestedSelection := filepath.Join(nested, "selection.cjs")
|
|
39
|
+
if err := os.WriteFile(selection, []byte("alpha"), 0o644); err != nil {
|
|
40
|
+
t.Fatal(err)
|
|
41
|
+
}
|
|
42
|
+
if err := os.WriteFile(nestedSelection, []byte("alpha"), 0o644); err != nil {
|
|
43
|
+
t.Fatal(err)
|
|
44
|
+
}
|
|
45
|
+
changed := fileChangeTypeChanged
|
|
46
|
+
created := fileChangeTypeCreated
|
|
47
|
+
deleted := fileChangeTypeDeleted
|
|
48
|
+
uri := func(location string) string {
|
|
49
|
+
normalized := filepath.ToSlash(location)
|
|
50
|
+
if filepath.VolumeName(location) != "" {
|
|
51
|
+
normalized = "/" + normalized
|
|
52
|
+
}
|
|
53
|
+
return (&url.URL{Scheme: "file", Path: normalized}).String()
|
|
54
|
+
}
|
|
55
|
+
snapshot := func(directory string) LSPProjectInputSnapshot {
|
|
56
|
+
normalized, err := normalizeLSPProjectInputSnapshot(
|
|
57
|
+
LSPProjectInputSnapshot{
|
|
58
|
+
Root: root,
|
|
59
|
+
ReloadDirectories: []string{directory},
|
|
60
|
+
},
|
|
61
|
+
root,
|
|
62
|
+
)
|
|
63
|
+
if err != nil {
|
|
64
|
+
t.Fatalf("normalize reload directory: %v", err)
|
|
65
|
+
}
|
|
66
|
+
return normalized
|
|
67
|
+
}
|
|
68
|
+
source := &NativePluginSource{projectInputs: snapshot(reloadDirectory)}
|
|
69
|
+
|
|
70
|
+
if err := os.WriteFile(selection, []byte("beta"), 0o644); err != nil {
|
|
71
|
+
t.Fatal(err)
|
|
72
|
+
}
|
|
73
|
+
if source.ProjectInputReloadMatchesChange(uri(selection), &changed) {
|
|
74
|
+
t.Fatal("ordinary child-content edit changed directory topology")
|
|
75
|
+
}
|
|
76
|
+
if err := os.WriteFile(nestedSelection, []byte("beta"), 0o644); err != nil {
|
|
77
|
+
t.Fatal(err)
|
|
78
|
+
}
|
|
79
|
+
if source.ProjectInputReloadMatchesChange(uri(nestedSelection), &changed) {
|
|
80
|
+
t.Fatal("nested descendant edit matched a non-recursive reload directory")
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
createdEntry := filepath.Join(reloadDirectory, "created.cjs")
|
|
84
|
+
if err := os.WriteFile(createdEntry, []byte("created"), 0o644); err != nil {
|
|
85
|
+
t.Fatal(err)
|
|
86
|
+
}
|
|
87
|
+
if !source.ProjectInputReloadMatchesChange(uri(createdEntry), &created) {
|
|
88
|
+
t.Fatal("immediate entry creation did not change directory topology")
|
|
89
|
+
}
|
|
90
|
+
source.projectInputs = snapshot(reloadDirectory)
|
|
91
|
+
if err := os.Remove(createdEntry); err != nil {
|
|
92
|
+
t.Fatal(err)
|
|
93
|
+
}
|
|
94
|
+
if !source.ProjectInputReloadMatchesChange(uri(createdEntry), &deleted) {
|
|
95
|
+
t.Fatal("immediate entry deletion did not change directory topology")
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
deletionRoot := filepath.Join(root, "deleted-deps")
|
|
99
|
+
if err := os.Mkdir(deletionRoot, 0o755); err != nil {
|
|
100
|
+
t.Fatal(err)
|
|
101
|
+
}
|
|
102
|
+
source.projectInputs = snapshot(deletionRoot)
|
|
103
|
+
if err := os.Remove(deletionRoot); err != nil {
|
|
104
|
+
t.Fatal(err)
|
|
105
|
+
}
|
|
106
|
+
if !source.ProjectInputReloadMatchesChange(uri(deletionRoot), &deleted) {
|
|
107
|
+
t.Fatal("reload-directory deletion did not change its topology state")
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
replacementRoot := filepath.Join(root, "replacement-deps")
|
|
111
|
+
if err := os.Mkdir(replacementRoot, 0o755); err != nil {
|
|
112
|
+
t.Fatal(err)
|
|
113
|
+
}
|
|
114
|
+
source.projectInputs = snapshot(replacementRoot)
|
|
115
|
+
if err := os.Remove(replacementRoot); err != nil {
|
|
116
|
+
t.Fatal(err)
|
|
117
|
+
}
|
|
118
|
+
if err := os.Mkdir(replacementRoot, 0o755); err != nil {
|
|
119
|
+
t.Fatal(err)
|
|
120
|
+
}
|
|
121
|
+
if !source.ProjectInputReloadMatchesChange(
|
|
122
|
+
uri(replacementRoot),
|
|
123
|
+
&created,
|
|
124
|
+
) {
|
|
125
|
+
t.Fatal("same-topology directory replacement did not match its identity event")
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
nestedParent := filepath.Join(root, "nested-parent")
|
|
129
|
+
nestedChild := filepath.Join(nestedParent, "child")
|
|
130
|
+
if err := os.MkdirAll(nestedChild, 0o755); err != nil {
|
|
131
|
+
t.Fatal(err)
|
|
132
|
+
}
|
|
133
|
+
nestedSnapshot, err := normalizeLSPProjectInputSnapshot(
|
|
134
|
+
LSPProjectInputSnapshot{
|
|
135
|
+
Root: root,
|
|
136
|
+
ReloadDirectories: []string{nestedParent, nestedChild},
|
|
137
|
+
},
|
|
138
|
+
root,
|
|
139
|
+
)
|
|
140
|
+
if err != nil {
|
|
141
|
+
t.Fatalf("normalize nested reload directories: %v", err)
|
|
142
|
+
}
|
|
143
|
+
source.projectInputs = nestedSnapshot
|
|
144
|
+
nestedEntry := filepath.Join(nestedChild, "selection.cjs")
|
|
145
|
+
if err := os.WriteFile(nestedEntry, []byte("alpha"), 0o644); err != nil {
|
|
146
|
+
t.Fatal(err)
|
|
147
|
+
}
|
|
148
|
+
if !source.ProjectInputReloadMatchesChange(uri(nestedEntry), &created) {
|
|
149
|
+
t.Fatal("unchanged parent reload directory hid nested topology change")
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
refreshRoot := filepath.Join(root, "refresh-deps")
|
|
153
|
+
if err := os.Mkdir(refreshRoot, 0o755); err != nil {
|
|
154
|
+
t.Fatal(err)
|
|
155
|
+
}
|
|
156
|
+
baseline := snapshot(refreshRoot)
|
|
157
|
+
refreshEntry := filepath.Join(refreshRoot, "selection.cjs")
|
|
158
|
+
if err := os.WriteFile(refreshEntry, []byte("alpha"), 0o644); err != nil {
|
|
159
|
+
t.Fatal(err)
|
|
160
|
+
}
|
|
161
|
+
refreshed := snapshot(refreshRoot)
|
|
162
|
+
preserveProjectInputReloadFingerprints(baseline, &refreshed)
|
|
163
|
+
source.projectInputs = refreshed
|
|
164
|
+
if !source.ProjectInputReloadMatchesChange(uri(refreshEntry), &created) {
|
|
165
|
+
t.Fatal("project-input refresh absorbed selection-time topology drift")
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
firstTarget := filepath.Join(root, "first-target")
|
|
169
|
+
secondTarget := filepath.Join(root, "second-target")
|
|
170
|
+
for _, target := range []string{firstTarget, secondTarget} {
|
|
171
|
+
if err := os.Mkdir(target, 0o755); err != nil {
|
|
172
|
+
t.Fatal(err)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
link := filepath.Join(reloadDirectory, "selection-link")
|
|
176
|
+
if err := os.Symlink(firstTarget, link); err == nil {
|
|
177
|
+
source.projectInputs = snapshot(reloadDirectory)
|
|
178
|
+
if err := os.Remove(link); err != nil {
|
|
179
|
+
t.Fatal(err)
|
|
180
|
+
}
|
|
181
|
+
if err := os.Symlink(secondTarget, link); err != nil {
|
|
182
|
+
t.Fatalf("retarget symlink: %v", err)
|
|
183
|
+
}
|
|
184
|
+
if !source.ProjectInputReloadMatchesChange(uri(link), &changed) {
|
|
185
|
+
t.Fatal("symlink retarget did not change directory topology")
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
package lspserver
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"bytes"
|
|
5
|
+
"crypto/sha256"
|
|
6
|
+
"fmt"
|
|
7
|
+
"os"
|
|
8
|
+
"path/filepath"
|
|
9
|
+
"testing"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
// TestReloadFileFingerprintPreservesRawSymlinkTarget verifies the Go startup
|
|
13
|
+
// validator hashes exact-file symlinks with the launcher's byte protocol.
|
|
14
|
+
//
|
|
15
|
+
// Decoding a POSIX link target as UTF-8 replaces invalid bytes, making an
|
|
16
|
+
// unchanged launcher snapshot disagree with the native validator forever. The
|
|
17
|
+
// capability check keeps the vector portable to filesystems that cannot retain
|
|
18
|
+
// the raw name while requiring byte fidelity wherever they can.
|
|
19
|
+
//
|
|
20
|
+
// 1. Create a dangling symlink with a non-UTF-8 raw target where supported.
|
|
21
|
+
// 2. Read it back and continue only when the filesystem preserved the bytes.
|
|
22
|
+
// 3. Hash the protocol's symlink, raw target, and missing-content records.
|
|
23
|
+
// 4. Assert the production fingerprint is exactly that digest.
|
|
24
|
+
func TestReloadFileFingerprintPreservesRawSymlinkTarget(t *testing.T) {
|
|
25
|
+
target := string([]byte{0xff, 'x'})
|
|
26
|
+
link := filepath.Join(t.TempDir(), "reload-link")
|
|
27
|
+
if err := os.Symlink(target, link); err != nil {
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
retained, err := os.Readlink(link)
|
|
31
|
+
if err != nil {
|
|
32
|
+
t.Fatal(err)
|
|
33
|
+
}
|
|
34
|
+
if !bytes.Equal([]byte(retained), []byte(target)) {
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
digest := sha256.New()
|
|
39
|
+
digest.Write([]byte("symlink\x00"))
|
|
40
|
+
digest.Write([]byte(target))
|
|
41
|
+
digest.Write([]byte{0})
|
|
42
|
+
digest.Write([]byte("missing\x00"))
|
|
43
|
+
expected := fmt.Sprintf("%x", digest.Sum(nil))
|
|
44
|
+
if got := projectInputReloadFileDigest(link); got != expected {
|
|
45
|
+
t.Fatalf("reload symlink digest = %s, want raw-byte protocol %s", got, expected)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -31,7 +31,7 @@ func TestResidentFallsBackWhenServeUnsupported(t *testing.T) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
source.residentMu.Lock()
|
|
34
|
-
unsupported := source.serveUnsupported[plugin
|
|
34
|
+
unsupported := source.serveUnsupported[pluginKey(plugin)]
|
|
35
35
|
source.residentMu.Unlock()
|
|
36
36
|
if !unsupported {
|
|
37
37
|
t.Fatal("a first-spawn failure must mark lsp-serve unsupported so the source stops retrying")
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
package lspserver
|
|
2
|
+
|
|
3
|
+
import "testing"
|
|
4
|
+
|
|
5
|
+
// TestLSPResidentInvalidationBroadcastsProgramInputOverlap verifies an input's
|
|
6
|
+
// contributor ownership never hides its second role as a shared Program input.
|
|
7
|
+
//
|
|
8
|
+
// A TypeScript source or resolveJsonModule JSON file can be declared by one
|
|
9
|
+
// producer while belonging to every resident Program. All residents must see
|
|
10
|
+
// the content delta; the daemon itself skips an external path when its Program
|
|
11
|
+
// does not contain it.
|
|
12
|
+
//
|
|
13
|
+
// 1. Install two resident entries with distinct producer keys.
|
|
14
|
+
// 2. Attribute one shared-Program URI to the first producer only.
|
|
15
|
+
// 3. Assert both residents receive the changed and external deltas.
|
|
16
|
+
func TestLSPResidentInvalidationBroadcastsProgramInputOverlap(t *testing.T) {
|
|
17
|
+
for _, externalURI := range []string{
|
|
18
|
+
"file:///project/src/shared.ts",
|
|
19
|
+
"file:///project/src/shared.json",
|
|
20
|
+
} {
|
|
21
|
+
t.Run(externalURI, func(t *testing.T) {
|
|
22
|
+
first := NativeLSPPluginEntry{Binary: "first", Name: "@ttsc/first"}
|
|
23
|
+
second := NativeLSPPluginEntry{Binary: "second", Name: "@ttsc/second"}
|
|
24
|
+
firstResident := &residentSidecar{}
|
|
25
|
+
secondResident := &residentSidecar{}
|
|
26
|
+
source := &NativePluginSource{
|
|
27
|
+
plugins: []NativeLSPPluginEntry{first, second},
|
|
28
|
+
residents: map[string]*residentSidecar{
|
|
29
|
+
pluginKey(first): firstResident,
|
|
30
|
+
pluginKey(second): secondResident,
|
|
31
|
+
},
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
source.InvalidateResidentProgramsForOwnedWatchedChanges(
|
|
35
|
+
[]string{externalURI},
|
|
36
|
+
[]string{externalURI},
|
|
37
|
+
map[string][]string{
|
|
38
|
+
externalURI: {pluginKey(first)},
|
|
39
|
+
},
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
for label, resident := range map[string]*residentSidecar{
|
|
43
|
+
"owner": firstResident,
|
|
44
|
+
"non-owner": secondResident,
|
|
45
|
+
} {
|
|
46
|
+
if len(resident.changed) != 1 ||
|
|
47
|
+
resident.changed[0] != externalURI ||
|
|
48
|
+
len(resident.external) != 1 ||
|
|
49
|
+
resident.external[0] != externalURI {
|
|
50
|
+
t.Fatalf(
|
|
51
|
+
"%s resident deltas = changed %#v, external %#v",
|
|
52
|
+
label,
|
|
53
|
+
resident.changed,
|
|
54
|
+
resident.external,
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
package lspserver
|
|
2
|
+
|
|
3
|
+
import "testing"
|
|
4
|
+
|
|
5
|
+
// TestLSPResidentInvalidationTargetsProjectInputOwners verifies external data
|
|
6
|
+
// changes reach only resident binaries whose producer declared the input.
|
|
7
|
+
//
|
|
8
|
+
// 1. Install two resident entries with distinct producer keys.
|
|
9
|
+
// 2. Attribute one external URI to the first producer.
|
|
10
|
+
// 3. Assert only the first resident receives changed/external deltas.
|
|
11
|
+
func TestLSPResidentInvalidationTargetsProjectInputOwners(t *testing.T) {
|
|
12
|
+
first := NativeLSPPluginEntry{Binary: "first", Name: "@ttsc/first"}
|
|
13
|
+
second := NativeLSPPluginEntry{Binary: "second", Name: "@ttsc/second"}
|
|
14
|
+
firstResident := &residentSidecar{}
|
|
15
|
+
secondResident := &residentSidecar{}
|
|
16
|
+
source := &NativePluginSource{
|
|
17
|
+
plugins: []NativeLSPPluginEntry{first, second},
|
|
18
|
+
residents: map[string]*residentSidecar{
|
|
19
|
+
pluginKey(first): firstResident,
|
|
20
|
+
pluginKey(second): secondResident,
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
const externalURI = "file:///project/docs/spec.md"
|
|
24
|
+
|
|
25
|
+
source.InvalidateResidentProgramsForOwnedWatchedChanges(
|
|
26
|
+
[]string{externalURI},
|
|
27
|
+
[]string{externalURI},
|
|
28
|
+
map[string][]string{
|
|
29
|
+
externalURI: {pluginKey(first)},
|
|
30
|
+
},
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
if len(firstResident.changed) != 1 ||
|
|
34
|
+
firstResident.changed[0] != externalURI ||
|
|
35
|
+
len(firstResident.external) != 1 ||
|
|
36
|
+
firstResident.external[0] != externalURI {
|
|
37
|
+
t.Fatalf(
|
|
38
|
+
"owned resident deltas = changed %#v, external %#v",
|
|
39
|
+
firstResident.changed,
|
|
40
|
+
firstResident.external,
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
if len(secondResident.changed) != 0 ||
|
|
44
|
+
len(secondResident.external) != 0 {
|
|
45
|
+
t.Fatalf(
|
|
46
|
+
"unrelated resident received deltas = changed %#v, external %#v",
|
|
47
|
+
secondResident.changed,
|
|
48
|
+
secondResident.external,
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
package lspserver
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"path/filepath"
|
|
5
|
+
"testing"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
// TestLSPSameTransportEntriesAreDeduplicated verifies logical manifest entries
|
|
9
|
+
// sharing one effective native launch identity produce one aggregate result.
|
|
10
|
+
//
|
|
11
|
+
// Native verbs receive the full plugin manifest and no selected-entry key. A
|
|
12
|
+
// composed aggregate and leaf can therefore have distinct names while invoking
|
|
13
|
+
// the same binary with the same argv; treating them as separate producers would
|
|
14
|
+
// duplicate diagnostics, inputs, completion hints, and command discovery.
|
|
15
|
+
func TestLSPSameTransportEntriesAreDeduplicated(t *testing.T) {
|
|
16
|
+
aggregate := NativeLSPPluginEntry{
|
|
17
|
+
Binary: "shared-sidecar",
|
|
18
|
+
Name: "@ttsc/aggregate",
|
|
19
|
+
ProjectDiagnostics: true,
|
|
20
|
+
ProjectInputs: true,
|
|
21
|
+
Stage: "check",
|
|
22
|
+
}
|
|
23
|
+
leaf := aggregate
|
|
24
|
+
leaf.Name = "@ttsc/leaf"
|
|
25
|
+
|
|
26
|
+
selected := selectPluginTransports(
|
|
27
|
+
[]NativeLSPPluginEntry{aggregate, leaf},
|
|
28
|
+
nil,
|
|
29
|
+
)
|
|
30
|
+
if len(selected) != 1 || selected[0].Name != aggregate.Name {
|
|
31
|
+
t.Fatalf("same launch transport selection = %#v", selected)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
root := t.TempDir()
|
|
35
|
+
snapshot := LSPProjectInputSnapshot{
|
|
36
|
+
Root: root,
|
|
37
|
+
Files: []string{filepath.Join(root, "spec.md")},
|
|
38
|
+
}
|
|
39
|
+
source := &NativePluginSource{
|
|
40
|
+
plugins: []NativeLSPPluginEntry{aggregate, leaf},
|
|
41
|
+
}
|
|
42
|
+
source.storeProjectInputs(aggregate, 1, snapshot)
|
|
43
|
+
source.storeProjectInputs(leaf, 1, snapshot)
|
|
44
|
+
owners := source.ProjectInputOwnersForURI(testFileURI(snapshot.Files[0]))
|
|
45
|
+
if len(owners) != 1 || owners[0] != pluginKey(aggregate) {
|
|
46
|
+
t.Fatalf("same transport input owners = %#v", owners)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
publication := &LSPProjectDiagnostics{
|
|
50
|
+
URI: "file:///tsconfig.json",
|
|
51
|
+
Diagnostics: []LSPDiagnostic{
|
|
52
|
+
{Message: "one aggregate finding"},
|
|
53
|
+
},
|
|
54
|
+
}
|
|
55
|
+
source.storeProjectDiagnostics(aggregate, 1, publication)
|
|
56
|
+
source.storeProjectDiagnostics(leaf, 1, publication)
|
|
57
|
+
merged := source.projectDiagnosticsSnapshot()
|
|
58
|
+
if merged == nil || len(merged.Diagnostics) != 1 {
|
|
59
|
+
t.Fatalf("same transport project publication = %#v", merged)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
result := source.ProjectDiagnosticsForOwners(nil)
|
|
63
|
+
if result.selected != 1 {
|
|
64
|
+
t.Fatalf("same transport selected %d project producers", result.selected)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -5,8 +5,10 @@ import type { ITtscProjectLocatorOptions } from "../../../structures/internal/IT
|
|
|
5
5
|
*
|
|
6
6
|
* Follows `extends` chains (including arrays) and merges compiler options with
|
|
7
7
|
* later configs taking precedence. Path-typed options (`baseUrl`,
|
|
8
|
-
* `declarationDir`, `rootDir`) are resolved
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* `declarationDir`, `outFile`, `rootDir`, `tsBuildInfoFile`) are resolved
|
|
9
|
+
* relative to the config that declares them. `${configDir}` paths are resolved
|
|
10
|
+
* against the final consuming config after the extends chain is merged. The
|
|
11
|
+
* `outDir` is resolved to an absolute path. Plugins are inherited from the
|
|
12
|
+
* nearest ancestor that declares them.
|
|
11
13
|
*/
|
|
12
14
|
export declare function readProjectConfig(opts?: ITtscProjectLocatorOptions): ITtscParsedProjectConfig;
|
|
@@ -13,21 +13,30 @@ const resolveProjectConfig_1 = require("./resolveProjectConfig");
|
|
|
13
13
|
* Compiler option keys whose values are file-system paths that must be resolved
|
|
14
14
|
* relative to the tsconfig that declares them, not the project root.
|
|
15
15
|
*/
|
|
16
|
-
const PATH_OPTIONS = new Set([
|
|
16
|
+
const PATH_OPTIONS = new Set([
|
|
17
|
+
"baseUrl",
|
|
18
|
+
"declarationDir",
|
|
19
|
+
"outFile",
|
|
20
|
+
"rootDir",
|
|
21
|
+
"tsBuildInfoFile",
|
|
22
|
+
]);
|
|
23
|
+
const CONFIG_DIR_TEMPLATE = "${configDir}";
|
|
17
24
|
/**
|
|
18
25
|
* Read and resolve the project config subset used by ttsc.
|
|
19
26
|
*
|
|
20
27
|
* Follows `extends` chains (including arrays) and merges compiler options with
|
|
21
28
|
* later configs taking precedence. Path-typed options (`baseUrl`,
|
|
22
|
-
* `declarationDir`, `rootDir`) are resolved
|
|
23
|
-
*
|
|
24
|
-
*
|
|
29
|
+
* `declarationDir`, `outFile`, `rootDir`, `tsBuildInfoFile`) are resolved
|
|
30
|
+
* relative to the config that declares them. `${configDir}` paths are resolved
|
|
31
|
+
* against the final consuming config after the extends chain is merged. The
|
|
32
|
+
* `outDir` is resolved to an absolute path. Plugins are inherited from the
|
|
33
|
+
* nearest ancestor that declares them.
|
|
25
34
|
*/
|
|
26
35
|
function readProjectConfig(opts = {}) {
|
|
27
36
|
const identity = (0, resolveProjectConfig_1.resolveProjectIdentity)(opts);
|
|
28
37
|
const tsconfig = identity.physicalConfigPath;
|
|
29
38
|
const root = identity.physicalProjectRoot;
|
|
30
|
-
const compilerOptions = readResolvedCompilerOptions(tsconfig);
|
|
39
|
+
const compilerOptions = readResolvedCompilerOptions(tsconfig, new Set(), node_path_1.default.dirname(tsconfig));
|
|
31
40
|
return {
|
|
32
41
|
configPaths: compilerOptions.configPaths,
|
|
33
42
|
compilerOptions: {
|
|
@@ -71,7 +80,7 @@ function resolveAbsolutePath(cwd, target) {
|
|
|
71
80
|
* `finally` block so sibling-referenced configs can be visited again via a
|
|
72
81
|
* different parent.
|
|
73
82
|
*/
|
|
74
|
-
function readResolvedCompilerOptions(tsconfig, seen = new Set()) {
|
|
83
|
+
function readResolvedCompilerOptions(tsconfig, seen = new Set(), configDir = node_path_1.default.dirname(tsconfig)) {
|
|
75
84
|
const canonical = resolveRealPath(tsconfig);
|
|
76
85
|
if (seen.has(canonical)) {
|
|
77
86
|
throw new Error(`ttsc: circular tsconfig extends detected: ${canonical}`);
|
|
@@ -80,7 +89,7 @@ function readResolvedCompilerOptions(tsconfig, seen = new Set()) {
|
|
|
80
89
|
try {
|
|
81
90
|
const parsed = (0, readConfigJson_1.readJsoncFile)(canonical);
|
|
82
91
|
const own = parsed.compilerOptions;
|
|
83
|
-
const base = resolveBaseCompilerOptions(canonical, parsed.extends, seen);
|
|
92
|
+
const base = resolveBaseCompilerOptions(canonical, parsed.extends, seen, configDir);
|
|
84
93
|
const ownBaseDir = node_path_1.default.dirname(canonical);
|
|
85
94
|
const ownOptionBaseDirs = own === undefined
|
|
86
95
|
? {}
|
|
@@ -92,7 +101,7 @@ function readResolvedCompilerOptions(tsconfig, seen = new Set()) {
|
|
|
92
101
|
const options = resolvePathOptions({
|
|
93
102
|
...base.options,
|
|
94
103
|
...(own ?? {}),
|
|
95
|
-
}, optionBaseDirs);
|
|
104
|
+
}, optionBaseDirs, configDir);
|
|
96
105
|
const ownPlugins = own?.plugins;
|
|
97
106
|
const pluginsDeclared = Array.isArray(ownPlugins);
|
|
98
107
|
const plugins = pluginsDeclared
|
|
@@ -103,7 +112,7 @@ function readResolvedCompilerOptions(tsconfig, seen = new Set()) {
|
|
|
103
112
|
optionBaseDirs,
|
|
104
113
|
options,
|
|
105
114
|
outDir: typeof own?.outDir === "string"
|
|
106
|
-
?
|
|
115
|
+
? resolveCompilerOptionPath(ownBaseDir, configDir, own.outDir)
|
|
107
116
|
: base.outDir,
|
|
108
117
|
pluginBaseDirs: pluginsDeclared
|
|
109
118
|
? plugins.map(() => ownBaseDir)
|
|
@@ -126,9 +135,9 @@ function readResolvedCompilerOptions(tsconfig, seen = new Set()) {
|
|
|
126
135
|
* Plugin inheritance: when the current config in an array chain explicitly
|
|
127
136
|
* declares `plugins`, subsequent configs in the array do not override them.
|
|
128
137
|
*/
|
|
129
|
-
function resolveBaseCompilerOptions(tsconfig, extended, seen) {
|
|
138
|
+
function resolveBaseCompilerOptions(tsconfig, extended, seen, configDir) {
|
|
130
139
|
if (typeof extended === "string") {
|
|
131
|
-
return readResolvedCompilerOptions(resolveExtendsConfig(tsconfig, extended), seen);
|
|
140
|
+
return readResolvedCompilerOptions(resolveExtendsConfig(tsconfig, extended), seen, configDir);
|
|
132
141
|
}
|
|
133
142
|
if (!Array.isArray(extended)) {
|
|
134
143
|
return {
|
|
@@ -152,7 +161,7 @@ function resolveBaseCompilerOptions(tsconfig, extended, seen) {
|
|
|
152
161
|
if (typeof specifier !== "string") {
|
|
153
162
|
continue;
|
|
154
163
|
}
|
|
155
|
-
const current = readResolvedCompilerOptions(resolveExtendsConfig(tsconfig, specifier), seen);
|
|
164
|
+
const current = readResolvedCompilerOptions(resolveExtendsConfig(tsconfig, specifier), seen, configDir);
|
|
156
165
|
merged = {
|
|
157
166
|
configPaths: uniquePaths([...merged.configPaths, ...current.configPaths]),
|
|
158
167
|
optionBaseDirs: {
|
|
@@ -180,17 +189,40 @@ function uniquePaths(paths) {
|
|
|
180
189
|
* Resolve path-typed compiler options to absolute paths using the directory of
|
|
181
190
|
* the tsconfig that declared each option (`baseDirs`).
|
|
182
191
|
*/
|
|
183
|
-
function resolvePathOptions(options, baseDirs) {
|
|
192
|
+
function resolvePathOptions(options, baseDirs, configDir) {
|
|
184
193
|
const resolved = { ...options };
|
|
185
194
|
for (const key of PATH_OPTIONS) {
|
|
186
195
|
const value = resolved[key];
|
|
187
196
|
const baseDir = baseDirs[key];
|
|
188
197
|
if (typeof value === "string" && baseDir !== undefined) {
|
|
189
|
-
resolved[key] =
|
|
198
|
+
resolved[key] = resolveCompilerOptionPath(baseDir, configDir, value);
|
|
190
199
|
}
|
|
191
200
|
}
|
|
192
201
|
return resolved;
|
|
193
202
|
}
|
|
203
|
+
/**
|
|
204
|
+
* Resolve an ordinary path from the config that declares it, but substitute a
|
|
205
|
+
* leading `${configDir}` from the final config consuming the merged preset.
|
|
206
|
+
*/
|
|
207
|
+
function resolveCompilerOptionPath(declaringDir, configDir, value) {
|
|
208
|
+
if (value.slice(0, CONFIG_DIR_TEMPLATE.length).toLowerCase() !==
|
|
209
|
+
CONFIG_DIR_TEMPLATE.toLowerCase()) {
|
|
210
|
+
return resolveAbsolutePath(declaringDir, value);
|
|
211
|
+
}
|
|
212
|
+
// The compiler picks the base directory from a case-insensitive prefix but
|
|
213
|
+
// substitutes only the exact spelling, so a mis-cased template still anchors
|
|
214
|
+
// here while staying in the path as written. Both halves are reproduced: this
|
|
215
|
+
// function exists to say where the compiler will put the file, and a value
|
|
216
|
+
// the compiler leaves literal is not ours to interpret.
|
|
217
|
+
//
|
|
218
|
+
// The exact spelling becomes "./" before the result is normalized, which
|
|
219
|
+
// keeps the value relative even when its remainder resembles an absolute
|
|
220
|
+
// Windows path. Either config-file separator is accepted on every host.
|
|
221
|
+
const substituted = value.startsWith(CONFIG_DIR_TEMPLATE)
|
|
222
|
+
? `./${value.slice(CONFIG_DIR_TEMPLATE.length)}`
|
|
223
|
+
: value;
|
|
224
|
+
return resolveAbsolutePath(configDir, substituted.replaceAll("\\", "/"));
|
|
225
|
+
}
|
|
194
226
|
/**
|
|
195
227
|
* Resolve an `extends` specifier to an absolute path using the same rules as
|
|
196
228
|
* TypeScript's config resolution:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readProjectConfig.js","sourceRoot":"","sources":["../../../../src/compiler/internal/project/readProjectConfig.ts"],"names":[],"mappings":";;;;;;AAAA,sDAAyB;AACzB,6CAA4C;AAC5C,0DAA6B;AAK7B,qDAA+D;AAC/D,iEAAgE;AAEhE;;;GAGG;AACH,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"readProjectConfig.js","sourceRoot":"","sources":["../../../../src/compiler/internal/project/readProjectConfig.ts"],"names":[],"mappings":";;;;;;AAAA,sDAAyB;AACzB,6CAA4C;AAC5C,0DAA6B;AAK7B,qDAA+D;AAC/D,iEAAgE;AAEhE;;;GAGG;AACH,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC;IAC3B,SAAS;IACT,gBAAgB;IAChB,SAAS;IACT,SAAS;IACT,iBAAiB;CAClB,CAAC,CAAC;AACH,MAAM,mBAAmB,GAAG,cAAc,CAAC;AAkB3C;;;;;;;;;;GAUG;AACH,2BACE,IAAI,GAA+B,EAAE;IAErC,MAAM,QAAQ,GAAG,IAAA,6CAAsB,EAAC,IAAI,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,QAAQ,CAAC,kBAAkB,CAAC;IAC7C,MAAM,IAAI,GAAG,QAAQ,CAAC,mBAAmB,CAAC;IAC1C,MAAM,eAAe,GAAG,2BAA2B,CACjD,QAAQ,EACR,IAAI,GAAG,EAAE,EACT,mBAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CACvB,CAAC;IACF,OAAO;QACL,WAAW,EAAE,eAAe,CAAC,WAAW;QACxC,eAAe,EAAE;YACf,GAAG,eAAe,CAAC,OAAO;YAC1B,MAAM,EAAE,eAAe,CAAC,MAAM;YAC9B,OAAO,EAAE,eAAe,CAAC,OAAO;SACjC;QACD,QAAQ;QACR,IAAI,EAAE,QAAQ;QACd,cAAc,EAAE,eAAe,CAAC,cAAc;QAC9C,IAAI;KACL,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAS,qBAAqB,CAC5B,KAAc;IAEd,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;AACrD,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,QAAgB;IACvC,IAAI,CAAC;QACH,OAAO,iBAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC;AAED,sEAAsE;AACtE,SAAS,mBAAmB,CAAC,GAAW,EAAE,MAAc;IACtD,OAAO,mBAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,mBAAI,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AACtE,CAAC;AAED;;;;;;GAMG;AACH,SAAS,2BAA2B,CAClC,QAAgB,EAChB,IAAI,GAAgB,IAAI,GAAG,EAAE,EAC7B,SAAS,GAAG,mBAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;IAElC,MAAM,SAAS,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC5C,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,6CAA6C,SAAS,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAA,8BAAa,EAAC,SAAS,CAMrC,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,CAAC,eAAe,CAAC;QACnC,MAAM,IAAI,GAAG,0BAA0B,CACrC,SAAS,EACT,MAAM,CAAC,OAAO,EACd,IAAI,EACJ,SAAS,CACV,CAAC;QACF,MAAM,UAAU,GAAG,mBAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,iBAAiB,GACrB,GAAG,KAAK,SAAS;YACf,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,MAAM,CAAC,WAAW,CAChB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,UAAU,CAAU,CAAC,CAC1D,CAAC;QACR,MAAM,cAAc,GAAG;YACrB,GAAG,IAAI,CAAC,cAAc;YACtB,GAAG,iBAAiB;SACrB,CAAC;QACF,MAAM,OAAO,GAAG,kBAAkB,CAChC;YACE,GAAG,IAAI,CAAC,OAAO;YACf,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC;SACf,EACD,cAAc,EACd,SAAS,CACV,CAAC;QACF,MAAM,UAAU,GAAG,GAAG,EAAE,OAAO,CAAC;QAChC,MAAM,eAAe,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAClD,MAAM,OAAO,GAAG,eAAe;YAC7B,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,qBAAqB,CAAC;YAC1C,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;QACjB,OAAO;YACL,WAAW,EAAE,WAAW,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;YAC1D,cAAc;YACd,OAAO;YACP,MAAM,EACJ,OAAO,GAAG,EAAE,MAAM,KAAK,QAAQ;gBAC7B,CAAC,CAAC,yBAAyB,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC;gBAC9D,CAAC,CAAC,IAAI,CAAC,MAAM;YACjB,cAAc,EAAE,eAAe;gBAC7B,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC;gBAC/B,CAAC,CAAC,IAAI,CAAC,cAAc;YACvB,eAAe,EAAE,eAAe,IAAI,IAAI,CAAC,eAAe;YACxD,OAAO;SACR,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACzB,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,0BAA0B,CACjC,QAAgB,EAChB,QAAiB,EACjB,IAAiB,EACjB,SAAiB;IAEjB,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,2BAA2B,CAChC,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,EACxC,IAAI,EACJ,SAAS,CACV,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO;YACL,WAAW,EAAE,EAAE;YACf,cAAc,EAAE,EAAE;YAClB,OAAO,EAAE,EAAE;YACX,cAAc,EAAE,EAAE;YAClB,eAAe,EAAE,KAAK;YACtB,OAAO,EAAE,EAAE;SACZ,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,GAA4B;QACpC,WAAW,EAAE,EAAE;QACf,cAAc,EAAE,EAAE;QAClB,OAAO,EAAE,EAAE;QACX,cAAc,EAAE,EAAE;QAClB,eAAe,EAAE,KAAK;QACtB,OAAO,EAAE,EAAE;KACZ,CAAC;IACF,KAAK,MAAM,SAAS,IAAI,QAAQ,EAAE,CAAC;QACjC,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;YAClC,SAAS;QACX,CAAC;QACD,MAAM,OAAO,GAAG,2BAA2B,CACzC,oBAAoB,CAAC,QAAQ,EAAE,SAAS,CAAC,EACzC,IAAI,EACJ,SAAS,CACV,CAAC;QACF,MAAM,GAAG;YACP,WAAW,EAAE,WAAW,CAAC,CAAC,GAAG,MAAM,CAAC,WAAW,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;YACzE,cAAc,EAAE;gBACd,GAAG,MAAM,CAAC,cAAc;gBACxB,GAAG,OAAO,CAAC,cAAc;aAC1B;YACD,OAAO,EAAE;gBACP,GAAG,MAAM,CAAC,OAAO;gBACjB,GAAG,OAAO,CAAC,OAAO;aACnB;YACD,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM;YACvC,cAAc,EAAE,OAAO,CAAC,eAAe;gBACrC,CAAC,CAAC,OAAO,CAAC,cAAc;gBACxB,CAAC,CAAC,MAAM,CAAC,cAAc;YACzB,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO;YACnE,eAAe,EAAE,MAAM,CAAC,eAAe,IAAI,OAAO,CAAC,eAAe;SACnE,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,WAAW,CAAC,KAAwB;IAC3C,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;AAC7B,CAAC;AAED;;;GAGG;AACH,SAAS,kBAAkB,CACzB,OAAgC,EAChC,QAAgC,EAChC,SAAiB;IAEjB,MAAM,QAAQ,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;IAChC,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC5B,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YACvD,QAAQ,CAAC,GAAG,CAAC,GAAG,yBAAyB,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,SAAS,yBAAyB,CAChC,YAAoB,EACpB,SAAiB,EACjB,KAAa;IAEb,IACE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,mBAAmB,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE;QACxD,mBAAmB,CAAC,WAAW,EAAE,EACjC,CAAC;QACD,OAAO,mBAAmB,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IAClD,CAAC;IACD,2EAA2E;IAC3E,6EAA6E;IAC7E,8EAA8E;IAC9E,2EAA2E;IAC3E,wDAAwD;IACxD,EAAE;IACF,yEAAyE;IACzE,yEAAyE;IACzE,wEAAwE;IACxE,MAAM,WAAW,GAAG,KAAK,CAAC,UAAU,CAAC,mBAAmB,CAAC;QACvD,CAAC,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE;QAChD,CAAC,CAAC,KAAK,CAAC;IACV,OAAO,mBAAmB,CAAC,SAAS,EAAE,WAAW,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,oBAAoB,CAAC,QAAgB,EAAE,SAAiB;IAC/D,MAAM,OAAO,GAAG,mBAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,mBAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC/B,OAAO,0BAA0B,CAAC,SAAS,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,mBAAmB,CAAC,SAAS,CAAC,EAAE,CAAC;QACnC,OAAO,0BAA0B,CAAC,mBAAI,CAAC,OAAO,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,QAAQ,GAAG,IAAA,2BAAa,EAAC,QAAQ,CAAC,CAAC;IACzC,0EAA0E;IAC1E,0EAA0E;IAC1E,2EAA2E;IAC3E,4DAA4D;IAC5D,MAAM,WAAW,GAAG,8BAA8B,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IACxE,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,0BAA0B,CAAC,WAAW,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,CAAC;QACH,OAAO,eAAe,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;IACtD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,eAAe,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,SAAS,OAAO,CAAC,CAAC,CAAC;IAChE,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,8BAA8B,CACrC,QAAqB,EACrB,SAAiB;IAEjB,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,EAAE,CAAC;QAClC,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,YAAoB,CAAC;IACzB,IAAI,CAAC;QACH,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,SAAS,eAAe,CAAC,CAAC;IAC/D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,2EAA2E;QAC3E,0EAA0E;QAC1E,iEAAiE;QACjE,0EAA0E;QAC1E,0EAA0E;QAC1E,oEAAoE;QACpE,IACG,KAA2C,EAAE,IAAI;YAClD,4BAA4B,EAC5B,CAAC;YACD,MAAM,IAAI,KAAK,CACb,iDAAiD,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KACxE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CACvD,EAAE,CACH,CAAC;QACJ,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,2EAA2E;IAC3E,8EAA8E;IAC9E,8EAA8E;IAC9E,mDAAmD;IACnD,EAAE;IACF,sEAAsE;IACtE,uEAAuE;IACvE,mBAAmB;IACnB,MAAM,QAAQ,GAAG,IAAA,6BAAY,EAAC,YAAY,CAAC,CAAC;IAC5C,MAAM,KAAK,GACT,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI;QAC/C,CAAC,CAAE,QAAmC,CAAC,QAAQ;QAC/C,CAAC,CAAC,SAAS,CAAC;IAChB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,mBAAI,CAAC,OAAO,CAAC,mBAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,KAAK,CAAC,CAAC;AACzD,CAAC;AAED;;;;GAIG;AACH,SAAS,iBAAiB,CAAC,SAAiB;IAC1C,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9B,OAAO,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AAClC,CAAC;AAED;;;;;GAKG;AACH,SAAS,0BAA0B,CAAC,QAAgB;IAClD,MAAM,UAAU,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC;QAC3C,CAAC,CAAC,CAAC,QAAQ,CAAC;QACZ,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,QAAQ,OAAO,CAAC,CAAC;IACnC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;YACtB,OAAO,eAAe,CAAC,SAAS,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,sCAAsC,QAAQ,EAAE,CAAC,CAAC;AACpE,CAAC;AAED,SAAS,MAAM,CAAC,QAAgB;IAC9B,IAAI,CAAC;QACH,OAAO,iBAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,mBAAmB,CAAC,SAAiB;IAC5C,OAAO,CACL,SAAS,KAAK,GAAG;QACjB,SAAS,KAAK,IAAI;QAClB,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC;QAC1B,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC;QAC3B,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC;QAC3B,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,CAC7B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { TtscBuildResult } from "../../structures/internal/TtscBuildResult";
|
|
2
|
+
export interface ResidentCheckProcessOptions {
|
|
3
|
+
args: readonly string[];
|
|
4
|
+
binary: string;
|
|
5
|
+
cwd: string;
|
|
6
|
+
env: NodeJS.ProcessEnv;
|
|
7
|
+
requestTimeoutMs?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface ResidentCheckRequest {
|
|
10
|
+
changed?: readonly string[];
|
|
11
|
+
external?: readonly string[];
|
|
12
|
+
invalidate?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface ResidentCheckTelemetry {
|
|
15
|
+
pid: number;
|
|
16
|
+
programLoads: number;
|
|
17
|
+
programUpdates: number;
|
|
18
|
+
reused: boolean;
|
|
19
|
+
}
|
|
20
|
+
export type ResidentCheckResult = TtscBuildResult & {
|
|
21
|
+
telemetry: ResidentCheckTelemetry;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* FIFO JSON-line client for a check-stage `check-serve` sidecar.
|
|
25
|
+
*
|
|
26
|
+
* A watch session serializes cycles, but the client still queues replies so a
|
|
27
|
+
* caller cannot accidentally pair a late response with the next request. Any
|
|
28
|
+
* framing failure retires the process; the launcher then falls back to the
|
|
29
|
+
* ordinary one-shot command for that cycle.
|
|
30
|
+
*/
|
|
31
|
+
export declare class ResidentCheckProcess {
|
|
32
|
+
private readonly child;
|
|
33
|
+
private readonly pending;
|
|
34
|
+
private readonly reader;
|
|
35
|
+
private readonly requestTimeoutMs;
|
|
36
|
+
private failure;
|
|
37
|
+
private stderr;
|
|
38
|
+
constructor(options: ResidentCheckProcessOptions);
|
|
39
|
+
request(payload: ResidentCheckRequest): Promise<ResidentCheckResult>;
|
|
40
|
+
dispose(): void;
|
|
41
|
+
private onLine;
|
|
42
|
+
private settle;
|
|
43
|
+
private fail;
|
|
44
|
+
private terminate;
|
|
45
|
+
private exitError;
|
|
46
|
+
}
|