ttsc 0.18.3 → 0.19.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/README.md +5 -6
- package/cmd/graphbench/main.go +1 -1
- package/cmd/platform/main.go +1 -48
- package/cmd/ttsc/build_branches_test.go +5 -1
- package/cmd/ttsc/main.go +0 -50
- package/cmd/ttsc/main_alias_branches_test.go +6 -12
- package/cmd/ttscgraph/dump.go +13 -3
- package/cmd/ttscgraph/main.go +18 -12
- package/cmd/ttscgraph/run_help_version_and_bad_flags_exit_codes_test.go +23 -5
- package/cmd/ttscgraph/serve.go +863 -0
- package/cmd/ttscgraph/serve_protocol_rejects_invalid_request_line_test.go +43 -0
- package/cmd/ttscgraph/serve_protocol_retries_session_creation_test.go +83 -0
- package/cmd/ttscgraph/serve_protocol_reuses_session_test.go +35 -0
- package/cmd/ttscgraph/serve_session_applies_source_edit_incrementally_test.go +55 -0
- package/cmd/ttscgraph/serve_session_fails_closed_on_deleted_config_test.go +68 -0
- package/cmd/ttscgraph/serve_session_fails_closed_on_invalid_config_test.go +50 -0
- package/cmd/ttscgraph/serve_session_keeps_missing_literal_root_unchanged_test.go +46 -0
- package/cmd/ttscgraph/serve_session_rebuilds_import_graph_change_test.go +60 -0
- package/cmd/ttscgraph/serve_session_reloads_created_literal_root_test.go +44 -0
- package/cmd/ttscgraph/serve_session_reloads_extended_config_change_test.go +45 -0
- package/cmd/ttscgraph/serve_session_reloads_newly_resolved_conditional_export_test.go +60 -0
- package/cmd/ttscgraph/serve_session_reloads_newly_resolved_config_types_test.go +44 -0
- package/cmd/ttscgraph/serve_session_reloads_newly_resolved_excluded_import_test.go +62 -0
- package/cmd/ttscgraph/serve_session_reloads_newly_resolved_package_export_test.go +46 -0
- package/cmd/ttscgraph/serve_session_reloads_newly_resolved_package_import_test.go +46 -0
- package/cmd/ttscgraph/serve_session_reloads_newly_resolved_path_alias_test.go +47 -0
- package/cmd/ttscgraph/serve_session_reloads_newly_resolved_reference_path_test.go +42 -0
- package/cmd/ttscgraph/serve_session_reloads_newly_resolved_root_dirs_target_test.go +46 -0
- package/cmd/ttscgraph/serve_session_reloads_newly_resolved_type_reference_test.go +42 -0
- package/cmd/ttscgraph/serve_session_reloads_root_file_set_test.go +52 -0
- package/cmd/ttscgraph/serve_session_reloads_source_deleted_during_load_test.go +60 -0
- package/cmd/ttscgraph/serve_session_reloads_transitive_project_reference_test.go +55 -0
- package/cmd/ttscgraph/serve_session_reloads_when_program_plugin_linked_test.go +53 -0
- package/cmd/ttscgraph/serve_session_reuses_unchanged_preamble_source_test.go +45 -0
- package/cmd/ttscgraph/serve_session_reuses_unchanged_snapshot_test.go +52 -0
- package/cmd/ttscgraph/serve_session_revisits_source_edited_during_load_test.go +61 -0
- package/cmd/ttscgraph/serve_session_tolerates_os_invalid_resolution_candidate_test.go +56 -0
- package/cmd/ttscgraph/serve_session_tracks_all_module_specifier_forms_test.go +41 -0
- package/cmd/ttscgraph/serve_session_tracks_diamond_project_references_once_test.go +61 -0
- package/cmd/ttscserver/main.go +5 -3
- package/driver/lsp.go +13 -1
- package/driver/plugins.go +56 -5
- package/driver/program.go +25 -10
- package/driver/rewrite.go +381 -21
- package/driver/session.go +11 -3
- package/go.mod +1 -0
- package/internal/graph/build.go +297 -3
- package/internal/graph/build_records_a_node_per_top_level_declaration_test.go +16 -2
- package/internal/graph/diagnostics.go +5 -4
- package/internal/graph/dump.go +60 -4
- package/internal/graph/dump_is_a_function_of_the_source_test.go +71 -0
- package/internal/graph/dump_serializes_the_full_graph_test.go +16 -4
- package/internal/graph/edges.go +122 -11
- package/internal/graph/exports.go +74 -17
- package/internal/graph/graph.go +33 -1
- package/internal/graph/node_identity_is_position_invariant_test.go +4 -2
- package/internal/graph/resolve.go +24 -0
- package/internal/graphsymbols/provider.go +50 -14
- package/internal/lspserver/lsp_native_plugin_source.go +77 -23
- package/internal/lspserver/lsp_plugin.go +19 -2
- package/internal/lspserver/lsp_proxy.go +244 -52
- package/internal/lspserver/lsp_server.go +35 -27
- package/internal/lspserver/lsp_symbols.go +25 -16
- package/lib/TtscCompiler.d.ts +13 -2
- package/lib/TtscCompiler.js +30 -20
- package/lib/TtscCompiler.js.map +1 -1
- package/lib/TtscService.js +9 -7
- package/lib/TtscService.js.map +1 -1
- package/lib/compiler/internal/compileProjectInMemory.js +15 -1
- package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
- package/lib/compiler/internal/project/createNativeProjectContextArgs.d.ts +3 -0
- package/lib/compiler/internal/project/createNativeProjectContextArgs.js +14 -0
- package/lib/compiler/internal/project/createNativeProjectContextArgs.js.map +1 -0
- package/lib/compiler/internal/project/readProjectConfig.js +53 -4
- package/lib/compiler/internal/project/readProjectConfig.js.map +1 -1
- package/lib/compiler/internal/project/resolveProjectConfig.d.ts +9 -2
- package/lib/compiler/internal/project/resolveProjectConfig.js +45 -16
- package/lib/compiler/internal/project/resolveProjectConfig.js.map +1 -1
- package/lib/compiler/internal/residentTransformProcess.d.ts +16 -5
- package/lib/compiler/internal/residentTransformProcess.js +68 -20
- package/lib/compiler/internal/residentTransformProcess.js.map +1 -1
- package/lib/compiler/internal/runBuild.d.ts +18 -0
- package/lib/compiler/internal/runBuild.js +220 -24
- package/lib/compiler/internal/runBuild.js.map +1 -1
- package/lib/compiler/internal/runSingleFileEmit.js +7 -4
- package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
- package/lib/compiler/internal/sharedHostHelpers.d.ts +16 -0
- package/lib/compiler/internal/sharedHostHelpers.js +23 -0
- package/lib/compiler/internal/sharedHostHelpers.js.map +1 -1
- package/lib/compiler/internal/startResidentTransform.js +18 -1
- package/lib/compiler/internal/startResidentTransform.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.js +34 -8
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/flags/parser.d.ts +17 -0
- package/lib/flags/parser.js +11 -1
- package/lib/flags/parser.js.map +1 -1
- package/lib/flags/schema.js +7 -0
- package/lib/flags/schema.js.map +1 -1
- package/lib/launcher/internal/prepareExecution.js +21 -2
- package/lib/launcher/internal/prepareExecution.js.map +1 -1
- package/lib/launcher/internal/runTtsc.js +13 -53
- package/lib/launcher/internal/runTtsc.js.map +1 -1
- package/lib/launcher/internal/runTtscserver.js +11 -0
- package/lib/launcher/internal/runTtscserver.js.map +1 -1
- package/lib/launcher/internal/runTtsx.js +27 -11
- package/lib/launcher/internal/runTtsx.js.map +1 -1
- package/lib/launcher/internal/runtimeHooks.d.ts +81 -0
- package/lib/launcher/internal/runtimeHooks.js +632 -43
- package/lib/launcher/internal/runtimeHooks.js.map +1 -1
- package/lib/launcher/internal/servedSourceMap.d.ts +25 -0
- package/lib/launcher/internal/servedSourceMap.js +164 -0
- package/lib/launcher/internal/servedSourceMap.js.map +1 -0
- package/lib/plugin/internal/buildSourcePlugin.d.ts +146 -2
- package/lib/plugin/internal/buildSourcePlugin.js +651 -113
- package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/loadProjectPlugins.d.ts +7 -0
- package/lib/plugin/internal/loadProjectPlugins.js +33 -10
- package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
- package/lib/structures/ITtscCompilerContext.d.ts +16 -2
- package/lib/structures/ITtscCompilerResult.d.ts +8 -5
- package/lib/structures/ITtscPluginCapabilities.d.ts +8 -0
- package/lib/structures/ITtscPluginFactoryContext.d.ts +14 -0
- package/lib/structures/internal/ITtscParsedProjectConfig.d.ts +3 -0
- package/lib/structures/internal/ITtscProjectIdentity.d.ts +17 -0
- package/lib/structures/internal/ITtscProjectIdentity.js +3 -0
- package/lib/structures/internal/ITtscProjectIdentity.js.map +1 -0
- package/lib/structures/internal/TtscCommonOptions.d.ts +8 -0
- package/package.json +11 -8
- package/shim/ast/lint.go +10 -0
- package/shim/ast/shim.go +44 -0
- package/shim/checker/enums_gen.go +19 -0
- package/shim/checker/shim.go +130 -0
- package/shim/diagnosticwriter/lint.go +30 -3
- package/shim/printer/shim.go +22 -4
- package/shim/scanner/regexp.go +27 -0
- package/src/TtscCompiler.ts +29 -22
- package/src/TtscService.ts +15 -7
- package/src/compiler/internal/compileProjectInMemory.ts +18 -1
- package/src/compiler/internal/project/createNativeProjectContextArgs.ts +15 -0
- package/src/compiler/internal/project/readProjectConfig.ts +61 -5
- package/src/compiler/internal/project/resolveProjectConfig.ts +51 -21
- package/src/compiler/internal/residentTransformProcess.ts +95 -21
- package/src/compiler/internal/runBuild.ts +313 -32
- package/src/compiler/internal/runSingleFileEmit.ts +7 -4
- package/src/compiler/internal/sharedHostHelpers.ts +24 -0
- package/src/compiler/internal/startResidentTransform.ts +21 -1
- package/src/compiler/internal/transformProjectInMemory.ts +49 -6
- package/src/flags/parser.ts +28 -1
- package/src/flags/schema.ts +8 -0
- package/src/launcher/internal/prepareExecution.ts +22 -2
- package/src/launcher/internal/runTtsc.ts +13 -61
- package/src/launcher/internal/runTtscserver.ts +14 -0
- package/src/launcher/internal/runTtsx.ts +28 -13
- package/src/launcher/internal/runtimeHooks.ts +771 -53
- package/src/launcher/internal/servedSourceMap.ts +183 -0
- package/src/plugin/internal/buildSourcePlugin.ts +859 -122
- package/src/plugin/internal/loadProjectPlugins.ts +36 -6
- package/src/structures/ITtscCompilerContext.ts +17 -2
- package/src/structures/ITtscCompilerResult.ts +8 -5
- package/src/structures/ITtscPluginCapabilities.ts +9 -0
- package/src/structures/ITtscPluginFactoryContext.ts +15 -0
- package/src/structures/internal/ITtscParsedProjectConfig.ts +3 -0
- package/src/structures/internal/ITtscProjectIdentity.ts +17 -0
- package/src/structures/internal/TtscCommonOptions.ts +8 -0
- package/tools/shim_audit/baseline.json +16 -7
- package/tools/shim_audit/main.go +777 -71
- package/tools/shim_audit/main_test.go +28 -1
- package/tools/shim_audit/producer_exemptions_require_rationale_test.go +42 -0
- package/tools/shim_audit/producer_surface_includes_exposed_methods_test.go +154 -0
- package/tools/shim_audit/producer_surface_rejects_unproducible_reference_test.go +142 -0
- package/utility/host.go +46 -20
- package/utility/serve.go +1 -1
- package/shim/checker/signature_api_completeness.go +0 -58
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"os"
|
|
5
|
+
"path/filepath"
|
|
6
|
+
"testing"
|
|
7
|
+
|
|
8
|
+
"github.com/samchon/ttsc/packages/ttsc/driver"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
// TestServeSessionRevisitsSourceEditedDuringLoad verifies a source edited
|
|
12
|
+
// between compiler load and state capture is refreshed on the next snapshot.
|
|
13
|
+
//
|
|
14
|
+
// Hashing the raw disk bytes at capture time would bless content the resident
|
|
15
|
+
// program never parsed: disk and graph would disagree until an unrelated
|
|
16
|
+
// change. The capture must hash the resident text instead, so the next
|
|
17
|
+
// snapshot sees the disk mismatch and applies the missed edit.
|
|
18
|
+
//
|
|
19
|
+
// 1. Load a session, then rewrite the source before capturing state.
|
|
20
|
+
// 2. Take a snapshot and assert it refreshes to the on-disk declaration.
|
|
21
|
+
// 3. Take another snapshot and assert the session has converged (unchanged).
|
|
22
|
+
func TestServeSessionRevisitsSourceEditedDuringLoad(t *testing.T) {
|
|
23
|
+
root := graphSessionFixture(t)
|
|
24
|
+
compiler, diags, err := driver.NewSession(root, "tsconfig.json", driver.LoadProgramOptions{})
|
|
25
|
+
if err != nil {
|
|
26
|
+
t.Fatal(err)
|
|
27
|
+
}
|
|
28
|
+
if compiler == nil {
|
|
29
|
+
t.Fatalf("NewSession returned nil session (diagnostics: %v)", diags)
|
|
30
|
+
}
|
|
31
|
+
file := filepath.Join(root, "src", "index.ts")
|
|
32
|
+
if err := os.WriteFile(file, []byte("export class EditedDuringLoad {}\n"), 0o644); err != nil {
|
|
33
|
+
t.Fatal(err)
|
|
34
|
+
}
|
|
35
|
+
session := &graphSession{
|
|
36
|
+
cwd: root,
|
|
37
|
+
tsconfig: "tsconfig.json",
|
|
38
|
+
compiler: compiler,
|
|
39
|
+
initialized: true,
|
|
40
|
+
}
|
|
41
|
+
defer session.Close()
|
|
42
|
+
if err := session.captureState(); err != nil {
|
|
43
|
+
t.Fatal(err)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
dump, _, changed, err := session.Snapshot()
|
|
47
|
+
if err != nil {
|
|
48
|
+
t.Fatal(err)
|
|
49
|
+
}
|
|
50
|
+
if dump == nil || !changed || !hasDumpNode(*dump, "EditedDuringLoad") || hasDumpNode(*dump, "BeforeEdit") {
|
|
51
|
+
t.Fatalf("edited-during-load source was not refreshed: dump:%v changed:%v", dump != nil, changed)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
dump, mode, changed, err := session.Snapshot()
|
|
55
|
+
if err != nil {
|
|
56
|
+
t.Fatal(err)
|
|
57
|
+
}
|
|
58
|
+
if dump != nil || mode != "unchanged" || changed {
|
|
59
|
+
t.Fatalf("session did not converge after the missed edit: dump:%v mode:%q changed:%v", dump != nil, mode, changed)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"path/filepath"
|
|
5
|
+
"testing"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
// TestServeSessionToleratesOsInvalidResolutionCandidate verifies unresolved
|
|
9
|
+
// module specifiers that name OS-unparseable paths never break the session.
|
|
10
|
+
//
|
|
11
|
+
// Bundler-style specifiers (`./style.css?inline`) and URL imports (`data:`)
|
|
12
|
+
// stay unresolved in tsgo and become freshness candidates. On Windows those
|
|
13
|
+
// candidate paths fail os.ReadFile with ERROR_INVALID_NAME, which is neither
|
|
14
|
+
// ErrNotExist nor ErrInvalid; treating that as a snapshot error would make
|
|
15
|
+
// every graph request fail forever on such a project.
|
|
16
|
+
//
|
|
17
|
+
// 1. Open a session whose only root imports a query-suffixed CSS path and a
|
|
18
|
+
// data: URL.
|
|
19
|
+
// 2. Assert the session initializes and serves its initial dump.
|
|
20
|
+
// 3. Assert an untouched second snapshot reports unchanged.
|
|
21
|
+
func TestServeSessionToleratesOsInvalidResolutionCandidate(t *testing.T) {
|
|
22
|
+
root := t.TempDir()
|
|
23
|
+
writeGraphFile(t, filepath.Join(root, "tsconfig.json"), `{
|
|
24
|
+
"compilerOptions": { "target": "ES2022", "module": "commonjs" },
|
|
25
|
+
"files": ["src/index.ts"]
|
|
26
|
+
}`)
|
|
27
|
+
writeGraphFile(t, filepath.Join(root, "src", "index.ts"), `
|
|
28
|
+
// @ts-expect-error bundler-only specifier stays unresolved for tsgo
|
|
29
|
+
import styles from "./style.css?inline";
|
|
30
|
+
// @ts-expect-error data: URLs resolve at runtime, not through the compiler
|
|
31
|
+
import remote from "data:text/plain,hello";
|
|
32
|
+
export const value: unknown[] = [styles, remote];
|
|
33
|
+
`)
|
|
34
|
+
|
|
35
|
+
session, err := newGraphSession(root, "tsconfig.json")
|
|
36
|
+
if err != nil {
|
|
37
|
+
t.Fatal(err)
|
|
38
|
+
}
|
|
39
|
+
defer session.Close()
|
|
40
|
+
|
|
41
|
+
dump, mode, changed, err := session.Snapshot()
|
|
42
|
+
if err != nil {
|
|
43
|
+
t.Fatal(err)
|
|
44
|
+
}
|
|
45
|
+
if dump == nil || mode != "initial" || !changed {
|
|
46
|
+
t.Fatalf("initial snapshot = dump:%v mode:%q changed:%v", dump != nil, mode, changed)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
dump, mode, changed, err = session.Snapshot()
|
|
50
|
+
if err != nil {
|
|
51
|
+
t.Fatal(err)
|
|
52
|
+
}
|
|
53
|
+
if dump != nil || mode != "unchanged" || changed {
|
|
54
|
+
t.Fatalf("untouched snapshot = dump:%v mode:%q changed:%v", dump != nil, mode, changed)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"path/filepath"
|
|
5
|
+
"testing"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
// TestServeSessionTracksAllModuleSpecifierForms verifies that every TypeScript
|
|
9
|
+
// syntax which can trigger module resolution contributes missing-file
|
|
10
|
+
// candidates to the freshness snapshot.
|
|
11
|
+
func TestServeSessionTracksAllModuleSpecifierForms(t *testing.T) {
|
|
12
|
+
root := t.TempDir()
|
|
13
|
+
writeGraphFile(t, filepath.Join(root, "tsconfig.json"), `{
|
|
14
|
+
"compilerOptions": { "target": "ES2022", "module": "commonjs", "strict": true },
|
|
15
|
+
"files": ["src/index.ts"]
|
|
16
|
+
}`)
|
|
17
|
+
writeGraphFile(t, filepath.Join(root, "src", "index.ts"), `
|
|
18
|
+
import legacy = require("./legacy");
|
|
19
|
+
export { exported } from "./exported";
|
|
20
|
+
export type Deferred = import("./types").Deferred;
|
|
21
|
+
export const lazy = import("./lazy");
|
|
22
|
+
export const common = require("./common");
|
|
23
|
+
export const result = legacy();
|
|
24
|
+
`)
|
|
25
|
+
|
|
26
|
+
session, err := newGraphSession(root, "tsconfig.json")
|
|
27
|
+
if err != nil {
|
|
28
|
+
t.Fatal(err)
|
|
29
|
+
}
|
|
30
|
+
defer session.Close()
|
|
31
|
+
|
|
32
|
+
for _, name := range []string{"legacy.ts", "exported.ts", "types.ts", "lazy.ts", "common.ts"} {
|
|
33
|
+
candidate := filepath.Join(root, "src", name)
|
|
34
|
+
state, ok := session.auxStates[candidate]
|
|
35
|
+
if !ok {
|
|
36
|
+
t.Errorf("module candidate %s was not tracked", name)
|
|
37
|
+
} else if state.Exists {
|
|
38
|
+
t.Errorf("missing module candidate %s unexpectedly exists", name)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"path/filepath"
|
|
5
|
+
"testing"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
// TestServeSessionTracksDiamondProjectReferencesOnce verifies the config
|
|
9
|
+
// traversal terminates and deduplicates when two references share a child.
|
|
10
|
+
//
|
|
11
|
+
// A diamond (root -> left, root -> right, both -> shared) visits the shared
|
|
12
|
+
// config twice; without the seen-set the traversal would duplicate tracked
|
|
13
|
+
// state, and on a reference cycle it would never terminate. The shared leaf
|
|
14
|
+
// must appear in the freshness state exactly once and the session must stay
|
|
15
|
+
// stable across untouched snapshots.
|
|
16
|
+
//
|
|
17
|
+
// 1. Open a session over a diamond of project references.
|
|
18
|
+
// 2. Assert the shared leaf config is hash-tracked.
|
|
19
|
+
// 3. Assert an untouched snapshot reports unchanged.
|
|
20
|
+
func TestServeSessionTracksDiamondProjectReferencesOnce(t *testing.T) {
|
|
21
|
+
root := t.TempDir()
|
|
22
|
+
writeGraphFile(t, filepath.Join(root, "tsconfig.json"), `{
|
|
23
|
+
"files": ["src/index.ts"],
|
|
24
|
+
"references": [{ "path": "./left" }, { "path": "./right" }]
|
|
25
|
+
}`)
|
|
26
|
+
writeGraphFile(t, filepath.Join(root, "src", "index.ts"), "export const root = 1;\n")
|
|
27
|
+
for _, side := range []string{"left", "right"} {
|
|
28
|
+
writeGraphFile(t, filepath.Join(root, side, "tsconfig.json"), `{
|
|
29
|
+
"compilerOptions": { "composite": true },
|
|
30
|
+
"files": ["src/index.ts"],
|
|
31
|
+
"references": [{ "path": "../shared" }]
|
|
32
|
+
}`)
|
|
33
|
+
writeGraphFile(t, filepath.Join(root, side, "src", "index.ts"), "export const side = 1;\n")
|
|
34
|
+
}
|
|
35
|
+
writeGraphFile(t, filepath.Join(root, "shared", "tsconfig.json"), `{
|
|
36
|
+
"compilerOptions": { "composite": true },
|
|
37
|
+
"files": ["src/index.ts"]
|
|
38
|
+
}`)
|
|
39
|
+
writeGraphFile(t, filepath.Join(root, "shared", "src", "index.ts"), "export const shared = 1;\n")
|
|
40
|
+
|
|
41
|
+
session, err := newGraphSession(root, "tsconfig.json")
|
|
42
|
+
if err != nil {
|
|
43
|
+
t.Fatal(err)
|
|
44
|
+
}
|
|
45
|
+
defer session.Close()
|
|
46
|
+
sharedConfig := filepath.ToSlash(filepath.Join(root, "shared", "tsconfig.json"))
|
|
47
|
+
if _, ok := session.configHashes[sharedConfig]; !ok {
|
|
48
|
+
t.Fatalf("shared diamond config was not tracked: %s; got %#v", sharedConfig, session.configHashes)
|
|
49
|
+
}
|
|
50
|
+
if _, _, _, err := session.Snapshot(); err != nil {
|
|
51
|
+
t.Fatal(err)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
dump, mode, changed, err := session.Snapshot()
|
|
55
|
+
if err != nil {
|
|
56
|
+
t.Fatal(err)
|
|
57
|
+
}
|
|
58
|
+
if dump != nil || mode != "unchanged" || changed {
|
|
59
|
+
t.Fatalf("diamond references churned: dump:%v mode:%q changed:%v", dump != nil, mode, changed)
|
|
60
|
+
}
|
|
61
|
+
}
|
package/cmd/ttscserver/main.go
CHANGED
|
@@ -133,9 +133,11 @@ func runLSP(args []string) int {
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
// The SymbolProvider answers textDocument/documentSymbol and
|
|
136
|
-
// textDocument/references
|
|
137
|
-
//
|
|
138
|
-
// the
|
|
136
|
+
// textDocument/references from ttsc's compiler-backed code graph. tsgo
|
|
137
|
+
// implements both methods itself, so the proxy forwards to tsgo whenever it
|
|
138
|
+
// advertises the capability and consults this provider only as a fallback
|
|
139
|
+
// (tsgo did not advertise). It loads the program lazily on the first such
|
|
140
|
+
// request, so wiring it here adds no startup cost.
|
|
139
141
|
symbolProvider := graphsymbols.NewProvider(cwd, strings.TrimSpace(*tsconfigFlag))
|
|
140
142
|
|
|
141
143
|
err = runLSPServer(ctx, lspserver.LSPServerOptions{
|
package/driver/lsp.go
CHANGED
|
@@ -49,6 +49,12 @@ type LSPTextEdit = lspserver.LSPTextEdit
|
|
|
49
49
|
// LSPDocumentVersion is the driver-level alias for lspserver.LSPDocumentVersion.
|
|
50
50
|
type LSPDocumentVersion = lspserver.LSPDocumentVersion
|
|
51
51
|
|
|
52
|
+
// LSPProjectDiagnostics is the driver-level alias for a project publication.
|
|
53
|
+
type LSPProjectDiagnostics = lspserver.LSPProjectDiagnostics
|
|
54
|
+
|
|
55
|
+
// LSPDiagnosticsResult separates document and project plugin diagnostics.
|
|
56
|
+
type LSPDiagnosticsResult = lspserver.LSPDiagnosticsResult
|
|
57
|
+
|
|
52
58
|
// LSPSymbolKind is the driver-level alias for lspserver.LSPSymbolKind.
|
|
53
59
|
type LSPSymbolKind = lspserver.LSPSymbolKind
|
|
54
60
|
|
|
@@ -104,6 +110,12 @@ type LSPServerOptions = lspserver.LSPServerOptions
|
|
|
104
110
|
// LSPUpstreamRunner is the driver-level alias for lspserver.LSPUpstreamRunner.
|
|
105
111
|
type LSPUpstreamRunner = lspserver.LSPUpstreamRunner
|
|
106
112
|
|
|
113
|
+
// LSPUpstreamValidator is the driver-level alias for lspserver.LSPUpstreamValidator.
|
|
114
|
+
type LSPUpstreamValidator = lspserver.LSPUpstreamValidator
|
|
115
|
+
|
|
116
|
+
// LSPUpstream is the driver-level alias for lspserver.LSPUpstream.
|
|
117
|
+
type LSPUpstream = lspserver.LSPUpstream
|
|
118
|
+
|
|
107
119
|
// MaxFrameBytes is the maximum byte length of a single JSON-RPC frame
|
|
108
120
|
// the proxy will read without returning ErrFrameTooLarge.
|
|
109
121
|
const MaxFrameBytes = lspserver.MaxFrameBytes
|
|
@@ -118,6 +130,7 @@ var ErrFrameClosed = lspserver.ErrFrameClosed
|
|
|
118
130
|
var ErrFrameTooLarge = lspserver.ErrFrameTooLarge
|
|
119
131
|
var ErrInvalidJSONRPC = lspserver.ErrInvalidJSONRPC
|
|
120
132
|
var ErrLSPUpstreamPanic = lspserver.ErrLSPUpstreamPanic
|
|
133
|
+
var ErrLSPUpstreamRunnerRequired = lspserver.ErrLSPUpstreamRunnerRequired
|
|
121
134
|
var ErrLSPCwdRequired = lspserver.ErrLSPCwdRequired
|
|
122
135
|
var ErrLSPTsgoBinaryRequired = lspserver.ErrLSPTsgoBinaryRequired
|
|
123
136
|
|
|
@@ -128,7 +141,6 @@ var NewFrameReader = lspserver.NewFrameReader
|
|
|
128
141
|
var WriteFrame = lspserver.WriteFrame
|
|
129
142
|
var ParseEnvelope = lspserver.ParseEnvelope
|
|
130
143
|
var RecoverPanicAs = lspserver.RecoverPanicAs
|
|
131
|
-
var WithUpstreamRunnerForTest = lspserver.WithUpstreamRunnerForTest
|
|
132
144
|
var RunLSPServer = lspserver.RunLSPServer
|
|
133
145
|
var DenyNpmInstall = lspserver.DenyNpmInstall
|
|
134
146
|
|
package/driver/plugins.go
CHANGED
|
@@ -4,6 +4,7 @@ import (
|
|
|
4
4
|
"encoding/json"
|
|
5
5
|
"fmt"
|
|
6
6
|
"os"
|
|
7
|
+
"path/filepath"
|
|
7
8
|
"strings"
|
|
8
9
|
)
|
|
9
10
|
|
|
@@ -13,6 +14,40 @@ import (
|
|
|
13
14
|
// linked plugins are active.
|
|
14
15
|
const LinkedPluginsEnv = "TTSC_LINKED_PLUGINS_JSON"
|
|
15
16
|
|
|
17
|
+
// PluginConfigDirEnv is the environment variable through which the ttsc
|
|
18
|
+
// launcher passes the project root that plugin config-file discovery and
|
|
19
|
+
// relative "configFile" resolution anchor at. The launcher sets it on every
|
|
20
|
+
// native plugin spawn; it matters when the compiled tsconfig is a generated
|
|
21
|
+
// wrapper outside the project — e.g. @ttsc/unplugin writes a compiler-options
|
|
22
|
+
// overlay into the system temp directory that `extends` the real project
|
|
23
|
+
// config — where the tsconfig directory no longer identifies the project and
|
|
24
|
+
// an unanchored discovery walk would climb the temp tree instead. It rides
|
|
25
|
+
// the environment rather than a CLI flag so third-party native hosts with
|
|
26
|
+
// strict flag sets are unaffected and linked plugins running inside them
|
|
27
|
+
// still receive it.
|
|
28
|
+
const PluginConfigDirEnv = "TTSC_PLUGIN_CONFIG_DIR"
|
|
29
|
+
|
|
30
|
+
// PluginConfigBaseDir returns the directory where a plugin anchors its
|
|
31
|
+
// config-file discovery walk and resolves relative "configFile" paths.
|
|
32
|
+
// The explicit PluginConfigDirEnv channel wins when set; otherwise the
|
|
33
|
+
// tsconfig's directory is used, falling back to cwd when no tsconfig is set.
|
|
34
|
+
func PluginConfigBaseDir(cwd, tsconfigPath string) string {
|
|
35
|
+
if dir := strings.TrimSpace(os.Getenv(PluginConfigDirEnv)); dir != "" {
|
|
36
|
+
if !filepath.IsAbs(dir) && cwd != "" {
|
|
37
|
+
dir = filepath.Join(cwd, dir)
|
|
38
|
+
}
|
|
39
|
+
return filepath.Clean(dir)
|
|
40
|
+
}
|
|
41
|
+
if tsconfigPath != "" {
|
|
42
|
+
resolved := tsconfigPath
|
|
43
|
+
if !filepath.IsAbs(resolved) {
|
|
44
|
+
resolved = filepath.Join(cwd, resolved)
|
|
45
|
+
}
|
|
46
|
+
return filepath.Dir(resolved)
|
|
47
|
+
}
|
|
48
|
+
return cwd
|
|
49
|
+
}
|
|
50
|
+
|
|
16
51
|
// PluginEntry is the manifest shape ttsc passes to driver-level plugins.
|
|
17
52
|
type PluginEntry struct {
|
|
18
53
|
Config map[string]any `json:"config"`
|
|
@@ -42,11 +77,14 @@ type ProgramPlugin interface {
|
|
|
42
77
|
// EmitTransformPlugin contributes an emit-phase AST transformer. The returned
|
|
43
78
|
// PluginTransform runs first in tsgo's per-file emit chain, sharing the emit
|
|
44
79
|
// EmitContext with the builtin transformers, so a plugin returns AST instead of
|
|
45
|
-
// spliced text
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
// transform
|
|
80
|
+
// spliced text. For an injected import, allocate its binding once with
|
|
81
|
+
// ec.Factory.NewUniqueNameEx and the Optimistic | FileLevel flags, then reuse
|
|
82
|
+
// that identifier for every reference. NewGeneratedNameForNode on a string
|
|
83
|
+
// literal uses tsgo's temp-name channel and can be shadowed by downlevel temps.
|
|
84
|
+
// Tsgo's module-transform emits the require and aliases the references itself.
|
|
85
|
+
// This is the AST-integration replacement for the ProgramPlugin + RewriteSet
|
|
86
|
+
// text-splice model. A plugin whose returned transform is nil contributes
|
|
87
|
+
// nothing.
|
|
50
88
|
type EmitTransformPlugin interface {
|
|
51
89
|
EmitTransform(PluginContext) (PluginTransform, error)
|
|
52
90
|
}
|
|
@@ -130,6 +168,19 @@ func (state linkedPluginState) apply(prog *Program) error {
|
|
|
130
168
|
return nil
|
|
131
169
|
}
|
|
132
170
|
|
|
171
|
+
func (state linkedPluginState) hasProgramPlugins() bool {
|
|
172
|
+
for index := range state.entries {
|
|
173
|
+
plugin, ok := registeredPlugin(index)
|
|
174
|
+
if !ok {
|
|
175
|
+
continue
|
|
176
|
+
}
|
|
177
|
+
if _, ok := plugin.(ProgramPlugin); ok {
|
|
178
|
+
return true
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return false
|
|
182
|
+
}
|
|
183
|
+
|
|
133
184
|
// emitTransforms collects an emit-phase PluginTransform from every registered
|
|
134
185
|
// EmitTransformPlugin, in registration order. Entries that do not implement
|
|
135
186
|
// EmitTransformPlugin, or whose transform is nil, are skipped.
|
package/driver/program.go
CHANGED
|
@@ -81,15 +81,14 @@ func NewLintDiagnostic(
|
|
|
81
81
|
lint: lint,
|
|
82
82
|
}
|
|
83
83
|
if file != nil {
|
|
84
|
+
pos = lint.Pos()
|
|
84
85
|
d.File = file.FileName()
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
d.Column = col + 1
|
|
92
|
-
}
|
|
86
|
+
length := lint.Len()
|
|
87
|
+
d.Start = &pos
|
|
88
|
+
d.Length = &length
|
|
89
|
+
line, col := shimscanner.GetECMALineAndByteOffsetOfPosition(file, pos)
|
|
90
|
+
d.Line = line + 1
|
|
91
|
+
d.Column = col + 1
|
|
93
92
|
}
|
|
94
93
|
return d
|
|
95
94
|
}
|
|
@@ -456,10 +455,10 @@ type sourcePreambleFS struct {
|
|
|
456
455
|
|
|
457
456
|
func (fs sourcePreambleFS) ReadFile(filePath string) (string, bool) {
|
|
458
457
|
contents, ok := fs.FS.ReadFile(filePath)
|
|
459
|
-
if !ok
|
|
458
|
+
if !ok {
|
|
460
459
|
return contents, ok
|
|
461
460
|
}
|
|
462
|
-
return
|
|
461
|
+
return ApplySourcePreambleToFile(filePath, contents, fs.preamble), true
|
|
463
462
|
}
|
|
464
463
|
|
|
465
464
|
// isSourcePreambleTarget reports whether the preamble should be injected into
|
|
@@ -480,6 +479,15 @@ func isSourcePreambleTarget(filePath string) bool {
|
|
|
480
479
|
return false
|
|
481
480
|
}
|
|
482
481
|
|
|
482
|
+
// ApplySourcePreambleToFile applies a generated preamble only when filePath is
|
|
483
|
+
// a non-declaration TypeScript or JavaScript source, matching sourcePreambleFS.
|
|
484
|
+
func ApplySourcePreambleToFile(filePath string, text string, preamble string) string {
|
|
485
|
+
if !isSourcePreambleTarget(filePath) {
|
|
486
|
+
return text
|
|
487
|
+
}
|
|
488
|
+
return ApplySourcePreamble(text, preamble)
|
|
489
|
+
}
|
|
490
|
+
|
|
483
491
|
// ApplySourcePreamble inserts a generated source preamble without moving the
|
|
484
492
|
// file's BOM or hashbang away from the first bytes of the physical output.
|
|
485
493
|
func ApplySourcePreamble(text string, preamble string) string {
|
|
@@ -542,6 +550,13 @@ func (p *Program) ApplyLinkedPlugins() error {
|
|
|
542
550
|
return p.pluginsApplyErr
|
|
543
551
|
}
|
|
544
552
|
|
|
553
|
+
// HasLinkedProgramPlugins reports whether the loaded project has an active
|
|
554
|
+
// ProgramPlugin. Those hooks mutate parsed ASTs in place and therefore require
|
|
555
|
+
// a fresh Program rather than Session's incremental source replacement.
|
|
556
|
+
func (p *Program) HasLinkedProgramPlugins() bool {
|
|
557
|
+
return p != nil && p.plugins.hasProgramPlugins()
|
|
558
|
+
}
|
|
559
|
+
|
|
545
560
|
// Diagnostics returns project diagnostics that must block compilation or
|
|
546
561
|
// runtime execution before any JavaScript is emitted or evaluated.
|
|
547
562
|
func (p *Program) Diagnostics() []Diagnostic {
|