ttsc 0.23.0 → 0.25.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/LICENSE +21 -21
- package/README.md +66 -63
- package/cmd/ttscgraph/serve.go +264 -48
- package/cmd/ttscgraph/serve_answers_a_project_that_implements_its_own_ambient_declaration_test.go +69 -0
- package/cmd/ttscgraph/serve_early_error_encode_failure_is_observable_test.go +40 -0
- package/cmd/ttscgraph/serve_graph_snapshot_version_matches_typescript_client_test.go +32 -0
- package/cmd/ttscgraph/serve_phase_trace_accounts_for_load_failure_test.go +45 -0
- package/cmd/ttscgraph/serve_phase_trace_is_opt_in_and_payload_free_test.go +52 -0
- package/cmd/ttscgraph/serve_protocol_negotiates_incremental_shards_test.go +44 -0
- package/cmd/ttscgraph/serve_session_reloads_commonjs_package_entry_for_esm_test.go +2 -2
- package/cmd/ttscgraph/serve_session_reloads_superseding_module_candidates_test.go +46 -20
- package/cmd/ttscgraph/serve_session_retries_failed_dump_test.go +9 -9
- package/cmd/ttscgraph/serve_shards.go +1390 -0
- package/cmd/ttscgraph/serve_shards_abandoned_generation_converges_on_retry_test.go +92 -0
- package/cmd/ttscgraph/serve_shards_delete_removed_source_test.go +57 -0
- package/cmd/ttscgraph/serve_shards_external_endpoints_test.go +53 -0
- package/cmd/ttscgraph/serve_shards_keep_source_distributed_dependencies_at_the_boundary_test.go +108 -0
- package/cmd/ttscgraph/serve_shards_match_full_dump_oracle_test.go +88 -0
- package/cmd/ttscgraph/serve_shards_merge_pending_and_new_edits_test.go +50 -0
- package/cmd/ttscgraph/serve_shards_prune_unreferenced_external_endpoints_test.go +65 -0
- package/cmd/ttscgraph/serve_shards_publish_created_source_test.go +92 -0
- package/cmd/ttscgraph/serve_shards_rebuild_declaration_edit_test.go +43 -0
- package/cmd/ttscgraph/serve_shards_refresh_cross_file_implementation_test.go +63 -0
- package/cmd/ttscgraph/serve_shards_refresh_dependent_diagnostics_test.go +80 -0
- package/cmd/ttscgraph/serve_shards_rename_moves_source_identity_test.go +95 -0
- package/cmd/ttscgraph/serve_shards_retry_preserves_committed_generation_test.go +48 -0
- package/cmd/ttscgraph/serve_shards_reuse_unaffected_sources_test.go +121 -0
- package/driver/declaration_shape.go +85 -0
- package/driver/program.go +39 -10
- package/go.sum +22 -22
- package/internal/graph/assigned_implementations_of_declaration_file_symbols_leave_no_edge_source_test.go +84 -0
- package/internal/graph/assigned_implementations_of_node_modules_symbols_leave_no_edge_source_test.go +85 -0
- package/internal/graph/build.go +62 -10
- package/internal/graph/build_files_reuses_committed_cross_file_endpoints_test.go +87 -0
- package/internal/graph/build_keeps_source_distributed_dependencies_at_the_external_boundary_test.go +74 -0
- package/internal/graph/dump.go +84 -43
- package/internal/graph/dump_path_mapper_caches_alias_resolution_test.go +29 -0
- package/internal/graph/dump_paths.go +134 -11
- package/internal/graph/dump_paths_canonicalize_windows_short_root_test.go +39 -0
- package/internal/graph/dump_rejects_provenance_only_path_errors_test.go +32 -0
- package/internal/graph/dump_serializes_the_full_graph_test.go +2 -2
- package/internal/graph/dump_symlink_project_publishes_matching_base_test.go +82 -0
- package/internal/graph/edges.go +73 -17
- package/internal/graph/exports.go +9 -2
- package/internal/graph/graph.go +47 -7
- package/internal/graph/graph_kind_contracts_match_their_producers_test.go +121 -0
- package/internal/graph/node_modifiers_emit_union_strings_test.go +1 -1
- package/internal/graph/provenance.go +11 -1
- package/internal/graph/resolve.go +1 -4
- package/internal/graph/source.go +23 -0
- package/internal/graph/wire_node_ids_share_alias_resolution_test.go +29 -0
- package/internal/lspserver/lsp_native_plugin_source.go +5 -6
- package/internal/lspserver/lsp_native_resident.go +17 -24
- package/lib/TtscService.d.ts +1 -6
- package/lib/TtscService.js +2 -2
- package/lib/TtscService.js.map +1 -1
- package/lib/compiler/internal/captureProcessOutput.d.ts +26 -0
- package/lib/compiler/internal/captureProcessOutput.js +92 -0
- package/lib/compiler/internal/captureProcessOutput.js.map +1 -0
- package/lib/compiler/internal/compileProjectInMemory.js +4 -7
- package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
- package/lib/compiler/internal/residentCheckProcess.d.ts +0 -2
- package/lib/compiler/internal/residentCheckProcess.js +1 -15
- package/lib/compiler/internal/residentCheckProcess.js.map +1 -1
- package/lib/compiler/internal/residentTransformProcess.d.ts +0 -6
- package/lib/compiler/internal/residentTransformProcess.js +0 -25
- package/lib/compiler/internal/residentTransformProcess.js.map +1 -1
- package/lib/compiler/internal/spawnNative.d.ts +14 -6
- package/lib/compiler/internal/spawnNative.js +32 -11
- package/lib/compiler/internal/spawnNative.js.map +1 -1
- package/lib/compiler/internal/startResidentTransform.d.ts +1 -5
- package/lib/compiler/internal/startResidentTransform.js +1 -3
- package/lib/compiler/internal/startResidentTransform.js.map +1 -1
- package/lib/launcher/internal/prepareExecution.d.ts +2 -1
- package/lib/launcher/internal/prepareExecution.js +269 -23
- package/lib/launcher/internal/prepareExecution.js.map +1 -1
- package/lib/launcher/internal/registerRuntimeHooks.js +6 -1
- package/lib/launcher/internal/registerRuntimeHooks.js.map +1 -1
- package/lib/launcher/internal/runTtscserver.js +4 -9
- package/lib/launcher/internal/runTtscserver.js.map +1 -1
- package/lib/launcher/internal/runTtsx.js +2 -55
- package/lib/launcher/internal/runTtsx.js.map +1 -1
- package/lib/launcher/internal/runtimeHooks.d.ts +25 -2
- package/lib/launcher/internal/runtimeHooks.js +344 -69
- package/lib/launcher/internal/runtimeHooks.js.map +1 -1
- package/lib/plugin/internal/buildSourcePlugin.js +31 -3
- package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/descriptorProcessFailure.d.ts +23 -19
- package/lib/plugin/internal/descriptorProcessFailure.js +40 -51
- package/lib/plugin/internal/descriptorProcessFailure.js.map +1 -1
- package/lib/plugin/internal/loadProjectPlugins.d.ts +12 -0
- package/lib/plugin/internal/loadProjectPlugins.js +77 -28
- package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
- package/package.json +8 -8
- package/shim/ast/extra-shim.json +4 -4
- package/shim/ast/go.mod +14 -14
- package/shim/ast/go.sum +20 -20
- package/shim/astnav/go.mod +14 -14
- package/shim/astnav/go.sum +20 -20
- package/shim/bundled/extra-shim.json +1 -1
- package/shim/bundled/go.mod +5 -5
- package/shim/checker/extra-shim.json +31 -31
- package/shim/checker/go.mod +5 -5
- package/shim/compiler/extra-shim.json +4 -4
- package/shim/compiler/go.mod +14 -14
- package/shim/compiler/go.sum +22 -22
- package/shim/core/extra-shim.json +4 -4
- package/shim/core/go.mod +5 -5
- package/shim/diagnosticwriter/go.mod +5 -5
- package/shim/lsp/extra-shim.json +4 -4
- package/shim/lsp/go.mod +16 -16
- package/shim/lsp/go.sum +26 -26
- package/shim/parser/extra-shim.json +4 -4
- package/shim/parser/go.mod +5 -5
- package/shim/printer/go.mod +14 -14
- package/shim/printer/go.sum +22 -22
- package/shim/scanner/extra-shim.json +4 -4
- package/shim/scanner/go.mod +5 -5
- package/shim/transformers/go.mod +14 -14
- package/shim/transformers/go.sum +20 -20
- package/shim/tsoptions/extra-shim.json +4 -4
- package/shim/tsoptions/go.mod +5 -5
- package/shim/tspath/extra-shim.json +4 -4
- package/shim/tspath/go.mod +5 -5
- package/shim/vfs/cachedvfs/extra-shim.json +4 -4
- package/shim/vfs/cachedvfs/go.mod +5 -5
- package/shim/vfs/extra-shim.json +4 -4
- package/shim/vfs/go.mod +5 -5
- package/shim/vfs/osvfs/extra-shim.json +4 -4
- package/shim/vfs/osvfs/go.mod +5 -5
- package/src/TtscService.ts +8 -20
- package/src/compiler/internal/captureProcessOutput.ts +96 -0
- package/src/compiler/internal/compileProjectInMemory.ts +7 -7
- package/src/compiler/internal/residentCheckProcess.ts +1 -21
- package/src/compiler/internal/residentTransformProcess.ts +0 -42
- package/src/compiler/internal/spawnNative.ts +39 -18
- package/src/compiler/internal/startResidentTransform.ts +1 -12
- package/src/launcher/internal/prepareExecution.ts +297 -26
- package/src/launcher/internal/registerRuntimeHooks.ts +11 -2
- package/src/launcher/internal/runTtscserver.ts +4 -9
- package/src/launcher/internal/runTtsx.ts +2 -78
- package/src/launcher/internal/runtimeHooks.ts +385 -82
- package/src/plugin/internal/buildSourcePlugin.ts +36 -3
- package/src/plugin/internal/descriptorProcessFailure.ts +34 -65
- package/src/plugin/internal/loadProjectPlugins.ts +78 -39
- package/tools/gen_shims/go.mod +14 -14
- package/tools/gen_shims/go.sum +12 -12
- package/tools/shim_audit/go.mod +10 -10
- package/tools/shim_audit/go.sum +8 -8
package/cmd/ttscgraph/serve_answers_a_project_that_implements_its_own_ambient_declaration_test.go
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"bytes"
|
|
5
|
+
"encoding/json"
|
|
6
|
+
"path/filepath"
|
|
7
|
+
"strings"
|
|
8
|
+
"testing"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
// TestServeAnswersAProjectThatImplementsItsOwnAmbientDeclaration verifies shard
|
|
12
|
+
// assembly succeeds for a project that declares an ambient global in its own
|
|
13
|
+
// `.d.ts` and assigns the implementation elsewhere.
|
|
14
|
+
//
|
|
15
|
+
// Shard partition indexes edge sources by non-external node, and external nodes
|
|
16
|
+
// live in a non-source shard that may own no edges. An edge leaving one is
|
|
17
|
+
// therefore not a wrong fact but an unassemblable snapshot: the session refused
|
|
18
|
+
// the whole transaction with "edge source node is absent from shard facts", so
|
|
19
|
+
// every request failed before it ran while `dump`, which applies no such check,
|
|
20
|
+
// still emitted the graph.
|
|
21
|
+
//
|
|
22
|
+
// 1. Serve a project whose `src/globals.d.ts` declares `var patched` and whose
|
|
23
|
+
// `src/index.ts` assigns an arrow function to it.
|
|
24
|
+
// 2. Request one negotiated shard snapshot.
|
|
25
|
+
// 3. Assert the response carries a complete transaction and no error.
|
|
26
|
+
func TestServeAnswersAProjectThatImplementsItsOwnAmbientDeclaration(t *testing.T) {
|
|
27
|
+
root := t.TempDir()
|
|
28
|
+
writeGraphFile(t, filepath.Join(root, "tsconfig.json"), `{
|
|
29
|
+
"compilerOptions": { "target": "ES2022", "module": "commonjs", "strict": true },
|
|
30
|
+
"include": ["src"]
|
|
31
|
+
}`)
|
|
32
|
+
writeGraphFile(t, filepath.Join(root, "src", "globals.d.ts"), `declare global {
|
|
33
|
+
var patched: (message: string) => void;
|
|
34
|
+
}
|
|
35
|
+
export {};
|
|
36
|
+
`)
|
|
37
|
+
writeGraphFile(t, filepath.Join(root, "src", "index.ts"), `export function helper(): void {}
|
|
38
|
+
patched = (message: string): void => {
|
|
39
|
+
helper();
|
|
40
|
+
};
|
|
41
|
+
`)
|
|
42
|
+
|
|
43
|
+
input := strings.NewReader("{\"id\":1,\"graphSnapshotVersion\":1}\n")
|
|
44
|
+
var output bytes.Buffer
|
|
45
|
+
if code := serveSnapshots(input, &output, root, "tsconfig.json"); code != 0 {
|
|
46
|
+
t.Fatalf("serveSnapshots exited %d: %s", code, output.String())
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
var initial serveResponse
|
|
50
|
+
if err := json.NewDecoder(&output).Decode(&initial); err != nil {
|
|
51
|
+
t.Fatal(err)
|
|
52
|
+
}
|
|
53
|
+
if initial.Error != "" {
|
|
54
|
+
t.Fatalf("shard assembly refused a project that implements its own ambient declaration: %s", initial.Error)
|
|
55
|
+
}
|
|
56
|
+
if initial.Mode != serveModeInitial || !initial.Changed || initial.Dump != nil || initial.Snapshot == nil {
|
|
57
|
+
t.Fatalf("negotiated initial response: %#v", initial)
|
|
58
|
+
}
|
|
59
|
+
if len(initial.Snapshot.Manifest) == 0 ||
|
|
60
|
+
len(initial.Snapshot.Upserts) != len(initial.Snapshot.Manifest) ||
|
|
61
|
+
len(initial.Snapshot.Deletes) != 0 {
|
|
62
|
+
t.Fatalf(
|
|
63
|
+
"initial transaction is not complete: manifest=%d upserts=%d deletes=%d",
|
|
64
|
+
len(initial.Snapshot.Manifest),
|
|
65
|
+
len(initial.Snapshot.Upserts),
|
|
66
|
+
len(initial.Snapshot.Deletes),
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"bytes"
|
|
5
|
+
"errors"
|
|
6
|
+
"strings"
|
|
7
|
+
"testing"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
type rejectedServeWriter struct{}
|
|
11
|
+
|
|
12
|
+
func (rejectedServeWriter) Write([]byte) (int, error) {
|
|
13
|
+
return 0, errors.New("synthetic response write failure")
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// TestServeEarlyErrorEncodeFailureIsObservable proves a rejected early error
|
|
17
|
+
// response fails the stream without claiming that an unencoded response ran.
|
|
18
|
+
//
|
|
19
|
+
// 1. Reject protocol negotiation before a graph session is constructed.
|
|
20
|
+
// 2. Fail the response writer and require a nonzero server result.
|
|
21
|
+
// 3. Require the stderr cause while forbidding successful phase rows.
|
|
22
|
+
func TestServeEarlyErrorEncodeFailureIsObservable(t *testing.T) {
|
|
23
|
+
root := graphSessionFixture(t)
|
|
24
|
+
oldStderr := stderr
|
|
25
|
+
defer func() { stderr = oldStderr }()
|
|
26
|
+
t.Setenv(graphPhaseTraceEnvironment, "1")
|
|
27
|
+
|
|
28
|
+
var diagnostic bytes.Buffer
|
|
29
|
+
stderr = &diagnostic
|
|
30
|
+
request := "{\"id\":29,\"graphSnapshotVersion\":99}\n"
|
|
31
|
+
if code := serveSnapshots(strings.NewReader(request), rejectedServeWriter{}, root, "tsconfig.json"); code == 0 {
|
|
32
|
+
t.Fatal("failed early error encoding returned success")
|
|
33
|
+
}
|
|
34
|
+
if !strings.Contains(diagnostic.String(), "write serve response: synthetic response write failure") {
|
|
35
|
+
t.Fatalf("failed early error encoding hid its cause: %q", diagnostic.String())
|
|
36
|
+
}
|
|
37
|
+
if strings.Contains(diagnostic.String(), "ttscgraph-phase") {
|
|
38
|
+
t.Fatalf("failed early error encoding claimed successful phase rows: %q", diagnostic.String())
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"os"
|
|
5
|
+
"path/filepath"
|
|
6
|
+
"regexp"
|
|
7
|
+
"strconv"
|
|
8
|
+
"testing"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
// TestServeGraphSnapshotVersionMatchesTypeScriptClient verifies the native
|
|
12
|
+
// opt-in number and the resident client move together. The outer serve protocol
|
|
13
|
+
// stays backward compatible, so only this explicit negotiation field can stop
|
|
14
|
+
// an old full-dump client from misreading a shard response.
|
|
15
|
+
func TestServeGraphSnapshotVersionMatchesTypeScriptClient(t *testing.T) {
|
|
16
|
+
source := filepath.Join("..", "..", "..", "graph", "src", "model", "TtscGraphSession.ts")
|
|
17
|
+
content, err := os.ReadFile(source)
|
|
18
|
+
if err != nil {
|
|
19
|
+
t.Fatal(err)
|
|
20
|
+
}
|
|
21
|
+
match := regexp.MustCompile(`const GRAPH_SNAPSHOT_PROTOCOL_VERSION = ([0-9]+);`).FindSubmatch(content)
|
|
22
|
+
if len(match) != 2 {
|
|
23
|
+
t.Fatalf("could not find GRAPH_SNAPSHOT_PROTOCOL_VERSION in %s", source)
|
|
24
|
+
}
|
|
25
|
+
version, err := strconv.Atoi(string(match[1]))
|
|
26
|
+
if err != nil {
|
|
27
|
+
t.Fatal(err)
|
|
28
|
+
}
|
|
29
|
+
if version != graphSnapshotProtocolVersion {
|
|
30
|
+
t.Fatalf("TypeScript client graph snapshot protocol v%d, native server v%d", version, graphSnapshotProtocolVersion)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"bytes"
|
|
5
|
+
"strings"
|
|
6
|
+
"testing"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
// TestServePhaseTraceAccountsForLoadFailure proves addressed requests retain a
|
|
10
|
+
// complete timing record even when no resident compiler session can be built.
|
|
11
|
+
//
|
|
12
|
+
// 1. Request a missing tsconfig with phase tracing enabled.
|
|
13
|
+
// 2. Require a normal addressed error response rather than process failure.
|
|
14
|
+
// 3. Require all five payload-free phases under mode=error.
|
|
15
|
+
func TestServePhaseTraceAccountsForLoadFailure(t *testing.T) {
|
|
16
|
+
root := graphSessionFixture(t)
|
|
17
|
+
request := "{\"id\":23,\"graphSnapshotVersion\":1}\n"
|
|
18
|
+
oldStderr := stderr
|
|
19
|
+
defer func() { stderr = oldStderr }()
|
|
20
|
+
t.Setenv(graphPhaseTraceEnvironment, "1")
|
|
21
|
+
|
|
22
|
+
var output bytes.Buffer
|
|
23
|
+
var trace bytes.Buffer
|
|
24
|
+
stderr = &trace
|
|
25
|
+
if code := serveSnapshots(strings.NewReader(request), &output, root, "missing-tsconfig.json"); code != 0 {
|
|
26
|
+
t.Fatalf("failed load exited %d", code)
|
|
27
|
+
}
|
|
28
|
+
if !strings.Contains(output.String(), `"id":23`) || !strings.Contains(output.String(), `"mode":"error"`) {
|
|
29
|
+
t.Fatalf("failed load omitted its addressed error response: %q", output.String())
|
|
30
|
+
}
|
|
31
|
+
for _, phase := range []string{
|
|
32
|
+
"native-load",
|
|
33
|
+
"semantic-refresh",
|
|
34
|
+
"shard-export",
|
|
35
|
+
"encode",
|
|
36
|
+
"producer-total",
|
|
37
|
+
} {
|
|
38
|
+
if !strings.Contains(trace.String(), "owner=producer request=23 mode=error phase="+phase+" durationMs=") {
|
|
39
|
+
t.Fatalf("failed-load trace omitted %s: %q", phase, trace.String())
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if strings.Contains(trace.String(), root) || strings.Contains(trace.String(), "missing-tsconfig") || strings.Contains(trace.String(), "{\"") {
|
|
43
|
+
t.Fatalf("failed-load trace exposed request or project content: %q", trace.String())
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"bytes"
|
|
5
|
+
"strings"
|
|
6
|
+
"testing"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
// TestServePhaseTraceIsOptInAndPayloadFree proves the benchmark diagnostic is
|
|
10
|
+
// disabled by default and exposes timings without project or request content.
|
|
11
|
+
//
|
|
12
|
+
// 1. Run the same native shard request with tracing disabled and enabled.
|
|
13
|
+
// 2. Capture only the server diagnostic stream, not the response payload.
|
|
14
|
+
// 3. Require the five named phases and reject fixture paths and JSON bodies.
|
|
15
|
+
func TestServePhaseTraceIsOptInAndPayloadFree(t *testing.T) {
|
|
16
|
+
root := graphSessionFixture(t)
|
|
17
|
+
request := "{\"id\":17,\"graphSnapshotVersion\":1}\n"
|
|
18
|
+
oldStderr := stderr
|
|
19
|
+
defer func() { stderr = oldStderr }()
|
|
20
|
+
|
|
21
|
+
t.Setenv(graphPhaseTraceEnvironment, "")
|
|
22
|
+
var disabled bytes.Buffer
|
|
23
|
+
stderr = &disabled
|
|
24
|
+
if code := serveSnapshots(strings.NewReader(request), &bytes.Buffer{}, root, "tsconfig.json"); code != 0 {
|
|
25
|
+
t.Fatalf("disabled trace exited %d", code)
|
|
26
|
+
}
|
|
27
|
+
if disabled.Len() != 0 {
|
|
28
|
+
t.Fatalf("disabled trace wrote %q", disabled.String())
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
t.Setenv(graphPhaseTraceEnvironment, "1")
|
|
32
|
+
var enabled bytes.Buffer
|
|
33
|
+
stderr = &enabled
|
|
34
|
+
if code := serveSnapshots(strings.NewReader(request), &bytes.Buffer{}, root, "tsconfig.json"); code != 0 {
|
|
35
|
+
t.Fatalf("enabled trace exited %d", code)
|
|
36
|
+
}
|
|
37
|
+
trace := enabled.String()
|
|
38
|
+
for _, phase := range []string{
|
|
39
|
+
"native-load",
|
|
40
|
+
"semantic-refresh",
|
|
41
|
+
"shard-export",
|
|
42
|
+
"encode",
|
|
43
|
+
"producer-total",
|
|
44
|
+
} {
|
|
45
|
+
if !strings.Contains(trace, "owner=producer request=17 mode=initial phase="+phase+" durationMs=") {
|
|
46
|
+
t.Fatalf("trace omitted %s: %q", phase, trace)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if strings.Contains(trace, root) || strings.Contains(trace, "graphSnapshotVersion") || strings.Contains(trace, "{\"") {
|
|
50
|
+
t.Fatalf("trace exposed request or project content: %q", trace)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"bytes"
|
|
5
|
+
"encoding/json"
|
|
6
|
+
"strings"
|
|
7
|
+
"testing"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
// TestServeProtocolNegotiatesIncrementalShards pins the opt-in boundary between
|
|
11
|
+
// existing full-dump clients and the native shard protocol. A negotiated first
|
|
12
|
+
// response carries one complete manifest and transaction, while the following
|
|
13
|
+
// no-op carries neither a dump nor a shard payload.
|
|
14
|
+
func TestServeProtocolNegotiatesIncrementalShards(t *testing.T) {
|
|
15
|
+
root := graphSessionFixture(t)
|
|
16
|
+
input := strings.NewReader("{\"id\":1,\"graphSnapshotVersion\":1}\n{\"id\":2,\"graphSnapshotVersion\":1}\n")
|
|
17
|
+
var output bytes.Buffer
|
|
18
|
+
if code := serveSnapshots(input, &output, root, "tsconfig.json"); code != 0 {
|
|
19
|
+
t.Fatalf("serveSnapshots exited %d", code)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
decoder := json.NewDecoder(&output)
|
|
23
|
+
var initial serveResponse
|
|
24
|
+
var unchanged serveResponse
|
|
25
|
+
if err := decoder.Decode(&initial); err != nil {
|
|
26
|
+
t.Fatal(err)
|
|
27
|
+
}
|
|
28
|
+
if err := decoder.Decode(&unchanged); err != nil {
|
|
29
|
+
t.Fatal(err)
|
|
30
|
+
}
|
|
31
|
+
if initial.Error != "" || initial.Mode != serveModeInitial || !initial.Changed || initial.Dump != nil || initial.Snapshot == nil {
|
|
32
|
+
t.Fatalf("negotiated initial response: %#v", initial)
|
|
33
|
+
}
|
|
34
|
+
snapshot := initial.Snapshot
|
|
35
|
+
if snapshot.ProtocolVersion != graphSnapshotProtocolVersion || snapshot.Sequence != 1 || snapshot.BaseSequence != 0 || snapshot.BaseGeneration != "" {
|
|
36
|
+
t.Fatalf("initial transaction coordinates: %#v", snapshot)
|
|
37
|
+
}
|
|
38
|
+
if len(snapshot.Manifest) == 0 || len(snapshot.Upserts) != len(snapshot.Manifest) || len(snapshot.Deletes) != 0 {
|
|
39
|
+
t.Fatalf("initial transaction is not complete: manifest=%d upserts=%d deletes=%d", len(snapshot.Manifest), len(snapshot.Upserts), len(snapshot.Deletes))
|
|
40
|
+
}
|
|
41
|
+
if unchanged.Error != "" || unchanged.Mode != serveModeUnchanged || unchanged.Changed || unchanged.Dump != nil || unchanged.Snapshot != nil {
|
|
42
|
+
t.Fatalf("negotiated unchanged response: %#v", unchanged)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -39,12 +39,12 @@ func TestServeSessionReloadsCommonJSPackageEntryForESM(t *testing.T) {
|
|
|
39
39
|
t.Fatal(err)
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
writeGraphFile(t, filepath.Join(root, "node_modules", "fixture-package", "dist", "main.ts"), "export function winner(): void {}\
|
|
42
|
+
writeGraphFile(t, filepath.Join(root, "node_modules", "fixture-package", "dist", "main.ts"), "export function winner(): void {}\n")
|
|
43
43
|
dump, mode, changed, err := session.Snapshot()
|
|
44
44
|
if err != nil {
|
|
45
45
|
t.Fatal(err)
|
|
46
46
|
}
|
|
47
|
-
if dump == nil || mode != serveModeReload || !changed || !
|
|
47
|
+
if dump == nil || mode != serveModeReload || !changed || !hasDumpNodeAt(*dump, "winner", "node_modules/fixture-package/dist/main.ts") {
|
|
48
48
|
t.Fatalf("CommonJS package main.ts = dump:%v mode:%q changed:%v", dump != nil, mode, changed)
|
|
49
49
|
}
|
|
50
50
|
}
|
|
@@ -2,7 +2,10 @@ package main
|
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
4
|
"path/filepath"
|
|
5
|
+
"strings"
|
|
5
6
|
"testing"
|
|
7
|
+
|
|
8
|
+
"github.com/samchon/ttsc/packages/ttsc/internal/graph"
|
|
6
9
|
)
|
|
7
10
|
|
|
8
11
|
// TestServeSessionReloadsSupersedingModuleCandidates verifies a resident
|
|
@@ -15,13 +18,14 @@ import (
|
|
|
15
18
|
//
|
|
16
19
|
// 1. Load a project whose specifier resolves to the lower-priority target.
|
|
17
20
|
// 2. Create only the absent target that precedes it in that resolver's search.
|
|
18
|
-
// 3. Assert the resident snapshot reloads and
|
|
19
|
-
//
|
|
21
|
+
// 3. Assert the resident snapshot reloads and the imported symbol resolves to
|
|
22
|
+
// the newly preferred file. Package internals remain external boundaries.
|
|
20
23
|
func TestServeSessionReloadsSupersedingModuleCandidates(t *testing.T) {
|
|
21
24
|
cases := []struct {
|
|
22
|
-
name
|
|
23
|
-
setup
|
|
24
|
-
add
|
|
25
|
+
name string
|
|
26
|
+
setup func(*testing.T, string) string
|
|
27
|
+
add func(*testing.T, string)
|
|
28
|
+
wantDiagnostic string
|
|
25
29
|
}{
|
|
26
30
|
{
|
|
27
31
|
name: "relative_extension",
|
|
@@ -32,10 +36,10 @@ func TestServeSessionReloadsSupersedingModuleCandidates(t *testing.T) {
|
|
|
32
36
|
}`)
|
|
33
37
|
writeGraphFile(t, filepath.Join(root, "src", "main.ts"), "import { winner } from './value';\nexport function main(): void { winner(); }\n")
|
|
34
38
|
writeGraphFile(t, filepath.Join(root, "src", "value.js"), "export function winner() {}\n")
|
|
35
|
-
return "
|
|
39
|
+
return "src/value.ts"
|
|
36
40
|
},
|
|
37
41
|
add: func(t *testing.T, root string) {
|
|
38
|
-
writeGraphFile(t, filepath.Join(root, "src", "value.ts"), "export function winner(): void {}\
|
|
42
|
+
writeGraphFile(t, filepath.Join(root, "src", "value.ts"), "export function winner(): void {}\n")
|
|
39
43
|
},
|
|
40
44
|
},
|
|
41
45
|
{
|
|
@@ -52,10 +56,10 @@ func TestServeSessionReloadsSupersedingModuleCandidates(t *testing.T) {
|
|
|
52
56
|
}`)
|
|
53
57
|
writeGraphFile(t, filepath.Join(root, "src", "main.ts"), "import { winner } from '@generated/value';\nexport function main(): void { winner(); }\n")
|
|
54
58
|
writeGraphFile(t, filepath.Join(root, "fallback", "value.ts"), "export function winner(): void {}\n")
|
|
55
|
-
return "
|
|
59
|
+
return "first/value.ts"
|
|
56
60
|
},
|
|
57
61
|
add: func(t *testing.T, root string) {
|
|
58
|
-
writeGraphFile(t, filepath.Join(root, "first", "value.ts"), "export function winner(): void {}\
|
|
62
|
+
writeGraphFile(t, filepath.Join(root, "first", "value.ts"), "export function winner(): void {}\n")
|
|
59
63
|
},
|
|
60
64
|
},
|
|
61
65
|
{
|
|
@@ -71,10 +75,10 @@ func TestServeSessionReloadsSupersedingModuleCandidates(t *testing.T) {
|
|
|
71
75
|
}`)
|
|
72
76
|
writeGraphFile(t, filepath.Join(root, "src", "views", "main.ts"), "import { winner } from './template';\nexport function main(): void { winner(); }\n")
|
|
73
77
|
writeGraphFile(t, filepath.Join(root, "generated", "views", "template.ts"), "export function winner(): void {}\n")
|
|
74
|
-
return "
|
|
78
|
+
return "src/views/template.ts"
|
|
75
79
|
},
|
|
76
80
|
add: func(t *testing.T, root string) {
|
|
77
|
-
writeGraphFile(t, filepath.Join(root, "src", "views", "template.ts"), "export function winner(): void {}\
|
|
81
|
+
writeGraphFile(t, filepath.Join(root, "src", "views", "template.ts"), "export function winner(): void {}\n")
|
|
78
82
|
},
|
|
79
83
|
},
|
|
80
84
|
{
|
|
@@ -86,10 +90,10 @@ func TestServeSessionReloadsSupersedingModuleCandidates(t *testing.T) {
|
|
|
86
90
|
}`)
|
|
87
91
|
writeGraphFile(t, filepath.Join(root, "src", "deep", "main.ts"), "import { winner } from 'fixture-package';\nexport function main(): void { winner(); }\n")
|
|
88
92
|
writeGraphFile(t, filepath.Join(root, "node_modules", "fixture-package", "index.js"), "export function winner() {}\n")
|
|
89
|
-
return "
|
|
93
|
+
return "src/node_modules/fixture-package/index.ts"
|
|
90
94
|
},
|
|
91
95
|
add: func(t *testing.T, root string) {
|
|
92
|
-
writeGraphFile(t, filepath.Join(root, "src", "node_modules", "fixture-package", "index.ts"), "export function winner(): void {}\
|
|
96
|
+
writeGraphFile(t, filepath.Join(root, "src", "node_modules", "fixture-package", "index.ts"), "export function winner(): void {}\n")
|
|
93
97
|
},
|
|
94
98
|
},
|
|
95
99
|
{
|
|
@@ -113,8 +117,9 @@ func TestServeSessionReloadsSupersedingModuleCandidates(t *testing.T) {
|
|
|
113
117
|
return ""
|
|
114
118
|
},
|
|
115
119
|
add: func(t *testing.T, root string) {
|
|
116
|
-
writeGraphFile(t, filepath.Join(root, "node_modules", "fixture-package", "dist", "first.js"), "export function winner() {}\
|
|
120
|
+
writeGraphFile(t, filepath.Join(root, "node_modules", "fixture-package", "dist", "first.js"), "export function winner() {}\n")
|
|
117
121
|
},
|
|
122
|
+
wantDiagnostic: "node_modules/fixture-package/dist/first.js",
|
|
118
123
|
},
|
|
119
124
|
{
|
|
120
125
|
name: "conditional_package_exports",
|
|
@@ -139,7 +144,7 @@ func TestServeSessionReloadsSupersedingModuleCandidates(t *testing.T) {
|
|
|
139
144
|
}
|
|
140
145
|
}`)
|
|
141
146
|
writeGraphFile(t, filepath.Join(root, "node_modules", "fixture-package", "dist", "fallback.js"), "export function winner() {}\n")
|
|
142
|
-
return ""
|
|
147
|
+
return "node_modules/fixture-package/dist/types.d.ts"
|
|
143
148
|
},
|
|
144
149
|
add: func(t *testing.T, root string) {
|
|
145
150
|
writeGraphFile(t, filepath.Join(root, "node_modules", "fixture-package", "dist", "types.d.ts"), "export declare function winner(): void;\n")
|
|
@@ -168,7 +173,7 @@ func TestServeSessionReloadsSupersedingModuleCandidates(t *testing.T) {
|
|
|
168
173
|
}`)
|
|
169
174
|
writeGraphFile(t, filepath.Join(root, "src", "main.ts"), "import { winner } from '#feature';\nexport function main(): void { winner(); }\n")
|
|
170
175
|
writeGraphFile(t, filepath.Join(root, "generated", "fallback.js"), "export function winner() {}\n")
|
|
171
|
-
return ""
|
|
176
|
+
return "generated/types.d.ts"
|
|
172
177
|
},
|
|
173
178
|
add: func(t *testing.T, root string) {
|
|
174
179
|
writeGraphFile(t, filepath.Join(root, "generated", "types.d.ts"), "export declare function winner(): void;\n")
|
|
@@ -183,10 +188,10 @@ func TestServeSessionReloadsSupersedingModuleCandidates(t *testing.T) {
|
|
|
183
188
|
}`)
|
|
184
189
|
writeGraphFile(t, filepath.Join(root, "src", "main.ts"), "import { winner } from './feature';\nexport function main(): void { winner(); }\n")
|
|
185
190
|
writeGraphFile(t, filepath.Join(root, "src", "feature", "index.js"), "export function winner() {}\n")
|
|
186
|
-
return "
|
|
191
|
+
return "src/feature.js"
|
|
187
192
|
},
|
|
188
193
|
add: func(t *testing.T, root string) {
|
|
189
|
-
writeGraphFile(t, filepath.Join(root, "src", "feature.js"), "export function winner() {}\
|
|
194
|
+
writeGraphFile(t, filepath.Join(root, "src", "feature.js"), "export function winner() {}\n")
|
|
190
195
|
},
|
|
191
196
|
},
|
|
192
197
|
}
|
|
@@ -208,9 +213,30 @@ func TestServeSessionReloadsSupersedingModuleCandidates(t *testing.T) {
|
|
|
208
213
|
if err != nil {
|
|
209
214
|
t.Fatal(err)
|
|
210
215
|
}
|
|
211
|
-
if dump == nil || mode != serveModeReload || !changed ||
|
|
212
|
-
|
|
216
|
+
if dump == nil || mode != serveModeReload || !changed ||
|
|
217
|
+
(want != "" && !hasDumpNodeAt(*dump, "winner", want)) ||
|
|
218
|
+
(test.wantDiagnostic != "" && !hasDumpDiagnosticContaining(*dump, test.wantDiagnostic)) {
|
|
219
|
+
t.Fatalf("superseding candidate = dump:%v mode:%q changed:%v want-file:%q want-diagnostic:%q", dump != nil, mode, changed, want, test.wantDiagnostic)
|
|
213
220
|
}
|
|
214
221
|
})
|
|
215
222
|
}
|
|
216
223
|
}
|
|
224
|
+
|
|
225
|
+
func hasDumpNodeAt(dump graph.Dump, name, fileSuffix string) bool {
|
|
226
|
+
suffix := filepath.ToSlash(fileSuffix)
|
|
227
|
+
for _, node := range dump.Nodes {
|
|
228
|
+
if node.Name == name && strings.HasSuffix(filepath.ToSlash(node.File), suffix) {
|
|
229
|
+
return true
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return false
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
func hasDumpDiagnosticContaining(dump graph.Dump, fragment string) bool {
|
|
236
|
+
for _, diagnostic := range dump.Diagnostics {
|
|
237
|
+
if strings.Contains(filepath.ToSlash(diagnostic.Message), filepath.ToSlash(fragment)) {
|
|
238
|
+
return true
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return false
|
|
242
|
+
}
|
|
@@ -36,13 +36,13 @@ func TestServeSessionKeepsChangeDetectionLiveAfterInitialDumpError(t *testing.T)
|
|
|
36
36
|
if err == nil || !strings.Contains(err.Error(), "project root") {
|
|
37
37
|
t.Fatalf("initial dump error = %v, want absolute-root rejection", err)
|
|
38
38
|
}
|
|
39
|
-
if dump != nil || changed || !session.initialized || session.
|
|
39
|
+
if dump != nil || changed || !session.initialized || session.pending == nil || session.pending.mode != serveModeInitial {
|
|
40
40
|
t.Fatalf(
|
|
41
41
|
"failed initial state = dump:%v changed:%v initialized:%v pending:%q",
|
|
42
42
|
dump != nil,
|
|
43
43
|
changed,
|
|
44
44
|
session.initialized,
|
|
45
|
-
session.
|
|
45
|
+
session.pending.mode,
|
|
46
46
|
)
|
|
47
47
|
}
|
|
48
48
|
|
|
@@ -71,11 +71,11 @@ func TestServeSessionRetriesAPendingDumpBeforeUnchanged(t *testing.T) {
|
|
|
71
71
|
t.Fatalf("NewSession returned nil session (diagnostics: %v)", diags)
|
|
72
72
|
}
|
|
73
73
|
session := &graphSession{
|
|
74
|
-
cwd:
|
|
75
|
-
tsconfig:
|
|
76
|
-
compiler:
|
|
77
|
-
initialized:
|
|
78
|
-
|
|
74
|
+
cwd: root,
|
|
75
|
+
tsconfig: "tsconfig.json",
|
|
76
|
+
compiler: compiler,
|
|
77
|
+
initialized: true,
|
|
78
|
+
pending: &graphChange{mode: serveModeReload, full: true},
|
|
79
79
|
}
|
|
80
80
|
defer session.Close()
|
|
81
81
|
if err := session.captureState(); err != nil {
|
|
@@ -89,8 +89,8 @@ func TestServeSessionRetriesAPendingDumpBeforeUnchanged(t *testing.T) {
|
|
|
89
89
|
if dump == nil || mode != serveModeReload || !changed {
|
|
90
90
|
t.Fatalf("pending dump retry = dump:%v mode:%q changed:%v", dump != nil, mode, changed)
|
|
91
91
|
}
|
|
92
|
-
if session.
|
|
93
|
-
t.Fatalf("successful retry left pending
|
|
92
|
+
if session.pending != nil {
|
|
93
|
+
t.Fatalf("successful retry left pending change %#v", session.pending)
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
dump, mode, changed, err = session.Snapshot()
|