ttsc 0.12.3 → 0.13.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.
Files changed (151) hide show
  1. package/cmd/platform/main.go +9 -0
  2. package/cmd/ttsc/api_compile.go +122 -101
  3. package/cmd/ttsc/api_compile_branches_test.go +55 -57
  4. package/cmd/ttsc/api_transform.go +67 -49
  5. package/cmd/ttsc/api_transform_branches_test.go +30 -32
  6. package/cmd/ttsc/build.go +141 -108
  7. package/cmd/ttsc/build_branches_test.go +95 -97
  8. package/cmd/ttsc/filter.go +70 -0
  9. package/cmd/ttsc/filter_strips_unknown_forwarded_flag_test.go +61 -0
  10. package/cmd/ttsc/flags_gen.go +30 -0
  11. package/cmd/ttsc/helpers_test.go +39 -28
  12. package/cmd/ttsc/main.go +111 -104
  13. package/cmd/ttsc/main_alias_branches_test.go +21 -23
  14. package/cmd/ttscserver/main.go +96 -90
  15. package/cmd/ttscserver/run_lsp_prefers_tsgo_flag_test.go +22 -22
  16. package/cmd/ttscserver/run_lsp_reports_server_error_test.go +22 -22
  17. package/cmd/ttscserver/run_lsp_uses_tsgo_environment_test.go +23 -23
  18. package/cmd/utility-host/main.go +30 -23
  19. package/driver/lsp.go +53 -7
  20. package/driver/plugins.go +88 -72
  21. package/driver/program.go +464 -340
  22. package/driver/rewrite.go +477 -380
  23. package/internal/lspserver/lsp_envelope.go +64 -64
  24. package/internal/lspserver/lsp_frame.go +60 -60
  25. package/internal/lspserver/lsp_plugin.go +57 -57
  26. package/internal/lspserver/lsp_proxy.go +265 -251
  27. package/internal/lspserver/lsp_server.go +155 -144
  28. package/lib/TtscCompiler.d.ts +7 -0
  29. package/lib/TtscCompiler.js +7 -0
  30. package/lib/TtscCompiler.js.map +1 -1
  31. package/lib/compiler/internal/buildNativeCompiler.d.ts +11 -1
  32. package/lib/compiler/internal/buildNativeCompiler.js +23 -3
  33. package/lib/compiler/internal/buildNativeCompiler.js.map +1 -1
  34. package/lib/compiler/internal/compileProjectInMemory.d.ts +9 -0
  35. package/lib/compiler/internal/compileProjectInMemory.js +36 -21
  36. package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
  37. package/lib/compiler/internal/paths.d.ts +27 -0
  38. package/lib/compiler/internal/paths.js +70 -0
  39. package/lib/compiler/internal/paths.js.map +1 -0
  40. package/lib/compiler/internal/project/readProjectConfig.d.ts +9 -1
  41. package/lib/compiler/internal/project/readProjectConfig.js +80 -1
  42. package/lib/compiler/internal/project/readProjectConfig.js.map +1 -1
  43. package/lib/compiler/internal/project/resolveProjectConfig.d.ts +13 -1
  44. package/lib/compiler/internal/project/resolveProjectConfig.js +42 -1
  45. package/lib/compiler/internal/project/resolveProjectConfig.js.map +1 -1
  46. package/lib/compiler/internal/resolveBinary.d.ts +9 -1
  47. package/lib/compiler/internal/resolveBinary.js +17 -1
  48. package/lib/compiler/internal/resolveBinary.js.map +1 -1
  49. package/lib/compiler/internal/resolveEmittedJavaScript.d.ts +16 -1
  50. package/lib/compiler/internal/resolveEmittedJavaScript.js +42 -10
  51. package/lib/compiler/internal/resolveEmittedJavaScript.js.map +1 -1
  52. package/lib/compiler/internal/resolveTsgo.d.ts +21 -1
  53. package/lib/compiler/internal/resolveTsgo.js +23 -1
  54. package/lib/compiler/internal/resolveTsgo.js.map +1 -1
  55. package/lib/compiler/internal/runBuild.d.ts +24 -4
  56. package/lib/compiler/internal/runBuild.js +355 -93
  57. package/lib/compiler/internal/runBuild.js.map +1 -1
  58. package/lib/compiler/internal/runSingleFileEmit.d.ts +10 -1
  59. package/lib/compiler/internal/runSingleFileEmit.js +14 -1
  60. package/lib/compiler/internal/runSingleFileEmit.js.map +1 -1
  61. package/lib/compiler/internal/sharedHostHelpers.d.ts +5 -0
  62. package/lib/compiler/internal/sharedHostHelpers.js +6 -2
  63. package/lib/compiler/internal/sharedHostHelpers.js.map +1 -1
  64. package/lib/compiler/internal/spawnNative.d.ts +21 -0
  65. package/lib/compiler/internal/spawnNative.js +59 -0
  66. package/lib/compiler/internal/spawnNative.js.map +1 -0
  67. package/lib/compiler/internal/transformProjectInMemory.d.ts +15 -1
  68. package/lib/compiler/internal/transformProjectInMemory.js +57 -61
  69. package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
  70. package/lib/flags/parser.d.ts +63 -0
  71. package/lib/flags/parser.js +254 -0
  72. package/lib/flags/parser.js.map +1 -0
  73. package/lib/flags/schema.d.ts +147 -0
  74. package/lib/flags/schema.js +405 -0
  75. package/lib/flags/schema.js.map +1 -0
  76. package/lib/launcher/internal/getCompilerVersionText.js +7 -0
  77. package/lib/launcher/internal/getCompilerVersionText.js.map +1 -1
  78. package/lib/launcher/internal/prepareExecution.js +35 -0
  79. package/lib/launcher/internal/prepareExecution.js.map +1 -1
  80. package/lib/launcher/internal/resolveCacheDir.d.ts +9 -0
  81. package/lib/launcher/internal/resolveCacheDir.js +22 -0
  82. package/lib/launcher/internal/resolveCacheDir.js.map +1 -0
  83. package/lib/launcher/internal/resolveTtscserverBinary.js +2 -0
  84. package/lib/launcher/internal/resolveTtscserverBinary.js.map +1 -1
  85. package/lib/launcher/internal/runTtsc.d.ts +10 -0
  86. package/lib/launcher/internal/runTtsc.js +90 -153
  87. package/lib/launcher/internal/runTtsc.js.map +1 -1
  88. package/lib/launcher/internal/runTtscserver.js +10 -35
  89. package/lib/launcher/internal/runTtscserver.js.map +1 -1
  90. package/lib/launcher/internal/runTtsx.d.ts +8 -0
  91. package/lib/launcher/internal/runTtsx.js +137 -79
  92. package/lib/launcher/internal/runTtsx.js.map +1 -1
  93. package/lib/plugin/internal/buildSourcePlugin.d.ts +38 -0
  94. package/lib/plugin/internal/buildSourcePlugin.js +40 -17
  95. package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
  96. package/lib/plugin/internal/loadProjectPlugins.d.ts +26 -0
  97. package/lib/plugin/internal/loadProjectPlugins.js +90 -41
  98. package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
  99. package/lib/structures/ITtscCompilerTransformation.d.ts +15 -2
  100. package/lib/structures/ITtscPlugin.d.ts +24 -0
  101. package/lib/structures/ITtscPluginCapabilities.d.ts +29 -0
  102. package/lib/structures/ITtscPluginCapabilities.js +3 -0
  103. package/lib/structures/ITtscPluginCapabilities.js.map +1 -0
  104. package/lib/structures/index.d.ts +1 -0
  105. package/lib/structures/index.js +1 -0
  106. package/lib/structures/index.js.map +1 -1
  107. package/lib/structures/internal/ITtscLoadedNativePlugin.d.ts +5 -0
  108. package/lib/structures/internal/TtscCommonOptions.d.ts +19 -0
  109. package/lib/structures/internal/TtscSingleFileEmitOptions.d.ts +0 -2
  110. package/package.json +9 -9
  111. package/shim/ast/shim.go +24 -0
  112. package/shim/checker/shim.go +35 -0
  113. package/shim/core/shim.go +17 -0
  114. package/shim/diagnosticwriter/shim.go +4 -0
  115. package/shim/lsp/shim.go +3 -3
  116. package/shim/printer/shim.go +20 -0
  117. package/src/TtscCompiler.ts +7 -0
  118. package/src/compiler/internal/buildNativeCompiler.ts +23 -3
  119. package/src/compiler/internal/compileProjectInMemory.ts +34 -25
  120. package/src/compiler/internal/paths.ts +68 -0
  121. package/src/compiler/internal/project/readProjectConfig.ts +86 -1
  122. package/src/compiler/internal/project/resolveProjectConfig.ts +44 -1
  123. package/src/compiler/internal/resolveBinary.ts +17 -1
  124. package/src/compiler/internal/resolveEmittedJavaScript.ts +43 -12
  125. package/src/compiler/internal/resolveTsgo.ts +29 -1
  126. package/src/compiler/internal/runBuild.ts +398 -112
  127. package/src/compiler/internal/runSingleFileEmit.ts +14 -1
  128. package/src/compiler/internal/sharedHostHelpers.ts +7 -7
  129. package/src/compiler/internal/spawnNative.ts +64 -0
  130. package/src/compiler/internal/transformProjectInMemory.ts +47 -67
  131. package/src/flags/parser.ts +367 -0
  132. package/src/flags/schema.ts +570 -0
  133. package/src/launcher/internal/getCompilerVersionText.ts +7 -0
  134. package/src/launcher/internal/prepareExecution.ts +35 -0
  135. package/src/launcher/internal/resolveCacheDir.ts +19 -0
  136. package/src/launcher/internal/resolveTtscserverBinary.ts +2 -0
  137. package/src/launcher/internal/runTtsc.ts +97 -143
  138. package/src/launcher/internal/runTtscserver.ts +9 -1
  139. package/src/launcher/internal/runTtsx.ts +149 -82
  140. package/src/plugin/internal/buildSourcePlugin.ts +40 -14
  141. package/src/plugin/internal/loadProjectPlugins.ts +116 -45
  142. package/src/structures/ITtscCompilerTransformation.ts +15 -2
  143. package/src/structures/ITtscPlugin.ts +26 -1
  144. package/src/structures/ITtscPluginCapabilities.ts +29 -0
  145. package/src/structures/index.ts +1 -0
  146. package/src/structures/internal/ITtscLoadedNativePlugin.ts +5 -0
  147. package/src/structures/internal/TtscCommonOptions.ts +19 -0
  148. package/src/structures/internal/TtscSingleFileEmitOptions.ts +0 -2
  149. package/tools/gen_shims/main.go +43 -8
  150. package/utility/flags_gen.go +30 -0
  151. package/utility/host.go +304 -245
