ttsc 0.16.3 → 0.16.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +96 -25
  2. package/cmd/graphbench/main.go +135 -0
  3. package/cmd/graphdump/main.go +60 -0
  4. package/cmd/ttscgraph/dump.go +69 -0
  5. package/cmd/ttscgraph/main.go +91 -0
  6. package/cmd/ttscgraph/run_dump_prints_the_graph_as_json_test.go +80 -0
  7. package/cmd/ttscgraph/run_help_version_and_bad_flags_exit_codes_test.go +75 -0
  8. package/cmd/utility-host/main.go +4 -1
  9. package/driver/overlay.go +64 -0
  10. package/driver/program.go +8 -1
  11. package/driver/session.go +85 -0
  12. package/internal/graph/build.go +330 -0
  13. package/internal/graph/build_records_a_node_per_top_level_declaration_test.go +96 -0
  14. package/internal/graph/decorators.go +122 -0
  15. package/internal/graph/decorators_capture_name_and_literal_arguments_test.go +98 -0
  16. package/internal/graph/diagnostics.go +23 -0
  17. package/internal/graph/dump.go +390 -0
  18. package/internal/graph/dump_evidence_skips_leading_trivia_test.go +92 -0
  19. package/internal/graph/dump_serializes_the_full_graph_test.go +146 -0
  20. package/internal/graph/edge_spans_point_to_resolved_usage_test.go +90 -0
  21. package/internal/graph/edges.go +538 -0
  22. package/internal/graph/edges_cover_class_level_references_test.go +93 -0
  23. package/internal/graph/enum_initializer_calls_are_edges_test.go +63 -0
  24. package/internal/graph/exports.go +60 -0
  25. package/internal/graph/file_diagnostics_match_tsgo_code_and_location_test.go +59 -0
  26. package/internal/graph/file_diagnostics_report_code_column_and_message_test.go +69 -0
  27. package/internal/graph/function_locals_do_not_collide_test.go +66 -0
  28. package/internal/graph/gitignore.go +51 -0
  29. package/internal/graph/graph.go +119 -0
  30. package/internal/graph/heritage_edges_cover_implements_and_interface_extends_test.go +76 -0
  31. package/internal/graph/heritage_edges_keep_extends_and_implements_to_same_base_test.go +61 -0
  32. package/internal/graph/heritage_edges_record_extends_versus_implements_origin_test.go +54 -0
  33. package/internal/graph/heritage_edges_traverse_barrels_and_stop_at_external_leaves_test.go +112 -0
  34. package/internal/graph/namespace_dotted_form_qualifies_deeply_test.go +60 -0
  35. package/internal/graph/namespace_members_become_qualified_nodes_and_edges_test.go +100 -0
  36. package/internal/graph/node_identity_is_position_invariant_test.go +84 -0
  37. package/internal/graph/node_modifiers_emit_union_strings_test.go +118 -0
  38. package/internal/graph/nodes_are_marked_exported_through_the_export_table_test.go +61 -0
  39. package/internal/graph/overload_implementation_replaces_signature_test.go +54 -0
  40. package/internal/graph/property_member_edges_remain_owner_visible_test.go +83 -0
  41. package/internal/graph/resolve.go +102 -0
  42. package/internal/graph/resolve_prefers_implementation_declaration_test.go +50 -0
  43. package/internal/graph/resolve_unwraps_barrel_reexport_to_real_declaration_test.go +230 -0
  44. package/internal/graph/type_ref_edges_cover_typeof_as_satisfies_test.go +79 -0
  45. package/internal/graph/type_ref_edges_resolve_named_types_across_files_test.go +52 -0
  46. package/internal/graph/value_access_edges_cover_properties_test.go +96 -0
  47. package/internal/graph/value_call_edges_cover_jsx_components_test.go +82 -0
  48. package/internal/graph/value_call_edges_cover_methods_and_constructors_test.go +70 -0
  49. package/internal/graph/value_call_edges_cover_variable_bound_callables_test.go +46 -0
  50. package/internal/graph/value_call_edges_do_not_double_record_invoked_member_access_test.go +65 -0
  51. package/internal/graph/value_call_edges_record_construct_versus_call_origin_test.go +75 -0
  52. package/internal/graph/value_call_edges_resolve_across_files_and_dedupe_test.go +55 -0
  53. package/internal/graph/value_call_edges_skip_self_and_unresolved_test.go +74 -0
  54. package/lib/TtscService.d.ts +55 -0
  55. package/lib/TtscService.js +93 -0
  56. package/lib/TtscService.js.map +1 -0
  57. package/lib/compiler/internal/residentTransformProcess.d.ts +47 -0
  58. package/lib/compiler/internal/residentTransformProcess.js +187 -0
  59. package/lib/compiler/internal/residentTransformProcess.js.map +1 -0
  60. package/lib/compiler/internal/startResidentTransform.d.ts +26 -0
  61. package/lib/compiler/internal/startResidentTransform.js +98 -0
  62. package/lib/compiler/internal/startResidentTransform.js.map +1 -0
  63. package/lib/index.d.ts +1 -0
  64. package/lib/index.js +1 -0
  65. package/lib/index.js.map +1 -1
  66. package/package.json +8 -8
  67. package/shim/ast/shim.go +6 -0
  68. package/shim/checker/shim.go +22 -12
  69. package/src/TtscService.ts +94 -0
  70. package/src/compiler/internal/residentTransformProcess.ts +216 -0
  71. package/src/compiler/internal/startResidentTransform.ts +126 -0
  72. package/src/index.ts +1 -0
  73. package/utility/host.go +8 -2
  74. package/utility/serve.go +158 -0
