ttsc 0.19.3 → 0.20.1

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 (170) hide show
  1. package/README.md +36 -34
  2. package/cmd/graphdump/main.go +2 -4
  3. package/cmd/ttsc/filter.go +12 -4
  4. package/cmd/ttsc/filter_resolves_flag_names_case_insensitively_test.go +53 -0
  5. package/cmd/ttsc/flags_gen.go +3 -3
  6. package/cmd/ttscgraph/dump.go +5 -7
  7. package/cmd/ttscgraph/run_dump_emits_only_checker_verified_member_relations_test.go +118 -0
  8. package/cmd/ttscgraph/serve.go +58 -308
  9. package/cmd/ttscgraph/serve_session_keeps_base_url_fallback_unchanged_test.go +49 -0
  10. package/cmd/ttscgraph/serve_session_keeps_esm_directory_candidate_unchanged_test.go +61 -0
  11. package/cmd/ttscgraph/serve_session_keeps_exports_blocked_file_candidates_unchanged_test.go +64 -0
  12. package/cmd/ttscgraph/serve_session_keeps_inactive_conditional_export_unchanged_test.go +66 -0
  13. package/cmd/ttscgraph/serve_session_keeps_lower_priority_module_candidate_unchanged_test.go +67 -0
  14. package/cmd/ttscgraph/serve_session_keeps_lower_priority_paths_pattern_unchanged_test.go +58 -0
  15. package/cmd/ttscgraph/serve_session_keeps_nonlongest_root_dirs_candidate_unchanged_test.go +54 -0
  16. package/cmd/ttscgraph/serve_session_reloads_commonjs_package_entry_for_esm_test.go +50 -0
  17. package/cmd/ttscgraph/serve_session_reloads_module_suffix_candidate_test.go +41 -0
  18. package/cmd/ttscgraph/serve_session_reloads_superseding_module_candidates_test.go +216 -0
  19. package/cmd/ttscgraph/serve_session_retries_failed_dump_test.go +103 -0
  20. package/driver/graph.go +12 -6
  21. package/driver/lsp.go +30 -0
  22. package/driver/program.go +37 -1
  23. package/driver/resolution_candidates.go +819 -0
  24. package/driver/windowsjunction/windowsjunction.go +40 -0
  25. package/go.mod +2 -0
  26. package/internal/graph/build.go +45 -11
  27. package/internal/graph/dump.go +276 -100
  28. package/internal/graph/dump_checkout_paths_are_stable_test.go +210 -0
  29. package/internal/graph/dump_diagnostics_ride_the_generation_that_built_it_test.go +9 -3
  30. package/internal/graph/dump_paths.go +172 -0
  31. package/internal/graph/dump_paths_are_portable_and_injective_test.go +93 -0
  32. package/internal/graph/dump_uses_ecma_line_terminators_test.go +87 -0
  33. package/internal/graph/duplicate_variable_object_members_keep_first_declaration_test.go +61 -0
  34. package/internal/graph/edges.go +208 -0
  35. package/internal/graph/graph.go +143 -5
  36. package/internal/graph/line_model.go +122 -0
  37. package/internal/graph/member_relation_edges_follow_checker_validity_test.go +85 -0
  38. package/internal/graph/member_relation_edges_preserve_checker_boundaries_test.go +191 -0
  39. package/internal/graph/member_relation_edges_reject_checker_invalid_pairs_test.go +119 -0
  40. package/internal/graph/node_ids_preserve_hash_bearing_components_test.go +41 -0
  41. package/internal/graph/node_modifiers_emit_union_strings_test.go +4 -1
  42. package/internal/graph/object_literal_members_ride_on_the_snapshot_test.go +192 -0
  43. package/internal/graph/object_member_signatures_preserve_literal_whitespace_test.go +67 -0
  44. package/internal/graph/object_members.go +229 -0
  45. package/internal/graph/provenance.go +88 -30
  46. package/internal/graph/source_texts_cover_every_resident_program_source_test.go +73 -0
  47. package/internal/graphsymbols/position_helpers_follow_ecma_line_terminators_test.go +66 -0
  48. package/internal/graphsymbols/provider.go +26 -91
  49. package/internal/lspserver/lsp_clean_didopen_refreshes_compiler_state_test.go +144 -0
  50. package/internal/lspserver/lsp_completion.go +109 -0
  51. package/internal/lspserver/lsp_completion_gate_never_refuses_a_matching_line_test.go +50 -0
  52. package/internal/lspserver/lsp_completion_hints_longest_trigger_wins_test.go +149 -0
  53. package/internal/lspserver/lsp_completion_hints_nearest_trigger_wins_test.go +37 -0
  54. package/internal/lspserver/lsp_completion_merges_into_upstream_response_test.go +149 -0
  55. package/internal/lspserver/lsp_completion_nearest_hint_replaces_nearest_filter_test.go +43 -0
  56. package/internal/lspserver/lsp_completion_preserves_completion_list_extensions_test.go +99 -0
  57. package/internal/lspserver/lsp_completion_refuses_hints_inside_a_string_literal_test.go +69 -0
  58. package/internal/lspserver/lsp_completion_replaces_full_filter_in_rank_order_test.go +85 -0
  59. package/internal/lspserver/lsp_completion_request.go +455 -0
  60. package/internal/lspserver/lsp_completion_scope.go +530 -0
  61. package/internal/lspserver/lsp_completion_scope_bench_test.go +41 -0
  62. package/internal/lspserver/lsp_completion_scope_classifies_regex_statement_and_operator_boundaries_test.go +39 -0
  63. package/internal/lspserver/lsp_completion_scope_ignores_jsdoc_bytes_in_literals_test.go +108 -0
  64. package/internal/lspserver/lsp_completion_scope_refuses_regex_hints_test.go +52 -0
  65. package/internal/lspserver/lsp_completion_trigger_uses_last_rune_test.go +24 -0
  66. package/internal/lspserver/lsp_deleted_watched_file_withdraws_plugin_diagnostics_test.go +110 -0
  67. package/internal/lspserver/lsp_didsave_keeps_the_incremental_changed_uri_path_test.go +78 -0
  68. package/internal/lspserver/lsp_hints_absence_is_not_an_error_test.go +46 -0
  69. package/internal/lspserver/lsp_hints_refresh_coalesces_concurrent_requests_test.go +82 -0
  70. package/internal/lspserver/lsp_hints_refresh_ignores_a_superseded_generation_test.go +40 -0
  71. package/internal/lspserver/lsp_hints_refresh_keeps_each_producer_isolated_test.go +64 -0
  72. package/internal/lspserver/lsp_hints_refresh_replaces_the_session_snapshot_test.go +66 -0
  73. package/internal/lspserver/lsp_hints_refresh_scheduled_by_editor_events_test.go +90 -0
  74. package/internal/lspserver/lsp_hints_refresh_serves_completion_while_running_test.go +91 -0
  75. package/internal/lspserver/lsp_index_byte_from_bounds_its_search_start_test.go +38 -0
  76. package/internal/lspserver/lsp_initialize_constrains_position_encoding_to_utf16_test.go +205 -0
  77. package/internal/lspserver/lsp_late_completion_trigger_is_reported_once_test.go +105 -0
  78. package/internal/lspserver/lsp_native_completion_hints_decode_flat_lint_wire_test.go +66 -0
  79. package/internal/lspserver/lsp_native_completion_hints_grouped_compatibility_boundary_test.go +60 -0
  80. package/internal/lspserver/lsp_native_plugin_source.go +315 -2
  81. package/internal/lspserver/lsp_native_resident.go +304 -0
  82. package/internal/lspserver/lsp_plugin.go +85 -8
  83. package/internal/lspserver/lsp_plugin_completion_resolve_stays_local_test.go +82 -0
  84. package/internal/lspserver/lsp_position_conversions_span_astral_and_combining_runes_test.go +119 -0
  85. package/internal/lspserver/lsp_proxy.go +601 -9
  86. package/internal/lspserver/lsp_refresh.go +70 -0
  87. package/internal/lspserver/lsp_resident_falls_back_when_serve_unsupported_test.go +43 -0
  88. package/internal/lspserver/lsp_resident_maps_verb_args_test.go +34 -0
  89. package/internal/lspserver/lsp_server.go +13 -1
  90. package/internal/lspserver/lsp_watched_file_changes_reach_compiler_caches_test.go +172 -0
  91. package/lib/TtscCompiler.d.ts +3 -1
  92. package/lib/TtscCompiler.js +5 -1
  93. package/lib/TtscCompiler.js.map +1 -1
  94. package/lib/TtscService.d.ts +13 -3
  95. package/lib/TtscService.js +6 -6
  96. package/lib/TtscService.js.map +1 -1
  97. package/lib/compiler/internal/project/readConfigJson.d.ts +30 -0
  98. package/lib/compiler/internal/project/readConfigJson.js +208 -0
  99. package/lib/compiler/internal/project/readConfigJson.js.map +1 -0
  100. package/lib/compiler/internal/project/readProjectConfig.js +53 -149
  101. package/lib/compiler/internal/project/readProjectConfig.js.map +1 -1
  102. package/lib/compiler/internal/residentTransformProcess.d.ts +15 -2
  103. package/lib/compiler/internal/residentTransformProcess.js +159 -39
  104. package/lib/compiler/internal/residentTransformProcess.js.map +1 -1
  105. package/lib/compiler/internal/runBuild.d.ts +6 -0
  106. package/lib/compiler/internal/runBuild.js +143 -44
  107. package/lib/compiler/internal/runBuild.js.map +1 -1
  108. package/lib/compiler/internal/startResidentTransform.d.ts +5 -1
  109. package/lib/compiler/internal/startResidentTransform.js +3 -1
  110. package/lib/compiler/internal/startResidentTransform.js.map +1 -1
  111. package/lib/compiler/internal/transformProjectInMemory.js +12 -2
  112. package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
  113. package/lib/flags/parser.d.ts +19 -0
  114. package/lib/flags/parser.js +78 -36
  115. package/lib/flags/parser.js.map +1 -1
  116. package/lib/flags/schema.d.ts +49 -11
  117. package/lib/flags/schema.js +94 -22
  118. package/lib/flags/schema.js.map +1 -1
  119. package/lib/internal/assertSafeExplicitCacheDirectory.d.ts +5 -0
  120. package/lib/internal/assertSafeExplicitCacheDirectory.js +26 -0
  121. package/lib/internal/assertSafeExplicitCacheDirectory.js.map +1 -0
  122. package/lib/launcher/internal/runTtsc.js +107 -69
  123. package/lib/launcher/internal/runTtsc.js.map +1 -1
  124. package/lib/launcher/internal/runTtsx.js +28 -41
  125. package/lib/launcher/internal/runTtsx.js.map +1 -1
  126. package/lib/launcher/internal/runtimeHooks.d.ts +15 -0
  127. package/lib/launcher/internal/runtimeHooks.js +18 -1
  128. package/lib/launcher/internal/runtimeHooks.js.map +1 -1
  129. package/lib/launcher/internal/watchTopology.d.ts +43 -0
  130. package/lib/launcher/internal/watchTopology.js +360 -0
  131. package/lib/launcher/internal/watchTopology.js.map +1 -0
  132. package/lib/plugin/internal/buildSourcePlugin.d.ts +14 -3
  133. package/lib/plugin/internal/buildSourcePlugin.js +247 -61
  134. package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
  135. package/lib/plugin/internal/loadProjectPlugins.js +63 -2
  136. package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
  137. package/lib/structures/ITtscCompilerTransformation.d.ts +16 -0
  138. package/lib/structures/internal/ITtscParsedProjectConfig.d.ts +2 -0
  139. package/package.json +8 -8
  140. package/shim/ast/shim.go +48 -3
  141. package/shim/astnav/go.mod +14 -0
  142. package/shim/astnav/go.sum +20 -0
  143. package/shim/astnav/shim.go +15 -0
  144. package/shim/checker/shim.go +100 -0
  145. package/shim/core/shim.go +47 -0
  146. package/shim/diagnosticwriter/lint.go +50 -0
  147. package/src/TtscCompiler.ts +5 -1
  148. package/src/TtscService.ts +37 -10
  149. package/src/compiler/internal/project/readConfigJson.ts +209 -0
  150. package/src/compiler/internal/project/readProjectConfig.ts +62 -158
  151. package/src/compiler/internal/residentTransformProcess.ts +197 -39
  152. package/src/compiler/internal/runBuild.ts +169 -47
  153. package/src/compiler/internal/startResidentTransform.ts +12 -1
  154. package/src/compiler/internal/transformProjectInMemory.ts +12 -1
  155. package/src/flags/parser.ts +113 -42
  156. package/src/flags/schema.ts +113 -31
  157. package/src/internal/assertSafeExplicitCacheDirectory.ts +29 -0
  158. package/src/launcher/internal/runTtsc.ts +117 -68
  159. package/src/launcher/internal/runTtsx.ts +29 -44
  160. package/src/launcher/internal/runtimeHooks.ts +30 -2
  161. package/src/launcher/internal/watchTopology.ts +466 -0
  162. package/src/plugin/internal/buildSourcePlugin.ts +326 -64
  163. package/src/plugin/internal/loadProjectPlugins.ts +80 -2
  164. package/src/structures/ITtscCompilerTransformation.ts +17 -0
  165. package/src/structures/internal/ITtscParsedProjectConfig.ts +2 -0
  166. package/tools/shim_audit/baseline.json +0 -3
  167. package/tools/shim_audit/main.go +42 -14
  168. package/tools/shim_audit/shim_dir_coverage_test.go +25 -0
  169. package/utility/flags_gen.go +3 -3
  170. package/utility/host.go +9 -3