package/utility/host.go CHANGED
@@ -1,308 +1,367 @@
1
1
  package utility
2
2
 
3
3
  import (
4
- "encoding/json"
5
- "flag"
6
- "fmt"
7
- "os"
8
- "path/filepath"
9
- "strings"
4
+ "encoding/json"
5
+ "flag"
6
+ "fmt"
7
+ "os"
8
+ "path/filepath"
9
+ "strings"
10
10
 
11
- shimcompiler "github.com/microsoft/typescript-go/shim/compiler"
12
- shimprinter "github.com/microsoft/typescript-go/shim/printer"
11
+ shimcompiler "github.com/microsoft/typescript-go/shim/compiler"
12
+ shimprinter "github.com/microsoft/typescript-go/shim/printer"
13
13
 
14
- "github.com/samchon/ttsc/packages/ttsc/driver"
14
+ "github.com/samchon/ttsc/packages/ttsc/driver"
15
15
  )
16
16
 
17
+ // hostOptions is the parsed form of the flags accepted by all three
18
+ // subcommands (check, build, transform).
17
19
  type hostOptions struct {
18
- cwd string
19
- emit bool
20
- noEmit bool
21
- outDir string
22
- pluginsJSON string
23
- quiet bool
24
- tsconfig string
25
- verbose bool
20
+ cwd string
21
+ emit bool
22
+ noEmit bool
23
+ outDir string
24
+ pluginsJSON string
25
+ quiet bool
26
+ tsconfig string
27
+ verbose bool
28
+ singleThreaded bool
29
+ checkers int
30
+ tsgoArgs []string
26
31
  }