@@ -0,0 +1,92 @@
1
+ package graph
2
+
3
+ import (
4
+ "encoding/json"
5
+ "path/filepath"
6
+ "testing"
7
+
8
+ "github.com/samchon/ttsc/packages/ttsc/driver"
9
+ )
10
+
11
+ // TestDumpEvidenceSkipsLeadingTrivia verifies that a node's and an edge's
12
+ // evidence line/column point at the code, not the leading trivia, because
13
+ // tsgo's Pos() is the full-start (it includes the doc comment and indentation
14
+ // before a token).
15
+ //
16
+ // A declaration preceded by a doc comment and a call indented under its function
17
+ // are the two shapes that break a naive Pos->line/col: the node would land on the
18
+ // comment line and the edge column on the indentation. The dump skips leading
19
+ // whitespace and `//` / `/* */` comments first, so this pins both to the real
20
+ // token start.
21
+ //
22
+ // 1. Compile a fixture where `main` carries a block doc comment and calls
23
+ // `helper()` indented two spaces.
24
+ // 2. Build and marshal the dump.
25
+ // 3. Assert the `main` node's evidence starts on the `export function main`
26
+ // line, and the calls edge's evidence is the indented call's line and column.
27
+ func TestDumpEvidenceSkipsLeadingTrivia(t *testing.T) {
28
+ root := t.TempDir()
29
+ writeFile(t, filepath.Join(root, "tsconfig.json"), fixtureTSConfig)
30
+ writeFile(t, filepath.Join(root, "src", "main.ts"), `export function helper(): void {}
31
+ /**
32
+ * doc for main
33
+ */
34
+ export function main(): void {
35
+ helper();
36
+ }
37
+ `)
38
+
39
+ prog, diags, err := driver.LoadProgram(root, "tsconfig.json", driver.LoadProgramOptions{})
40
+ if err != nil {
41
+ t.Fatal(err)
42
+ }
43
+ if len(diags) != 0 {
44
+ t.Fatalf("unexpected diagnostics: %v", diags)
45
+ }
46
+ defer func() { _ = prog.Close() }()
47
+
48
+ g := Build(prog)
49
+ data, err := MarshalDump(g, root, "tsconfig.json", nil, SourceTexts(prog), false)
50
+ if err != nil {
51
+ t.Fatalf("MarshalDump: %v", err)
52
+ }
53
+ var dump Dump
54
+ if err := json.Unmarshal(data, &dump); err != nil {
55
+ t.Fatalf("dump is not valid JSON: %v", err)
56
+ }
57
+
58
+ // The `main` declaration starts on line 5 — past its three-line doc comment —
59
+ // not on line 2 where the comment (its leading trivia) begins.
60
+ var main *DumpNode
61
+ for i := range dump.Nodes {
62
+ if dump.Nodes[i].Kind == "function" && dump.Nodes[i].Name == "main" {
63
+ main = &dump.Nodes[i]
64
+ }
65
+ }
66
+ if main == nil || main.Evidence == nil {
67
+ t.Fatalf("missing main node with evidence: %+v", dump.Nodes)
68
+ }
69
+ if main.Evidence.StartLine != 5 {
70
+ t.Fatalf("main evidence startLine = %d, want 5 (past the doc comment)", main.Evidence.StartLine)
71
+ }
72
+
73
+ // The `helper()` call sits on line 6, indented two spaces, so the edge
74
+ // evidence is line 6 column 3 — not line 5 (where the trivia begins) or
75
+ // column 1 (the indentation).
76
+ var call *DumpEdge
77
+ for i := range dump.Edges {
78
+ e := &dump.Edges[i]
79
+ if e.Kind == "calls" && e.From == "src/main.ts#main:function" {
80
+ call = e
81
+ }
82
+ }
83
+ if call == nil || call.Evidence == nil {
84
+ t.Fatalf("missing calls edge with evidence: %+v", dump.Edges)
85
+ }
86
+ if call.Evidence.StartLine != 6 || call.Evidence.StartCol != 3 {
87
+ t.Fatalf(
88
+ "call evidence = line %d col %d, want line 6 col 3 (the indented call)",
89
+ call.Evidence.StartLine, call.Evidence.StartCol,
90
+ )
91
+ }
92
+ }
@@ -0,0 +1,146 @@
1
+ package graph
2
+
3
+ import (
4
+ "encoding/json"
5
+ "path/filepath"
6
+ "strings"
7
+ "testing"
8
+
9
+ "github.com/samchon/ttsc/packages/ttsc/driver"
10
+ )
11
+
12
+ // TestMarshalDumpSerializesTheFullGraph verifies that MarshalDump projects a
13
+ // built graph onto the IGraphDump wire contract the `ttscgraph dump` command
14
+ // prints and the @ttsc/graph engine loads: the project envelope, every node and
15
+ // edge, project-relative paths, line/col evidence, and the lowercase wire keys.
16
+ //
17
+ // The Node/Edge structs carry no json tags, so dump.go's projection is the only
18
+ // thing standing between the Go fields and the wire. A regression there would
19
+ // ship keys or kinds the engine does not read, so the key and kind assertions
20
+ // are load-bearing, not cosmetic.
21
+ //
22
+ // 1. Build a two-function fixture with one call, so the dump has a node set and
23
+ // a value-call edge.
24
+ // 2. Marshal it with source texts and assert the envelope, counts, and that the
25
+ // call edge maps to kind "calls" with a line/col evidence span.
26
+ // 3. Assert paths are project-relative, the wire keys are the lowercase json
27
+ // tags, every edge endpoint resolves to a dumped node, and --pretty indents.
28
+ func TestMarshalDumpSerializesTheFullGraph(t *testing.T) {
29
+ root := t.TempDir()
30
+ writeFile(t, filepath.Join(root, "tsconfig.json"), fixtureTSConfig)
31
+ writeFile(t, filepath.Join(root, "src", "main.ts"), `export function helper(): void {}
32
+ export function main(): void {
33
+ helper();
34
+ }
35
+ `)
36
+
37
+ prog, diags, err := driver.LoadProgram(root, "tsconfig.json", driver.LoadProgramOptions{})
38
+ if err != nil {
39
+ t.Fatal(err)
40
+ }
41
+ if len(diags) != 0 {
42
+ t.Fatalf("unexpected diagnostics: %v", diags)
43
+ }
44
+ defer func() { _ = prog.Close() }()
45
+
46
+ g := Build(prog)
47
+ sources := SourceTexts(prog)
48
+
49
+ data, err := MarshalDump(g, root, "tsconfig.json", nil, sources, false)
50
+ if err != nil {
51
+ t.Fatalf("MarshalDump: %v", err)
52
+ }
53
+
54
+ var dump Dump
55
+ if err := json.Unmarshal(data, &dump); err != nil {
56
+ t.Fatalf("dump is not valid JSON: %v\n%s", err, data)
57
+ }
58
+ if dump.Project != root || dump.Tsconfig != "tsconfig.json" {
59
+ t.Fatalf("project/tsconfig not echoed: %q / %q", dump.Project, dump.Tsconfig)
60
+ }
61
+ if len(dump.Nodes) != len(g.Nodes) {
62
+ t.Fatalf("dumped %d nodes, graph has %d", len(dump.Nodes), len(g.Nodes))
63
+ }
64
+ if len(dump.Edges) != len(g.Edges) {
65
+ t.Fatalf("dumped %d edges, graph has %d", len(dump.Edges), len(g.Edges))
66
+ }
67
+
68
+ // Locate the two function nodes by their wire shape, and confirm paths and ids
69
+ // are project-relative (no temp-dir prefix leaked).
70
+ byID := make(map[string]DumpNode, len(dump.Nodes))
71
+ var mainID, helperID string
72
+ for _, n := range dump.Nodes {
73
+ byID[n.ID] = n
74
+ if n.Kind == "function" && n.Name == "main" {
75
+ mainID = n.ID
76
+ }
77
+ if n.Kind == "function" && n.Name == "helper" {
78
+ helperID = n.ID
79
+ }
80
+ }
81
+ if mainID == "" || helperID == "" {
82
+ t.Fatalf("missing main/helper function nodes: %v", dump.Nodes)
83
+ }
84
+ if mainID != "src/main.ts#main:function" {
85
+ t.Fatalf("node id not project-relative: %q", mainID)
86
+ }
87
+ if byID[mainID].File != "src/main.ts" {
88
+ t.Fatalf("node file not project-relative: %q", byID[mainID].File)
89
+ }
90
+ if byID[mainID].Evidence == nil || byID[mainID].Evidence.StartLine == 0 {
91
+ t.Fatalf("main node missing line/col evidence: %+v", byID[mainID].Evidence)
92
+ }
93
+
94
+ // The main -> helper call maps to kind "calls" with a located evidence span.
95
+ var call *DumpEdge
96
+ for i := range dump.Edges {
97
+ e := &dump.Edges[i]
98
+ if e.From == mainID && e.To == helperID && e.Kind == "calls" {
99
+ call = e
100
+ }
101
+ }
102
+ if call == nil {
103
+ t.Fatalf("no calls edge main -> helper in dump:\n%s", data)
104
+ }
105
+ if call.Evidence == nil || call.Evidence.StartLine == 0 || call.Evidence.File != "src/main.ts" {
106
+ t.Fatalf("call edge missing project-relative line/col evidence: %+v", call.Evidence)
107
+ }
108
+
109
+ // Every edge endpoint resolves to a dumped node.
110
+ for _, e := range dump.Edges {
111
+ if _, ok := byID[e.From]; !ok {
112
+ t.Fatalf("edge from %q has no dumped node", e.From)
113
+ }
114
+ if _, ok := byID[e.To]; !ok {
115
+ t.Fatalf("edge to %q has no dumped node", e.To)
116
+ }
117
+ }
118
+
119
+ // The wire keys are the lowercase json tags, not the Go field names.
120
+ s := string(data)
121
+ for _, key := range []string{`"id":`, `"kind":`, `"name":`, `"file":`, `"external":`, `"from":`, `"to":`} {
122
+ if !strings.Contains(s, key) {
123
+ t.Fatalf("dump missing wire key %s:\n%s", key, s)
124
+ }
125
+ }
126
+ for _, leaked := range []string{`"ID":`, `"Kind":`, `"From":`, `"External":`} {
127
+ if strings.Contains(s, leaked) {
128
+ t.Fatalf("dump leaked Go field name %s:\n%s", leaked, s)
129
+ }
130
+ }
131
+ // The dump carries no ceremony keys: it is wholly checker-resolved, so it has
132
+ // no per-edge trust flags and no schema version to negotiate.
133
+ for _, gone := range []string{`"schemaVersion"`, `"provenance":`, `"confidence":`} {
134
+ if strings.Contains(s, gone) {
135
+ t.Fatalf("dump still emits removed key %s:\n%s", gone, s)
136
+ }
137
+ }
138
+
139
+ pretty, err := MarshalDump(g, root, "tsconfig.json", nil, sources, true)
140
+ if err != nil {
141
+ t.Fatalf("MarshalDump pretty: %v", err)
142
+ }
143
+ if !strings.Contains(string(pretty), "\n ") {
144
+ t.Fatalf("--pretty output is not indented:\n%s", pretty)
145
+ }
146
+ }
@@ -0,0 +1,90 @@
1
+ package graph
2
+
3
+ import (
4
+ "path/filepath"
5
+ "strings"
6
+ "testing"
7
+
8
+ "github.com/samchon/ttsc/packages/ttsc/driver"
9
+ )
10
+
11
+ // TestEdgeSpansPointToResolvedUsage verifies each checker-resolved edge keeps
12
+ // the source expression that produced it. The edge is still deduped by
13
+ // from/to/kind, but MCP needs the first concrete use span so a truncated
14
+ // declaration can reopen the right line without string-searching for a target
15
+ // name that may appear elsewhere.
16
+ func TestEdgeSpansPointToResolvedUsage(t *testing.T) {
17
+ root := t.TempDir()
18
+ writeFile(t, filepath.Join(root, "tsconfig.json"), fixtureTSConfig)
19
+ path := filepath.Join(root, "src", "main.ts")
20
+ writeFile(t, path, `export function helper(): number {
21
+ return 1;
22
+ }
23
+
24
+ export function caller(): number {
25
+ const helperShadow = 0;
26
+ return helper() + helperShadow;
27
+ }
28
+
29
+ export class Box {
30
+ value = 1;
31
+
32
+ read(): number {
33
+ return this.value;
34
+ }
35
+ }
36
+ `)
37
+
38
+ prog, diags, err := driver.LoadProgram(root, "tsconfig.json", driver.LoadProgramOptions{})
39
+ if err != nil {
40
+ t.Fatal(err)
41
+ }
42
+ if len(diags) != 0 {
43
+ t.Fatalf("unexpected diagnostics: %v", diags)
44
+ }
45
+ defer func() { _ = prog.Close() }()
46
+
47
+ graph := Build(prog)
48
+ caller := nodeByName(graph, "caller", NodeFunction)
49
+ helper := nodeByName(graph, "helper", NodeFunction)
50
+ read := nodeByName(graph, "Box.read", NodeMethod)
51
+ value := nodeByName(graph, "Box.value", NodeVariable)
52
+ if caller == nil || helper == nil || read == nil || value == nil {
53
+ t.Fatalf("missing fixture nodes: caller=%v helper=%v read=%v value=%v", caller, helper, read, value)
54
+ }
55
+ source := prog.SourceFile(caller.File).Text()
56
+
57
+ call := findEdge(graph, caller.ID, helper.ID, EdgeValueCall)
58
+ if call == nil {
59
+ t.Fatalf("missing caller -> helper value-call edge; edges: %v", graph.Edges)
60
+ }
61
+ if got := strings.TrimSpace(source[call.Pos:call.End]); got != "helper" {
62
+ t.Fatalf("value-call span = %q, want helper", got)
63
+ }
64
+
65
+ access := findEdge(graph, read.ID, value.ID, EdgeValueAccess)
66
+ if access == nil {
67
+ t.Fatalf("missing Box.read -> Box.value value-access edge; edges: %v", graph.Edges)
68
+ }
69
+ if got := source[access.Pos:access.End]; !strings.Contains(got, "this.value") {
70
+ t.Fatalf("value-access span = %q, want this.value expression", got)
71
+ }
72
+ }
73
+
74
+ func nodeByName(graph *Graph, name string, kind NodeKind) *Node {
75
+ for _, node := range graph.Nodes {
76
+ if node.Name == name && node.Kind == kind {
77
+ return node
78
+ }
79
+ }
80
+ return nil
81
+ }
82
+
83
+ func findEdge(graph *Graph, from, to string, kind EdgeKind) *Edge {
84
+ for _, edge := range graph.Edges {
85
+ if edge.From == from && edge.To == to && edge.Kind == kind {
86
+ return edge
87
+ }
88
+ }
89
+ return nil
90
+ }