package/README.md CHANGED
@@ -8,8 +8,8 @@ A `typescript-go` toolchain for compiler-powered plugins and type-safe execution
8
8
 
9
9
  - **`ttsc`**: build, check, and transform.
10
10
  - **`ttsx`**: execute TypeScript with type checking.
11
- - [**`@ttsc/lint`**](https://github.com/samchon/ttsc/tree/master/packages/lint): lint violations as compiler errors.
12
11
  - [**`@ttsc/graph`**](https://github.com/samchon/ttsc/tree/master/packages/graph): MCP code graph that reduces agent token usage.
12
+ - [**`@ttsc/lint`**](https://github.com/samchon/ttsc/tree/master/packages/lint): lint violations as compiler errors.
13
13
  - **plugin support**: compiler-powered libraries, such as `typia`.
14
14
 
15
15
  ## Setup
@@ -35,6 +35,33 @@ That covers the CLI. The integrations each have a short guide:
35
35
  - [`@ttsc/metro`](https://ttsc.dev/docs/setup/metro): React Native and Expo.
36
36
  - [`@ttsc/vscode`](https://ttsc.dev/docs/setup/vscode): live editor diagnostics.
37
37
 
38
+ ## Graph
39
+
40
+ Your coding agent answers from the compiler, spending roughly 90% fewer tokens.
41
+
42
+ `@ttsc/graph` is an MCP server that gives the agent a compiler-resolved graph of your project: what calls what, what a change would touch, and where to start reading. The agent asks the type checker instead of grepping and re-reading files.
43
+
44
+ Register it with your MCP client. For Claude Code, a `.mcp.json` in the project root:
45
+
46
+ ```bash
47
+ npm install -D ttsc @ttsc/graph typescript
48
+ ```
49
+
50
+ ```json
51
+ {
52
+ "mcpServers": {
53
+ "ttsc-graph": {
54
+ "command": "npx",
55
+ "args": ["-y", "@ttsc/graph"]
56
+ }
57
+ }
58
+ }
59
+ ```
60
+
61
+ On the agent-cost benchmark, Claude agents answer reading zero files, cutting tokens by roughly 90% and tool calls by 93% to 96%. The design and per-repository numbers are in the [Code Graph guide](https://ttsc.dev/docs/graph) and the [benchmark](https://ttsc.dev/docs/benchmark/graph).
62
+
63
+ ![Median tokens on the shared onboarding question, lower is better](https://ttsc.dev/benchmark/svg/graph-common-codex-gpt-5.6-sol.svg)
64
+
38
65
  ## Lint
39
66
 
40
67
  Lint and format at compiler speed: up to 800x faster than ESLint.
@@ -75,15 +102,17 @@ let total = count;
75
102
 
76
103
  ```text
77
104
  $ npx ttsc --noEmit
105
+ src/index.ts:1:1 - error TS11966: [no-var] Unexpected var, use let or const instead.
106
+
107
+ 1 var count = 3;
108
+ ~~~
109
+
78
110
  src/index.ts:2:5 - error TS17397: [prefer-const] Use const instead of let.
79
111
 
80
112
  2 let total = count;
81
- ~~~~~~~~~~~~~
113
+ ~~~~~
82
114
 
83
- src/index.ts:1:1 - error TS11966: [no-var] Unexpected var, use let or const instead.
84
-
85
- 1 var count = 3;
86
- ~~~~~~~~~~~~~~
115
+ Found 2 errors in the same file, starting at: src/index.ts:1
87
116
  ```
88
117
 
89
118
  Clean the project in place:
@@ -95,33 +124,6 @@ npx ttsc format # format edits only, never changes behavior
95
124
 
96
125
  The rule catalog and every `format` key are in the [Lint & Format guide](https://ttsc.dev/docs/lint).
97
126
 
98
- ## Graph
99
-
100
- Your coding agent answers from the compiler, spending roughly 90% fewer tokens.
101
-
102
- `@ttsc/graph` is an MCP server that gives the agent a compiler-resolved graph of your project: what calls what, what a change would touch, and where to start reading. The agent asks the type checker instead of grepping and re-reading files.
103
-
104
- Register it with your MCP client. For Claude Code, a `.mcp.json` in the project root:
105
-
106
- ```bash
107
- npm install -D ttsc @ttsc/graph typescript
108
- ```
109
-
110
- ```json
111
- {
112
- "mcpServers": {
113
- "ttsc-graph": {
114
- "command": "npx",
115
- "args": ["-y", "@ttsc/graph"]
116
- }
117
- }
118
- }
119
- ```
120
-
121
- On the agent-cost benchmark, Claude agents answer reading zero files, cutting tokens by roughly 90% and tool calls by 93% to 96%. The design and per-repository numbers are in the [Code Graph guide](https://ttsc.dev/docs/graph) and the [benchmark](https://ttsc.dev/docs/benchmark/graph).
122
-
123
- ![Median tokens on the shared onboarding question, lower is better](https://ttsc.dev/benchmark/svg/graph-common-codex-gpt-5.6-sol.svg)
124
-
125
127
  ## Plugins
126
128
 
127
129
  A plugin hooks the compile to add checks, transforms, or type-driven code generation, all driven by the types the checker has already resolved. It runs on every `ttsc` build and `ttsx` run, with no extra step.
@@ -146,8 +148,8 @@ export const isStringArray = (() => {
146
148
  Utility plugins shipped in this repository:
147
149
 
148
150
  - [`@ttsc/banner`](https://github.com/samchon/ttsc/tree/master/packages/banner): adds `@packageDocumentation` JSDoc banners.
149
- - [`@ttsc/lint`](https://github.com/samchon/ttsc/tree/master/packages/lint): lints and formats TypeScript source.
150
151
  - [`@ttsc/graph`](https://github.com/samchon/ttsc/tree/master/packages/graph): MCP server exposing a checker-resolved code graph to coding agents.
152
+ - [`@ttsc/lint`](https://github.com/samchon/ttsc/tree/master/packages/lint): lints and formats TypeScript source.
151
153
  - [`@ttsc/paths`](https://github.com/samchon/ttsc/tree/master/packages/paths): rewrites source path aliases so JS and declaration emit receive relative imports.
152
154
  - [`@ttsc/strip`](https://github.com/samchon/ttsc/tree/master/packages/strip): removes configured calls and `debugger` statements.
153
155
  - [`@ttsc/unplugin`](https://github.com/samchon/ttsc/tree/master/packages/unplugin): runs `ttsc` plugins inside bundlers supported by `unplugin`.
@@ -28,9 +28,8 @@ func run() int {
28
28
  flag.Parse()
29
29
 
30
30
  // Resolve the project root the same way LoadProgram does (absolute, then
31
- // tsgo-normalized) so it shares the node file paths' drive-letter case on
32
- // Windows; otherwise the dump's prefix-based relativization would miss and
33
- // leave every path absolute.
31
+ // tsgo-normalized) so the schema-v6 mapper receives the same canonical root
32
+ // grammar and drive-letter case as the compiler's source paths.
34
33
  root := *cwd
35
34
  if abs, err := filepath.Abs(root); err == nil {
36
35
  root = abs
@@ -60,7 +59,6 @@ func run() int {
60
59
  // `ttscgraph dump` is the one that proves the whole contract.
61
60
  data, err := graph.MarshalDump(g, root, *tsconfig, ignored, texts, graph.DumpOrigin{
62
61
  Provenance: graph.NewProvenance(
63
- root,
64
62
  // No version: this tool is built from the tree on demand and never
65
63
  // stamped, and an invented one would be worse than an absent one.
66
64
  graph.Producer{Tool: "graphdump", Typescript: graph.TypescriptVersion()},
@@ -59,12 +59,20 @@ func filterHostArgs(args []string) []string {
59
59
  return filtered
60
60
  }
61
61
 
62
- // splitFlagName strips the leading `--` from a flag argument and reports
63
- // whether the argument carries an inline value (`--foo=value`).
62
+ // splitFlagName strips the leading `--` from a flag argument, lower-cases the
63
+ // result, and reports whether the argument carries an inline value
64
+ // (`--foo=value`).
65
+ //
66
+ // Lower-casing is the same normalization `normalizeFlagToken` in
67
+ // `packages/ttsc/src/flags/schema.ts` applies, and the generated
68
+ // `HostFlagAllowList` keys are produced by it. TypeScript's option parser
69
+ // matches option names case-insensitively, so keying this lookup on the exact
70
+ // spelling would make the Go layer stop recognising a flag the launcher and the
71
+ // compiler both resolve.
64
72
  func splitFlagName(arg string) (string, bool) {
65
73
  name := strings.TrimPrefix(arg, "--")
66
74
  if i := strings.IndexByte(name, '='); i != -1 {
67
- return name[:i], true
75
+ return strings.ToLower(name[:i]), true
68
76
  }
69
- return name, false
77
+ return strings.ToLower(name), false
70
78
  }
@@ -0,0 +1,53 @@
1
+ package main
2
+
3
+ import (
4
+ "reflect"
5
+ "testing"
6
+ )
7
+
8
+ // TestFilterHostArgsResolvesFlagNamesCaseInsensitively verifies the host
9
+ // allow-list lookup applies the same flag-name normalization the schema uses
10
+ // when it generates that allow-list.
11
+ //
12
+ // TypeScript's option parser matches option names case-insensitively, and
13
+ // `normalizeFlagToken` in `packages/ttsc/src/flags/schema.ts` is the one
14
+ // normalization every layer keys off — including `buildGoAllowList`, whose
15
+ // output is `flags_gen.go`. Keying this lookup on the exact spelling while the
16
+ // generated keys are normalized would recreate the split-brain one layer
17
+ // further down: a flag the launcher and the compiler both resolve would be
18
+ // dropped here, silently taking the following token with it.
19
+ //
20
+ // 1. A case-variant known flag survives with its value.
21
+ // 2. A case-variant boolean known flag survives and does not eat the next token.
22
+ // 3. An unknown flag is still dropped in every casing, with its value.
23
+ func TestFilterHostArgsResolvesFlagNamesCaseInsensitively(t *testing.T) {
24
+ cases := []struct {
25
+ name string
26
+ in []string
27
+ want []string
28
+ }{
29
+ {
30
+ name: "keeps a case-variant value flag with its value",
31
+ in: []string{"--TSCONFIG", "tsconfig.json", "--CWD=."},
32
+ want: []string{"--TSCONFIG", "tsconfig.json", "--CWD=."},
33
+ },
34
+ {
35
+ name: "keeps a case-variant boolean flag without eating the next token",
36
+ in: []string{"--NOEMIT", "--tsconfig", "tsconfig.json"},
37
+ want: []string{"--NOEMIT", "--tsconfig", "tsconfig.json"},
38
+ },
39
+ {
40
+ name: "still drops an unknown flag in any casing",
41
+ in: []string{"--tsconfig=tsconfig.json", "--sTrIcT", "true"},
42
+ want: []string{"--tsconfig=tsconfig.json"},
43
+ },
44
+ }
45
+ for _, tc := range cases {
46
+ t.Run(tc.name, func(t *testing.T) {
47
+ got := filterHostArgs(tc.in)
48
+ if !reflect.DeepEqual(got, tc.want) {
49
+ t.Fatalf("filterHostArgs(%v):\n want %v\n got %v", tc.in, tc.want, got)
50
+ }
51
+ })
52
+ }
53
+ }
@@ -17,13 +17,13 @@ var HostFlagAllowList = map[string]bool{
17
17
  "cwd": true,
18
18
  "emit": false,
19
19
  "manifest": true,
20
- "noEmit": false,
21
- "outDir": true,
20
+ "noemit": false,
21
+ "outdir": true,
22
22
  "p": true,
23
23
  "plugins-json": true,
24
24
  "project": true,
25
25
  "quiet": false,
26
- "singleThreaded": false,
26
+ "singlethreaded": false,
27
27
  "tsconfig": true,
28
28
  "tsgo-args": true,
29
29
  "verbose": false,
@@ -37,9 +37,8 @@ func runDump(args []string) int {
37
37
  cwd = resolved
38
38
  }
39
39
  // Resolve the project root the same way LoadProgram does (absolute, then
40
- // tsgo-normalized) so it shares the node file paths' drive-letter case on
41
- // Windows; otherwise the dump's prefix-based relativization would miss and
42
- // leave every path absolute.
40
+ // tsgo-normalized) so the schema-v6 mapper receives the same canonical root
41
+ // grammar and drive-letter case as the compiler's source paths.
43
42
  if abs, err := filepath.Abs(cwd); err == nil {
44
43
  cwd = abs
45
44
  }
@@ -60,7 +59,7 @@ func runDump(args []string) int {
60
59
  g := graph.Build(prog)
61
60
  ignored := graph.GitIgnoredFiles(cwd, g)
62
61
  texts := graph.SourceTexts(prog)
63
- origin, err := dumpOrigin(prog, cwd, texts)
62
+ origin, err := dumpOrigin(prog, texts)
64
63
  if err != nil {
65
64
  fmt.Fprintf(stderr, "ttscgraph: %v\n", err)
66
65
  return 1
@@ -90,7 +89,7 @@ func runDump(args []string) int {
90
89
  // saw the project, so it carries the same provenance a served snapshot does:
91
90
  // without it the file is a pile of facts with no way to tell which program, or
92
91
  // which day, they describe.
93
- func dumpOrigin(prog *driver.Program, cwd string, texts map[string]string) (graph.DumpOrigin, error) {
92
+ func dumpOrigin(prog *driver.Program, texts map[string]string) (graph.DumpOrigin, error) {
94
93
  configs, err := parsedConfigs(prog)
95
94
  if err != nil {
96
95
  return graph.DumpOrigin{}, err
@@ -105,7 +104,6 @@ func dumpOrigin(prog *driver.Program, cwd string, texts map[string]string) (grap
105
104
  }
106
105
  return graph.DumpOrigin{
107
106
  Provenance: graph.NewProvenance(
108
- cwd,
109
107
  serveProducer(),
110
108
  fullSnapshotCapabilities,
111
109
  fileDigests(configHashes),
@@ -113,6 +111,6 @@ func dumpOrigin(prog *driver.Program, cwd string, texts map[string]string) (grap
113
111
  texts,
114
112
  diskDigests,
115
113
  ),
116
- Diagnostics: graph.NewDiagnostics(prog, cwd),
114
+ Diagnostics: graph.NewDiagnostics(prog),
117
115
  }, nil
118
116
  }
@@ -0,0 +1,118 @@
1
+ package main
2
+
3
+ import (
4
+ "bytes"
5
+ "encoding/json"
6
+ "path/filepath"
7
+ "testing"
8
+
9
+ "github.com/samchon/ttsc/packages/ttsc/internal/graph"
10
+ )
11
+
12
+ // TestRunDumpEmitsOnlyCheckerVerifiedMemberRelations verifies the shipped dump
13
+ // command serializes native member facts and does not revive a rejected pair.
14
+ //
15
+ // The graph reader no longer synthesizes member edges from equal names, so the
16
+ // command boundary must prove all three layers together: compiler diagnostics,
17
+ // native pair validation, and the public implements/overrides wire vocabulary.
18
+ //
19
+ // 1. Dump a program with one valid and one TS2416-invalid implementation.
20
+ // 2. Locate the container and member nodes in the serialized document.
21
+ // 3. Require the valid member edge and its evidence, reject the invalid edge,
22
+ // and ensure the internal native edge kind never reaches JSON.
23
+ func TestRunDumpEmitsOnlyCheckerVerifiedMemberRelations(t *testing.T) {
24
+ root := t.TempDir()
25
+ writeGraphFile(t, filepath.Join(root, "tsconfig.json"), `{
26
+ "compilerOptions": {
27
+ "target": "ES2022",
28
+ "module": "commonjs",
29
+ "strict": true,
30
+ "rootDir": "src",
31
+ "outDir": "dist"
32
+ },
33
+ "files": ["src/main.ts"]
34
+ }
35
+ `)
36
+ writeGraphFile(t, filepath.Join(root, "src", "main.ts"), `export interface Contract {
37
+ execute(input: number): void;
38
+ }
39
+ export class Good implements Contract {
40
+ execute(input: number): void {}
41
+ }
42
+ export class Bad implements Contract {
43
+ execute(input: string): void {}
44
+ }
45
+ `)
46
+
47
+ oldStdout, oldStderr := stdout, stderr
48
+ defer func() { stdout, stderr = oldStdout, oldStderr }()
49
+ var out, errBuf bytes.Buffer
50
+ stdout, stderr = &out, &errBuf
51
+
52
+ if code := run([]string{"dump", "--cwd", root, "--tsconfig", "tsconfig.json"}); code != 0 {
53
+ t.Fatalf("run dump exit = %d, want 0; stderr:\n%s", code, errBuf.String())
54
+ }
55
+ if bytes.Contains(out.Bytes(), []byte("member-relation")) {
56
+ t.Fatalf("internal edge kind leaked into the public dump:\n%s", out.String())
57
+ }
58
+
59
+ var dump graph.Dump
60
+ if err := json.Unmarshal(out.Bytes(), &dump); err != nil {
61
+ t.Fatalf("dump output is not valid JSON: %v\n%s", err, out.String())
62
+ }
63
+ seen2416 := false
64
+ for _, diagnostic := range dump.Diagnostics {
65
+ seen2416 = seen2416 || diagnostic.Code == 2416
66
+ }
67
+ if !seen2416 {
68
+ t.Fatalf("fixture must retain TS2416 in the same snapshot: %v", dump.Diagnostics)
69
+ }
70
+
71
+ node := func(name, kind string) *graph.DumpNode {
72
+ t.Helper()
73
+ for i := range dump.Nodes {
74
+ candidate := &dump.Nodes[i]
75
+ declaredName := candidate.QualifiedName
76
+ if declaredName == "" {
77
+ declaredName = candidate.Name
78
+ }
79
+ if declaredName == name && candidate.Kind == kind {
80
+ return candidate
81
+ }
82
+ }
83
+ t.Fatalf("missing %s %s; nodes: %v", kind, name, dump.Nodes)
84
+ return nil
85
+ }
86
+ contract := node("Contract", "interface")
87
+ good := node("Good", "class")
88
+ contractExecute := node("Contract.execute", "method")
89
+ goodExecute := node("Good.execute", "method")
90
+ badExecute := node("Bad.execute", "method")
91
+
92
+ countEdge := func(from, to, kind string) int {
93
+ count := 0
94
+ for _, edge := range dump.Edges {
95
+ if edge.From == from && edge.To == to && edge.Kind == kind {
96
+ count++
97
+ }
98
+ }
99
+ return count
100
+ }
101
+ if count := countEdge(good.ID, contract.ID, "implements"); count != 1 {
102
+ t.Fatalf("container implementation edge count = %d, want 1; edges: %v", count, dump.Edges)
103
+ }
104
+ if count := countEdge(goodExecute.ID, contractExecute.ID, "implements"); count != 1 {
105
+ t.Fatalf("valid member implementation edge count = %d, want 1; edges: %v", count, dump.Edges)
106
+ }
107
+ if count := countEdge(badExecute.ID, contractExecute.ID, "implements"); count != 0 {
108
+ t.Fatalf("checker-invalid member implementation edge count = %d, want 0; edges: %v", count, dump.Edges)
109
+ }
110
+ for _, edge := range dump.Edges {
111
+ if edge.From == goodExecute.ID && edge.To == contractExecute.ID && edge.Kind == "implements" {
112
+ if edge.Evidence == nil || goodExecute.Evidence == nil ||
113
+ edge.Evidence.StartLine != goodExecute.Evidence.StartLine {
114
+ t.Fatalf("member edge evidence does not identify Good.execute: edge=%v node=%v", edge.Evidence, goodExecute.Evidence)
115
+ }
116
+ }
117
+ }
118
+ }