27
32
 
33
+ // transformResult is the JSON envelope written to stdout by RunTransform.
34
+ // TypeScript maps relative output key → printer output; Diagnostics is
35
+ // reserved for future plugin diagnostics (currently always empty/omitted).
28
36
  type transformResult struct {
29
- Diagnostics []any `json:"diagnostics,omitempty"`
30
- TypeScript map[string]string `json:"typescript"`
37
+ Diagnostics []any `json:"diagnostics,omitempty"`
38
+ TypeScript map[string]string `json:"typescript"`
31
39
  }
32
40
 
33
41
  // RunCheck validates the project and linked plugin configuration without
34
42
  // emitting output.
35
43
  func RunCheck(args []string) int {
36
- opts, ok := parseHostOptions("check", args)
37
- if !ok {
38
- return 2
39
- }
40
- opts.noEmit = true
41
- prog, _, ok := loadUtilityProgram(opts)
42
- if !ok {
43
- return 2
44
- }
45
- defer prog.Close()
46
- if err := prog.ApplyLinkedPlugins(); err != nil {
47
- fmt.Fprintln(os.Stderr, err)
48
- return 2
49
- }
50
- return 0
44
+ opts, ok := parseHostOptions("check", args)
45
+ if !ok {
46
+ return 2
47
+ }
48
+ opts.noEmit = true
49
+ prog, _, ok := loadUtilityProgram(opts)
50
+ if !ok {
51
+ return 2
52
+ }
53
+ defer prog.Close()
54
+ if err := prog.ApplyLinkedPlugins(); err != nil {
55
+ fmt.Fprintln(os.Stderr, err)
56
+ return 2
57
+ }
58
+ return 0
51
59
  }
52
60
 
53
61
  // RunBuild hosts linked transform packages inside one compiler emit.
54
62
  func RunBuild(args []string) int {
55
- opts, ok := parseHostOptions("build", args)
56
- if !ok {
57
- return 2
58
- }
59
- prog, entries, ok := loadUtilityProgram(opts)
60
- if !ok {
61
- return 2
62
- }
63
- defer prog.Close()
64
- if opts.noEmit {
65
- return 0
66
- }
67
- if opts.verbose {
68
- opts.quiet = false
69
- }
70
- if !opts.quiet {
71
- fmt.Fprintf(os.Stdout, "// ttsc utility: plugins=%d emit=%v\n", len(entries), !opts.noEmit)
72
- }
73
- res, eDiags, err := prog.EmitAllRaw(makeSourcePreambleWriteFile(prog))
74
- if err != nil {
75
- fmt.Fprintf(os.Stderr, "ttsc utility: emit failed: %v\n", err)
76
- return 3
77
- }
78
- for _, d := range eDiags {
79
- fmt.Fprintln(os.Stderr, " -", d.String())
80
- }
81
- if driver.CountErrors(eDiags) > 0 {
82
- return 2
83
- }
84
- if res != nil && !opts.quiet {
85
- fmt.Fprintf(os.Stdout, "// ttsc utility: emitted=%d files\n", len(res.EmittedFiles))
86
- }
87
- return 0
63
+ opts, ok := parseHostOptions("build", args)
64
+ if !ok {
65
+ return 2
66
+ }
67
+ prog, entries, ok := loadUtilityProgram(opts)
68
+ if !ok {
69
+ return 2
70
+ }
71
+ defer prog.Close()
72
+ if opts.noEmit {
73
+ return 0
74
+ }
75
+ if opts.verbose {
76
+ opts.quiet = false // --verbose overrides the default --quiet=true
77
+ }
78
+ if !opts.quiet {
79
+ fmt.Fprintf(os.Stdout, "// ttsc utility: plugins=%d emit=%v\n", len(entries), !opts.noEmit)
80
+ }
81
+ res, eDiags, err := prog.EmitAllRaw(makeSourcePreambleWriteFile(prog))
82
+ if err != nil {
83
+ fmt.Fprintf(os.Stderr, "ttsc utility: emit failed: %v\n", err)
84
+ return 3
85
+ }
86
+ for _, d := range eDiags {
87
+ fmt.Fprintln(os.Stderr, " -", d.String())
88
+ }
89
+ if driver.CountErrors(eDiags) > 0 {
90
+ return 2
91
+ }
92
+ if res != nil && !opts.quiet {
93
+ fmt.Fprintf(os.Stdout, "// ttsc utility: emitted=%d files\n", len(res.EmittedFiles))
94
+ }
95
+ return 0
88
96
  }
89
97
 
90
98
  // RunTransform returns the project TypeScript text after linked source
91
99
  // mutations.
92
100
  func RunTransform(args []string) int {
93
- opts, ok := parseHostOptions("transform", args)
94
- if !ok {
95
- return 2
96
- }
97
- prog, _, ok := loadUtilityProgram(opts)
98
- if !ok {
99
- return 2
100
- }
101
- defer prog.Close()
102
- if err := prog.ApplyLinkedPlugins(); err != nil {
103
- fmt.Fprintln(os.Stderr, err)
104
- return 2
105
- }
106
- printer := shimprinter.NewPrinter(shimprinter.PrinterOptions{}, shimprinter.PrintHandlers{}, nil)
107
- out := transformResult{TypeScript: map[string]string{}}
108
- for _, file := range prog.SourceFiles() {
109
- text := shimprinter.EmitSourceFile(printer, file)
110
- out.TypeScript[apiOutputKey(opts.cwd, file.FileName())] = text
111
- }
112
- data, _ := json.Marshal(out)
113
- fmt.Fprintln(os.Stdout, string(data))
114
- return 0
101
+ opts, ok := parseHostOptions("transform", args)
102
+ if !ok {
103
+ return 2
104
+ }
105
+ prog, _, ok := loadUtilityProgram(opts)
106
+ if !ok {
107
+ return 2
108
+ }
109
+ defer prog.Close()
110
+ if err := prog.ApplyLinkedPlugins(); err != nil {
111
+ fmt.Fprintln(os.Stderr, err)
112
+ return 2
113
+ }
114
+ printer := shimprinter.NewPrinter(shimprinter.PrinterOptions{}, shimprinter.PrintHandlers{}, nil)
115
+ out := transformResult{TypeScript: map[string]string{}}
116
+ for _, file := range prog.SourceFiles() {
117
+ text := shimprinter.EmitSourceFile(printer, file)
118
+ out.TypeScript[apiOutputKey(opts.cwd, file.FileName())] = text
119
+ }
120
+ data, _ := json.Marshal(out)
121
+ fmt.Fprintln(os.Stdout, string(data))
122
+ return 0
115
123
  }
116
124
 
125
+ // parseHostOptions parses the standard flag set for the given subcommand name.
126
+ // Unknown flags forwarded from the JS launcher are stripped by filterHostArgs
127
+ // before flag.FlagSet sees them, so spurious "flag provided but not defined"
128
+ // errors are avoided. Returns (zero, false) on any parse or validation error.
117
129
  func parseHostOptions(command string, args []string) (hostOptions, bool) {
118
- fs := flag.NewFlagSet(command, flag.ContinueOnError)
119
- fs.SetOutput(os.Stderr)
120
- cwd := fs.String("cwd", "", "project directory")
121
- emit := fs.Bool("emit", false, "force emit")
122
- noEmit := fs.Bool("noEmit", false, "force no emit")
123
- outDir := fs.String("outDir", "", "emit directory override")
124
- pluginsJSON := fs.String("plugins-json", "", "ttsc plugin manifest JSON")
125
- quiet := fs.Bool("quiet", true, "suppress summary")
126
- tsconfig := fs.String("tsconfig", "tsconfig.json", "project tsconfig")
127
- verbose := fs.Bool("verbose", false, "print summary")
128
- if err := fs.Parse(filterHostArgs(args)); err != nil {
129
- return hostOptions{}, false
130
- }
131
- if *emit && *noEmit {
132
- fmt.Fprintln(os.Stderr, "ttsc utility: --emit and --noEmit are mutually exclusive")
133
- return hostOptions{}, false
134
- }
135
- resolvedCwd := *cwd
136
- if resolvedCwd == "" {
137
- var err error
138
- resolvedCwd, err = os.Getwd()
139
- if err != nil {
140
- fmt.Fprintf(os.Stderr, "ttsc utility: cwd: %v\n", err)
141
- return hostOptions{}, false
142
- }
143
- }
144
- if !filepath.IsAbs(resolvedCwd) {
145
- abs, err := filepath.Abs(resolvedCwd)
146
- if err != nil {
147
- fmt.Fprintf(os.Stderr, "ttsc utility: cwd: %v\n", err)
148
- return hostOptions{}, false
149
- }
150
- resolvedCwd = abs
151
- }
152
- return hostOptions{
153
- cwd: filepath.Clean(resolvedCwd),
154
- emit: *emit,
155
- noEmit: *noEmit,
156
- outDir: *outDir,
157
- pluginsJSON: *pluginsJSON,
158
- quiet: *quiet,
159
- tsconfig: *tsconfig,
160
- verbose: *verbose,
161
- }, true
130
+ fs := flag.NewFlagSet(command, flag.ContinueOnError)
131
+ fs.SetOutput(os.Stderr)
132
+ cwd := fs.String("cwd", "", "project directory")
133
+ emit := fs.Bool("emit", false, "force emit")
134
+ noEmit := fs.Bool("noEmit", false, "force no emit")
135
+ outDir := fs.String("outDir", "", "emit directory override")
136
+ pluginsJSON := fs.String("plugins-json", "", "ttsc plugin manifest JSON")
137
+ quiet := fs.Bool("quiet", true, "suppress summary")
138
+ tsconfig := fs.String("tsconfig", "tsconfig.json", "project tsconfig")
139
+ verbose := fs.Bool("verbose", false, "print summary")
140
+ singleThreaded := fs.Bool("singleThreaded", false, "run TypeScript-Go single-threaded")
141
+ checkers := fs.Int("checkers", 0, "type-checker pool size (0 = TypeScript-Go default)")
142
+ tsgoArgsRaw := fs.String("tsgo-args", "", "JSON array of forwarded tsgo CLI flags")
143
+ if err := fs.Parse(filterHostArgs(args)); err != nil {
144
+ return hostOptions{}, false
145
+ }
146
+ var tsgoArgs []string
147
+ if *tsgoArgsRaw != "" {
148
+ if err := json.Unmarshal([]byte(*tsgoArgsRaw), &tsgoArgs); err != nil {
149
+ fmt.Fprintf(os.Stderr, "ttsc utility: invalid --tsgo-args: %v\n", err)
150
+ return hostOptions{}, false
151
+ }
152
+ }
153
+ if *emit && *noEmit {
154
+ fmt.Fprintln(os.Stderr, "ttsc utility: --emit and --noEmit are mutually exclusive")
155
+ return hostOptions{}, false
156
+ }
157
+ resolvedCwd := *cwd
158
+ if resolvedCwd == "" {
159
+ var err error
160
+ resolvedCwd, err = os.Getwd()
161
+ if err != nil {
162
+ fmt.Fprintf(os.Stderr, "ttsc utility: cwd: %v\n", err)
163
+ return hostOptions{}, false
164
+ }
165
+ }
166
+ if !filepath.IsAbs(resolvedCwd) {
167
+ abs, err := filepath.Abs(resolvedCwd)
168
+ if err != nil {
169
+ fmt.Fprintf(os.Stderr, "ttsc utility: cwd: %v\n", err)
170
+ return hostOptions{}, false
171
+ }
172
+ resolvedCwd = abs
173
+ }
174
+ return hostOptions{
175
+ cwd: filepath.Clean(resolvedCwd),
176
+ emit: *emit,
177
+ noEmit: *noEmit,
178
+ outDir: *outDir,
179
+ pluginsJSON: *pluginsJSON,
180
+ quiet: *quiet,
181
+ tsconfig: *tsconfig,
182
+ verbose: *verbose,
183
+ singleThreaded: *singleThreaded,
184
+ checkers: *checkers,
185
+ tsgoArgs: tsgoArgs,
186
+ }, true
162
187
  }
163
188
 
189
+ // filterHostArgs strips flags that the Go flag set does not declare so that
190
+ // flags forwarded from the JS launcher (e.g. tsgo-specific options) do not
191
+ // cause flag.FlagSet to error. Flags not in the known set are consumed together
192
+ // with their value argument when they clearly take one (no inline "=" and the
193
+ // next token does not start with "-").
194
+ //
195
+ // The allow-list itself is generated from packages/ttsc/src/flags/schema.ts
196
+ // (see flags_gen.go); editing it means editing the schema and re-running
197
+ // `pnpm format`, not patching this file.
164
198
  func filterHostArgs(args []string) []string {
165
- known := map[string]bool{
166
- "cwd": true,
167
- "emit": false,
168
- "noEmit": false,
169
- "outDir": true,
170
- "plugins-json": true,
171
- "quiet": false,
172
- "tsconfig": true,
173
- "verbose": false,
174
- }
175
- filtered := make([]string, 0, len(args))
176
- for i := 0; i < len(args); i++ {
177
- current := args[i]
178
- if current == "--" {
179
- break
180
- }
181
- if !strings.HasPrefix(current, "--") {
182
- filtered = append(filtered, current)
183
- continue
184
- }
185
- name, hasInlineValue := flagName(current)
186
- takesValue, ok := known[name]
187
- if ok {
188
- filtered = append(filtered, current)
189
- if takesValue && !hasInlineValue && i+1 < len(args) {
190
- i++
191
- filtered = append(filtered, args[i])
192
- }
193
- continue
194
- }
195
- if !hasInlineValue && i+1 < len(args) && !strings.HasPrefix(args[i+1], "-") {
196
- i++
197
- }
198
- }
199
- return filtered
199
+ filtered := make([]string, 0, len(args))
200
+ for i := 0; i < len(args); i++ {
201
+ current := args[i]
202
+ if current == "--" {
203
+ break
204
+ }
205
+ if !strings.HasPrefix(current, "--") {
206
+ filtered = append(filtered, current)
207
+ continue
208
+ }
209
+ name, hasInlineValue := flagName(current)
210
+ takesValue, ok := HostFlagAllowList[name]
211
+ if ok {
212
+ filtered = append(filtered, current)
213
+ if takesValue && !hasInlineValue && i+1 < len(args) {
214
+ i++
215
+ filtered = append(filtered, args[i])
216
+ }
217
+ continue
218
+ }
219
+ if !hasInlineValue && i+1 < len(args) && !strings.HasPrefix(args[i+1], "-") {
220
+ i++
221
+ }
222
+ }
223
+ return filtered
200
224
  }
201
225
 
226
+ // flagName strips the leading "--" from a flag argument and reports whether
227
+ // the flag carries an inline value (i.e. the argument contains "=").
202
228
  func flagName(arg string) (string, bool) {
203
- name := strings.TrimPrefix(arg, "--")
204
- before, _, found := strings.Cut(name, "=")
205
- return before, found
229
+ name := strings.TrimPrefix(arg, "--")
230
+ before, _, found := strings.Cut(name, "=")
231
+ return before, found
206
232
  }
207
233
 
234
+ // loadUtilityProgram parses plugins JSON, sets the linked-plugin environment
235
+ // variable for the duration of LoadProgram, and returns a fully initialized
236
+ // Program along with the decoded plugin entries. Returns (nil, nil, false) and
237
+ // prints diagnostics to stderr on any error.
208
238
  func loadUtilityProgram(opts hostOptions) (*driver.Program, []driver.PluginEntry, bool) {
209
- entries, err := parsePluginEntries(opts.pluginsJSON)
210
- if err != nil {
211
- fmt.Fprintln(os.Stderr, err)
212
- return nil, nil, false
213
- }
214
- restoreEnv := setLinkedPluginManifest(opts.pluginsJSON)
215
- defer restoreEnv()
239
+ entries, err := parsePluginEntries(opts.pluginsJSON)
240
+ if err != nil {
241
+ fmt.Fprintln(os.Stderr, err)
242
+ return nil, nil, false
243
+ }
244
+ restoreEnv := setLinkedPluginManifest(opts.pluginsJSON)
245
+ defer restoreEnv()
216
246
 
217
- prog, diags, err := driver.LoadProgram(opts.cwd, opts.tsconfig, driver.LoadProgramOptions{
218
- ForceEmit: opts.emit,
219
- ForceNoEmit: opts.noEmit,
220
- OutDir: opts.outDir,
221
- })
222
- if err != nil {
223
- fmt.Fprintf(os.Stderr, "ttsc utility: %v\n", err)
224
- return nil, nil, false
225
- }
226
- if len(diags) > 0 {
227
- driver.WritePrettyDiagnostics(os.Stderr, diags, opts.cwd)
228
- return nil, nil, false
229
- }
230
- if diags := prog.Diagnostics(); len(diags) > 0 {
231
- driver.WritePrettyDiagnostics(os.Stderr, diags, opts.cwd)
232
- _ = prog.Close()
233
- return nil, nil, false
234
- }
235
- return prog, entries, true
247
+ prog, diags, err := driver.LoadProgram(opts.cwd, opts.tsconfig, driver.LoadProgramOptions{
248
+ ForceEmit: opts.emit,
249
+ ForceNoEmit: opts.noEmit,
250
+ OutDir: opts.outDir,
251
+ SingleThreaded: opts.singleThreaded,
252
+ Checkers: opts.checkers,
253
+ TsgoArgs: opts.tsgoArgs,
254
+ })
255
+ if err != nil {
256
+ fmt.Fprintf(os.Stderr, "ttsc utility: %v\n", err)
257
+ return nil, nil, false
258
+ }
259
+ if len(diags) > 0 {
260
+ driver.WritePrettyDiagnostics(os.Stderr, diags, opts.cwd)
261
+ return nil, nil, false
262
+ }
263
+ if diags := prog.Diagnostics(); len(diags) > 0 {
264
+ driver.WritePrettyDiagnostics(os.Stderr, diags, opts.cwd)
265
+ _ = prog.Close()
266
+ return nil, nil, false
267
+ }
268
+ return prog, entries, true
236
269
  }
237
270
 
271
+ // parsePluginEntries decodes the --plugins-json flag value into a slice of
272
+ // PluginEntry. An empty or whitespace-only string is treated as "no plugins"
273
+ // (returns nil, nil) rather than a JSON error.
238
274
  func parsePluginEntries(input string) ([]driver.PluginEntry, error) {
239
- if strings.TrimSpace(input) == "" {
240
- return nil, nil
241
- }
242
- var entries []driver.PluginEntry
243
- if err := json.Unmarshal([]byte(input), &entries); err != nil {
244
- return nil, fmt.Errorf("ttsc utility: invalid --plugins-json: %w", err)
245
- }
246
- return entries, nil
275
+ if strings.TrimSpace(input) == "" {
276
+ return nil, nil
277
+ }
278
+ var entries []driver.PluginEntry
279
+ if err := json.Unmarshal([]byte(input), &entries); err != nil {
280
+ return nil, fmt.Errorf("ttsc utility: invalid --plugins-json: %w", err)
281
+ }
282
+ return entries, nil
247
283
  }
248
284
 
285
+ // setLinkedPluginManifest writes input into the LinkedPluginsEnv environment
286
+ // variable (or clears it when input is blank) and returns a restore function
287
+ // that puts the variable back to its previous state. The restore function is
288
+ // intended to be called via defer immediately after setLinkedPluginManifest.
249
289
  func setLinkedPluginManifest(input string) func() {
250
- previous, existed := os.LookupEnv(driver.LinkedPluginsEnv)
251
- if strings.TrimSpace(input) == "" {
252
- _ = os.Unsetenv(driver.LinkedPluginsEnv)
253
- } else {
254
- _ = os.Setenv(driver.LinkedPluginsEnv, input)
255
- }
256
- return func() {
257
- if existed {
258
- _ = os.Setenv(driver.LinkedPluginsEnv, previous)
259
- } else {
260
- _ = os.Unsetenv(driver.LinkedPluginsEnv)
261
- }
262
- }
290
+ previous, existed := os.LookupEnv(driver.LinkedPluginsEnv)
291
+ if strings.TrimSpace(input) == "" {
292
+ _ = os.Unsetenv(driver.LinkedPluginsEnv)
293
+ } else {
294
+ _ = os.Setenv(driver.LinkedPluginsEnv, input)
295
+ }
296
+ return func() {
297
+ if existed {
298
+ _ = os.Setenv(driver.LinkedPluginsEnv, previous)
299
+ } else {
300
+ _ = os.Unsetenv(driver.LinkedPluginsEnv)
301
+ }
302
+ }
263
303
  }
264
304
 
305
+ // makeSourcePreambleWriteFile returns a WriteFile callback that injects
306
+ // prog.SourcePreamble at the top of every emitted output file that supports
307
+ // it. Returns nil when no preamble is needed (empty preamble, nil program, or
308
+ // RemoveComments enabled), which tells the caller to use the default writer.
265
309
  func makeSourcePreambleWriteFile(prog *driver.Program) shimcompiler.WriteFile {
266
- if prog == nil || prog.SourcePreamble == "" || shouldRemoveComments(prog) {
267
- return nil
268
- }
269
- return func(fileName, text string, _ *shimcompiler.WriteFileData) error {
270
- if shouldEnsureSourcePreamble(fileName, text, prog.SourcePreamble) {
271
- text = driver.ApplySourcePreamble(text, prog.SourcePreamble)
272
- }
273
- return driver.DefaultWriteFile(fileName, text)
274
- }
310
+ if prog == nil || prog.SourcePreamble == "" || shouldRemoveComments(prog) {
311
+ return nil
312
+ }
313
+ return func(fileName, text string, _ *shimcompiler.WriteFileData) error {
314
+ if shouldEnsureSourcePreamble(fileName, text, prog.SourcePreamble) {
315
+ text = driver.ApplySourcePreamble(text, prog.SourcePreamble)
316
+ }
317
+ return driver.DefaultWriteFile(fileName, text)
318
+ }
275
319
  }
276
320
 
321
+ // shouldRemoveComments reports whether the compiler options ask tsgo to strip
322
+ // comments. When true the source preamble (which is itself a comment block) must
323
+ // not be injected because tsgo would then strip it, resulting in a no-op.
277
324
  func shouldRemoveComments(prog *driver.Program) bool {
278
- if prog == nil || prog.ParsedConfig == nil || prog.ParsedConfig.ParsedConfig == nil || prog.ParsedConfig.ParsedConfig.CompilerOptions == nil {
279
- return false
280
- }
281
- return prog.ParsedConfig.ParsedConfig.CompilerOptions.RemoveComments.IsTrue()
325
+ if prog == nil || prog.ParsedConfig == nil || prog.ParsedConfig.ParsedConfig == nil || prog.ParsedConfig.ParsedConfig.CompilerOptions == nil {
326
+ return false
327
+ }
328
+ return prog.ParsedConfig.ParsedConfig.CompilerOptions.RemoveComments.IsTrue()
282
329
  }
283
330
 
331
+ // shouldEnsureSourcePreamble reports whether the preamble still needs to be
332
+ // injected into the output file. The idempotency check (strings.Contains)
333
+ // prevents double-injection on watch-mode rebuilds.
284
334
  func shouldEnsureSourcePreamble(fileName, text, sourcePreamble string) bool {
285
- return isSourcePreambleOutputTarget(fileName) && !strings.Contains(text, sourcePreamble)
335
+ return isSourcePreambleOutputTarget(fileName) && !strings.Contains(text, sourcePreamble)
286
336
  }
287
337
 
338
+ // isSourcePreambleOutputTarget reports whether fileName is a JS or declaration
339
+ // output file that should receive the source preamble. Declaration files
340
+ // (.d.ts/.d.mts/.d.cts) are included because plugins like @ttsc/banner inject
341
+ // a copyright header that must appear there as well.
288
342
  func isSourcePreambleOutputTarget(fileName string) bool {
289
- lower := strings.ToLower(filepath.ToSlash(fileName))
290
- for _, suffix := range []string{".d.ts", ".d.mts", ".d.cts", ".js", ".jsx", ".mjs", ".cjs"} {
291
- if strings.HasSuffix(lower, suffix) {
292
- return true
293
- }
294
- }
295
- return false
343
+ lower := strings.ToLower(filepath.ToSlash(fileName))
344
+ for _, suffix := range []string{".d.ts", ".d.mts", ".d.cts", ".js", ".jsx", ".mjs", ".cjs"} {
345
+ if strings.HasSuffix(lower, suffix) {
346
+ return true
347
+ }
348
+ }
349
+ return false
296
350
  }
297
351
 
352
+ // apiOutputKey converts an absolute fileName to a path relative to cwd for use
353
+ // as the JSON key in RunTransform output. Falls back to the slash-normalized
354
+ // absolute path when the file lives outside the project root.
298
355
  func apiOutputKey(cwd, fileName string) string {
299
- rel, err := filepath.Rel(cwd, fileName)
300
- if err != nil || isOutsideRelativePath(rel) {
301
- return filepath.ToSlash(fileName)
302
- }
303
- return filepath.ToSlash(rel)
356
+ rel, err := filepath.Rel(cwd, fileName)
357
+ if err != nil || isOutsideRelativePath(rel) {
358
+ return filepath.ToSlash(fileName)
359
+ }
360
+ return filepath.ToSlash(rel)
304
361
  }
305
362
 
363
+ // isOutsideRelativePath reports whether rel escapes the project root (starts
364
+ // with ".." or is exactly "..").
306
365
  func isOutsideRelativePath(rel string) bool {
307
- return rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator))
366
+ return rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator))
308
367
  }