ttsc 0.10.2 → 0.11.0-dev.20260517

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 (106) hide show
  1. package/README.md +8 -0
  2. package/cmd/ttsc/api_compile.go +106 -106
  3. package/cmd/ttsc/api_transform.go +54 -54
  4. package/cmd/ttsc/main.go +103 -103
  5. package/cmd/ttscserver/helpers_test.go +27 -0
  6. package/cmd/ttscserver/main.go +154 -0
  7. package/cmd/ttscserver/run_lsp_reports_getwd_error_test.go +34 -0
  8. package/cmd/ttscserver/run_lsp_reports_server_error_test.go +42 -0
  9. package/driver/lsp_envelope.go +136 -0
  10. package/driver/lsp_frame.go +121 -0
  11. package/driver/lsp_plugin.go +150 -0
  12. package/driver/lsp_proxy.go +394 -0
  13. package/driver/lsp_server.go +197 -0
  14. package/go.mod +4 -0
  15. package/go.sum +4 -0
  16. package/internal/cwd/cwd.go +8 -8
  17. package/lib/TtscCompiler.d.ts +15 -16
  18. package/lib/TtscCompiler.js +15 -16
  19. package/lib/TtscCompiler.js.map +1 -1
  20. package/lib/compiler/internal/compileProjectInMemory.d.ts +4 -1
  21. package/lib/compiler/internal/compileProjectInMemory.js +4 -1
  22. package/lib/compiler/internal/compileProjectInMemory.js.map +1 -1
  23. package/lib/compiler/internal/project/readProjectConfig.js.map +1 -1
  24. package/lib/compiler/internal/runBuild.js +43 -1
  25. package/lib/compiler/internal/runBuild.js.map +1 -1
  26. package/lib/compiler/internal/sharedHostHelpers.d.ts +12 -12
  27. package/lib/compiler/internal/sharedHostHelpers.js +12 -12
  28. package/lib/defineTtscPlugin.d.ts +18 -0
  29. package/lib/defineTtscPlugin.js +7 -0
  30. package/lib/defineTtscPlugin.js.map +1 -0
  31. package/lib/index.d.ts +4 -3
  32. package/lib/index.js +4 -3
  33. package/lib/index.js.map +1 -1
  34. package/lib/launcher/internal/prepareExecution.js +1 -1
  35. package/lib/launcher/internal/prepareExecution.js.map +1 -1
  36. package/lib/launcher/internal/resolveTtscserverBinary.d.ts +12 -0
  37. package/lib/launcher/internal/resolveTtscserverBinary.js +43 -0
  38. package/lib/launcher/internal/resolveTtscserverBinary.js.map +1 -0
  39. package/lib/launcher/internal/runTtsc.js +47 -8
  40. package/lib/launcher/internal/runTtsc.js.map +1 -1
  41. package/lib/launcher/internal/runTtscserver.d.ts +20 -0
  42. package/lib/launcher/internal/runTtscserver.js +125 -0
  43. package/lib/launcher/internal/runTtscserver.js.map +1 -0
  44. package/lib/launcher/internal/runTtsx.js +1 -1
  45. package/lib/launcher/internal/runTtsx.js.map +1 -1
  46. package/lib/launcher/ttscserver.d.ts +2 -0
  47. package/lib/launcher/ttscserver.js +9 -0
  48. package/lib/launcher/ttscserver.js.map +1 -0
  49. package/lib/plugin/internal/buildSourcePlugin.d.ts +9 -0
  50. package/lib/plugin/internal/buildSourcePlugin.js +197 -2
  51. package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
  52. package/lib/plugin/internal/loadProjectPlugins.js +86 -8
  53. package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
  54. package/lib/structures/ITtscCompilerContext.d.ts +1 -1
  55. package/lib/structures/ITtscCompilerDiagnostic.d.ts +3 -3
  56. package/lib/structures/ITtscCompilerResult.d.ts +10 -22
  57. package/lib/structures/ITtscCompilerTransformation.d.ts +2 -2
  58. package/lib/structures/ITtscPlugin.d.ts +37 -4
  59. package/lib/structures/ITtscPlugin.js +0 -4
  60. package/lib/structures/ITtscPlugin.js.map +1 -1
  61. package/lib/structures/ITtscPluginContributor.d.ts +26 -0
  62. package/lib/structures/ITtscPluginContributor.js +3 -0
  63. package/lib/structures/ITtscPluginContributor.js.map +1 -0
  64. package/lib/structures/ITtscPluginFactoryContext.d.ts +5 -5
  65. package/lib/structures/ITtscProjectPluginConfig.d.ts +2 -2
  66. package/lib/structures/TtscPluginStage.d.ts +4 -3
  67. package/lib/structures/index.d.ts +1 -0
  68. package/lib/structures/index.js +1 -0
  69. package/lib/structures/index.js.map +1 -1
  70. package/lib/structures/internal/ITtscLoadedNativePlugin.d.ts +3 -0
  71. package/lib/structures/internal/TtscBuildOptions.d.ts +13 -0
  72. package/lib/structures/internal/TtscCommonOptions.d.ts +5 -2
  73. package/package.json +10 -9
  74. package/shim/lsp/extra-shim.json +4 -0
  75. package/shim/lsp/go.mod +16 -0
  76. package/shim/lsp/go.sum +26 -0
  77. package/shim/lsp/shim.go +42 -0
  78. package/shim/printer/shim.go +5 -5
  79. package/src/TtscCompiler.ts +15 -16
  80. package/src/compiler/internal/compileProjectInMemory.ts +4 -1
  81. package/src/compiler/internal/project/readProjectConfig.ts +0 -1
  82. package/src/compiler/internal/runBuild.ts +43 -1
  83. package/src/compiler/internal/sharedHostHelpers.ts +12 -12
  84. package/src/defineTtscPlugin.ts +26 -0
  85. package/src/index.ts +4 -3
  86. package/src/launcher/internal/prepareExecution.ts +1 -1
  87. package/src/launcher/internal/resolveTtscserverBinary.ts +51 -0
  88. package/src/launcher/internal/runTtsc.ts +53 -11
  89. package/src/launcher/internal/runTtscserver.ts +92 -0
  90. package/src/launcher/internal/runTtsx.ts +1 -1
  91. package/src/launcher/ttscserver.ts +8 -0
  92. package/src/plugin/internal/buildSourcePlugin.ts +231 -12
  93. package/src/plugin/internal/loadProjectPlugins.ts +108 -8
  94. package/src/structures/ITtscCompilerContext.ts +1 -1
  95. package/src/structures/ITtscCompilerDiagnostic.ts +3 -3
  96. package/src/structures/ITtscCompilerResult.ts +10 -22
  97. package/src/structures/ITtscCompilerTransformation.ts +2 -2
  98. package/src/structures/ITtscPlugin.ts +37 -11
  99. package/src/structures/ITtscPluginContributor.ts +27 -0
  100. package/src/structures/ITtscPluginFactoryContext.ts +5 -5
  101. package/src/structures/ITtscProjectPluginConfig.ts +2 -2
  102. package/src/structures/TtscPluginStage.ts +4 -3
  103. package/src/structures/index.ts +1 -0
  104. package/src/structures/internal/ITtscLoadedNativePlugin.ts +3 -0
  105. package/src/structures/internal/TtscBuildOptions.ts +13 -0
  106. package/src/structures/internal/TtscCommonOptions.ts +5 -2
package/README.md CHANGED
@@ -162,6 +162,14 @@ Ecosystem plugins are listed below; PRs adding `ttsc` plugins are welcome.
162
162
  - [`nestia`](https://github.com/samchon/nestia): generates NestJS routes, OpenAPI, and SDKs.
163
163
  - [`typia`](https://github.com/samchon/typia): generates validators, serializers, and type-driven runtime code.
164
164
 
165
+ ## Sponsors
166
+
167
+ [![Sponsors](https://raw.githubusercontent.com/samchon/sponsor-images/refs/heads/master/public/circle.svg)](https://github.com/sponsors/samchon)
168
+
169
+ Thanks for your support.
170
+
171
+ Your [donation](https://github.com/sponsors/samchon) encourages `ttsc` development.
172
+
165
173
  ## References
166
174
 
167
175
  - TypeScript runners: [`ts-node`](https://github.com/TypeStrong/ts-node) and [`tsx`](https://github.com/privatenumber/tsx)
@@ -7,25 +7,25 @@
7
7
  package main
8
8
 
9
9
  import (
10
- "encoding/json"
11
- "flag"
12
- "fmt"
13
- "os"
14
- "path/filepath"
15
- "strings"
10
+ "encoding/json"
11
+ "flag"
12
+ "fmt"
13
+ "os"
14
+ "path/filepath"
15
+ "strings"
16
16
 
17
- shimcompiler "github.com/microsoft/typescript-go/shim/compiler"
17
+ shimcompiler "github.com/microsoft/typescript-go/shim/compiler"
18
18
 
19
- "github.com/samchon/ttsc/packages/ttsc/driver"
20
- cwdutil "github.com/samchon/ttsc/packages/ttsc/internal/cwd"
19
+ "github.com/samchon/ttsc/packages/ttsc/driver"
20
+ cwdutil "github.com/samchon/ttsc/packages/ttsc/internal/cwd"
21
21
  )
22
22
 
23
23
  type apiCompileResult struct {
24
- // Diagnostics is omitted only when the compiler produced no diagnostics.
25
- // Output is still returned in diagnostic cases because TypeScript-Go may
26
- // produce partial emit text before a build-failing error is reported.
27
- Diagnostics []apiCompileDiagnostic `json:"diagnostics,omitempty"`
28
- Output map[string]string `json:"output"`
24
+ // Diagnostics is omitted only when the compiler produced no diagnostics.
25
+ // Output is still returned in diagnostic cases because TypeScript-Go may
26
+ // produce partial emit text before a build-failing error is reported.
27
+ Diagnostics []apiCompileDiagnostic `json:"diagnostics,omitempty"`
28
+ Output map[string]string `json:"output"`
29
29
  }
30
30
 
31
31
  // apiCompileDiagnostic mirrors the public TypeScript-side diagnostic DTO.
@@ -33,113 +33,113 @@ type apiCompileResult struct {
33
33
  // `character`) instead of Go naming so callers can pass the data through
34
34
  // without remapping.
35
35
  type apiCompileDiagnostic struct {
36
- File *string `json:"file"`
37
- Category string `json:"category"`
38
- Code int32 `json:"code"`
39
- Start *int `json:"start,omitempty"`
40
- Length *int `json:"length,omitempty"`
41
- Line int `json:"line,omitempty"`
42
- Character int `json:"character,omitempty"`
43
- MessageText string `json:"messageText"`
36
+ File *string `json:"file"`
37
+ Category string `json:"category"`
38
+ Code int32 `json:"code"`
39
+ Start *int `json:"start,omitempty"`
40
+ Length *int `json:"length,omitempty"`
41
+ Line int `json:"line,omitempty"`
42
+ Character int `json:"character,omitempty"`
43
+ MessageText string `json:"messageText"`
44
44
  }
45
45
 
46
46
  func runAPICompile(args []string) int {
47
- fs := flag.NewFlagSet("api-compile", flag.ContinueOnError)
48
- fs.SetOutput(stderr)
49
- tsconfigPath := fs.String("tsconfig", "tsconfig.json", "path to tsconfig.json")
50
- cwdOverride := fs.String("cwd", "", "override the working directory")
51
- if err := fs.Parse(args); err != nil {
52
- return 2
53
- }
47
+ fs := flag.NewFlagSet("api-compile", flag.ContinueOnError)
48
+ fs.SetOutput(stderr)
49
+ tsconfigPath := fs.String("tsconfig", "tsconfig.json", "path to tsconfig.json")
50
+ cwdOverride := fs.String("cwd", "", "override the working directory")
51
+ if err := fs.Parse(args); err != nil {
52
+ return 2
53
+ }
54
54
 
55
- cwd, err := cwdutil.Resolve(*cwdOverride, os.Getwd)
56
- if err != nil {
57
- fmt.Fprintf(stderr, "ttsc: %v\n", err)
58
- return 2
59
- }
55
+ cwd, err := cwdutil.Resolve(*cwdOverride, os.Getwd)
56
+ if err != nil {
57
+ fmt.Fprintf(stderr, "ttsc: %v\n", err)
58
+ return 2
59
+ }
60
60
 
61
- prog, diags, err := driver.LoadProgram(cwd, *tsconfigPath, driver.LoadProgramOptions{
62
- ForceEmit: true,
63
- })
64
- if err != nil {
65
- fmt.Fprintf(stderr, "ttsc api-compile: %v\n", err)
66
- return 2
67
- }
68
- if prog != nil {
69
- defer prog.Close()
70
- diags = append(diags, prog.Diagnostics()...)
71
- }
61
+ prog, diags, err := driver.LoadProgram(cwd, *tsconfigPath, driver.LoadProgramOptions{
62
+ ForceEmit: true,
63
+ })
64
+ if err != nil {
65
+ fmt.Fprintf(stderr, "ttsc api-compile: %v\n", err)
66
+ return 2
67
+ }
68
+ if prog != nil {
69
+ defer prog.Close()
70
+ diags = append(diags, prog.Diagnostics()...)
71
+ }
72
72
 
73
- output := map[string]string{}
74
- if prog != nil {
75
- rewrites := driver.NewRewriteSet()
76
- // Capture WriteFile output in a map keyed by project-relative paths. This
77
- // gives the JS API a deterministic object and avoids touching outDir.
78
- writeFile := shimcompiler.WriteFile(
79
- func(fileName, text string, _ *shimcompiler.WriteFileData) error {
80
- output[apiOutputKey(cwd, fileName)] = text
81
- return nil
82
- },
83
- )
84
- _, emitDiags, err := prog.EmitAll(rewrites, writeFile)
85
- if err != nil {
86
- fmt.Fprintf(stderr, "ttsc api-compile: emit failed: %v\n", err)
87
- return 3
88
- }
89
- diags = append(diags, emitDiags...)
90
- }
73
+ output := map[string]string{}
74
+ if prog != nil {
75
+ rewrites := driver.NewRewriteSet()
76
+ // Capture WriteFile output in a map keyed by project-relative paths. This
77
+ // gives the JS API a deterministic object and avoids touching outDir.
78
+ writeFile := shimcompiler.WriteFile(
79
+ func(fileName, text string, _ *shimcompiler.WriteFileData) error {
80
+ output[apiOutputKey(cwd, fileName)] = text
81
+ return nil
82
+ },
83
+ )
84
+ _, emitDiags, err := prog.EmitAll(rewrites, writeFile)
85
+ if err != nil {
86
+ fmt.Fprintf(stderr, "ttsc api-compile: emit failed: %v\n", err)
87
+ return 3
88
+ }
89
+ diags = append(diags, emitDiags...)
90
+ }
91
91
 
92
- result := apiCompileResult{
93
- Diagnostics: make([]apiCompileDiagnostic, 0, len(diags)),
94
- Output: output,
95
- }
96
- for _, diag := range diags {
97
- result.Diagnostics = append(result.Diagnostics, toAPICompileDiagnostic(diag))
98
- }
92
+ result := apiCompileResult{
93
+ Diagnostics: make([]apiCompileDiagnostic, 0, len(diags)),
94
+ Output: output,
95
+ }
96
+ for _, diag := range diags {
97
+ result.Diagnostics = append(result.Diagnostics, toAPICompileDiagnostic(diag))
98
+ }
99
99
 
100
- data, err := json.Marshal(result)
101
- if err != nil {
102
- fmt.Fprintf(stderr, "ttsc api-compile: result marshal failed: %v\n", err)
103
- return 3
104
- }
105
- fmt.Fprintln(stdout, string(data))
106
- if driver.CountErrors(diags) > 0 {
107
- return 2
108
- }
109
- return 0
100
+ data, err := json.Marshal(result)
101
+ if err != nil {
102
+ fmt.Fprintf(stderr, "ttsc api-compile: result marshal failed: %v\n", err)
103
+ return 3
104
+ }
105
+ fmt.Fprintln(stdout, string(data))
106
+ if driver.CountErrors(diags) > 0 {
107
+ return 2
108
+ }
109
+ return 0
110
110
  }
111
111
 
112
112
  func toAPICompileDiagnostic(diag driver.Diagnostic) apiCompileDiagnostic {
113
- var file *string
114
- if diag.File != "" {
115
- value := diag.File
116
- file = &value
117
- }
118
- category := "error"
119
- if diag.Severity == driver.SeverityWarning {
120
- category = "warning"
121
- }
122
- return apiCompileDiagnostic{
123
- File: file,
124
- Category: category,
125
- Code: diag.Code,
126
- Start: diag.Start,
127
- Length: diag.Length,
128
- Line: diag.Line,
129
- Character: diag.Column,
130
- MessageText: diag.Message,
131
- }
113
+ var file *string
114
+ if diag.File != "" {
115
+ value := diag.File
116
+ file = &value
117
+ }
118
+ category := "error"
119
+ if diag.Severity == driver.SeverityWarning {
120
+ category = "warning"
121
+ }
122
+ return apiCompileDiagnostic{
123
+ File: file,
124
+ Category: category,
125
+ Code: diag.Code,
126
+ Start: diag.Start,
127
+ Length: diag.Length,
128
+ Line: diag.Line,
129
+ Character: diag.Column,
130
+ MessageText: diag.Message,
131
+ }
132
132
  }
133
133
 
134
134
  func apiOutputKey(cwd, fileName string) string {
135
- // Relative keys are the API contract for files inside the project. Absolute
136
- // keys are preserved for uncommon compiler outputs outside cwd.
137
- if rel, err := filepath.Rel(cwd, fileName); err == nil && !isOutsideRelativePath(rel) {
138
- return filepath.ToSlash(rel)
139
- }
140
- return filepath.ToSlash(fileName)
135
+ // Relative keys are the API contract for files inside the project. Absolute
136
+ // keys are preserved for uncommon compiler outputs outside cwd.
137
+ if rel, err := filepath.Rel(cwd, fileName); err == nil && !isOutsideRelativePath(rel) {
138
+ return filepath.ToSlash(rel)
139
+ }
140
+ return filepath.ToSlash(fileName)
141
141
  }
142
142
 
143
143
  func isOutsideRelativePath(rel string) bool {
144
- return rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator))
144
+ return rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator))
145
145
  }
@@ -7,69 +7,69 @@
7
7
  package main
8
8
 
9
9
  import (
10
- "encoding/json"
11
- "flag"
12
- "fmt"
13
- "os"
10
+ "encoding/json"
11
+ "flag"
12
+ "fmt"
13
+ "os"
14
14
 
15
- "github.com/samchon/ttsc/packages/ttsc/driver"
16
- cwdutil "github.com/samchon/ttsc/packages/ttsc/internal/cwd"
15
+ "github.com/samchon/ttsc/packages/ttsc/driver"
16
+ cwdutil "github.com/samchon/ttsc/packages/ttsc/internal/cwd"
17
17
  )
18
18
 
19
19
  type apiTransformResult struct {
20
- // TypeScript contains every non-library source file visible through the
21
- // Program facade, keyed the same way api-compile keys emitted files.
22
- Diagnostics []apiCompileDiagnostic `json:"diagnostics,omitempty"`
23
- TypeScript map[string]string `json:"typescript"`
20
+ // TypeScript contains every non-library source file visible through the
21
+ // Program facade, keyed the same way api-compile keys emitted files.
22
+ Diagnostics []apiCompileDiagnostic `json:"diagnostics,omitempty"`
23
+ TypeScript map[string]string `json:"typescript"`
24
24
  }
25
25
 
26
26
  func runAPITransform(args []string) int {
27
- fs := flag.NewFlagSet("api-transform", flag.ContinueOnError)
28
- fs.SetOutput(stderr)
29
- tsconfigPath := fs.String("tsconfig", "tsconfig.json", "path to tsconfig.json")
30
- cwdOverride := fs.String("cwd", "", "override the working directory")
31
- if err := fs.Parse(args); err != nil {
32
- return 2
33
- }
27
+ fs := flag.NewFlagSet("api-transform", flag.ContinueOnError)
28
+ fs.SetOutput(stderr)
29
+ tsconfigPath := fs.String("tsconfig", "tsconfig.json", "path to tsconfig.json")
30
+ cwdOverride := fs.String("cwd", "", "override the working directory")
31
+ if err := fs.Parse(args); err != nil {
32
+ return 2
33
+ }
34
34
 
35
- cwd, err := cwdutil.Resolve(*cwdOverride, os.Getwd)
36
- if err != nil {
37
- fmt.Fprintf(stderr, "ttsc: %v\n", err)
38
- return 2
39
- }
35
+ cwd, err := cwdutil.Resolve(*cwdOverride, os.Getwd)
36
+ if err != nil {
37
+ fmt.Fprintf(stderr, "ttsc: %v\n", err)
38
+ return 2
39
+ }
40
40
 
41
- prog, diags, err := driver.LoadProgram(cwd, *tsconfigPath, driver.LoadProgramOptions{
42
- ForceNoEmit: true,
43
- })
44
- if err != nil {
45
- fmt.Fprintf(stderr, "ttsc api-transform: %v\n", err)
46
- return 2
47
- }
48
- typescript := map[string]string{}
49
- if prog != nil {
50
- defer prog.Close()
51
- for _, file := range prog.SourceFiles() {
52
- typescript[apiOutputKey(cwd, file.FileName())] = file.Text()
53
- }
54
- diags = append(diags, prog.Diagnostics()...)
55
- }
41
+ prog, diags, err := driver.LoadProgram(cwd, *tsconfigPath, driver.LoadProgramOptions{
42
+ ForceNoEmit: true,
43
+ })
44
+ if err != nil {
45
+ fmt.Fprintf(stderr, "ttsc api-transform: %v\n", err)
46
+ return 2
47
+ }
48
+ typescript := map[string]string{}
49
+ if prog != nil {
50
+ defer prog.Close()
51
+ for _, file := range prog.SourceFiles() {
52
+ typescript[apiOutputKey(cwd, file.FileName())] = file.Text()
53
+ }
54
+ diags = append(diags, prog.Diagnostics()...)
55
+ }
56
56
 
57
- result := apiTransformResult{
58
- Diagnostics: make([]apiCompileDiagnostic, 0, len(diags)),
59
- TypeScript: typescript,
60
- }
61
- for _, diag := range diags {
62
- result.Diagnostics = append(result.Diagnostics, toAPICompileDiagnostic(diag))
63
- }
57
+ result := apiTransformResult{
58
+ Diagnostics: make([]apiCompileDiagnostic, 0, len(diags)),
59
+ TypeScript: typescript,
60
+ }
61
+ for _, diag := range diags {
62
+ result.Diagnostics = append(result.Diagnostics, toAPICompileDiagnostic(diag))
63
+ }
64
64
 
65
- data, err := json.Marshal(result)
66
- if err != nil {
67
- fmt.Fprintf(stderr, "ttsc api-transform: result marshal failed: %v\n", err)
68
- return 3
69
- }
70
- fmt.Fprintln(stdout, string(data))
71
- if driver.CountErrors(diags) > 0 {
72
- return 2
73
- }
74
- return 0
65
+ data, err := json.Marshal(result)
66
+ if err != nil {
67
+ fmt.Fprintf(stderr, "ttsc api-transform: result marshal failed: %v\n", err)
68
+ return 3
69
+ }
70
+ fmt.Fprintln(stdout, string(data))
71
+ if driver.CountErrors(diags) > 0 {
72
+ return 2
73
+ }
74
+ return 0
75
75
  }
package/cmd/ttsc/main.go CHANGED
@@ -12,103 +12,103 @@
12
12
  package main
13
13
 
14
14
  import (
15
- "flag"
16
- "fmt"
17
- "io"
18
- "os"
19
- "runtime"
20
- "strings"
15
+ "flag"
16
+ "fmt"
17
+ "io"
18
+ "os"
19
+ "runtime"
20
+ "strings"
21
21
  )
22
22
 
23
23
  // These are overridden via `-ldflags "-X main.version=... -X main.commit=..."`
24
24
  // in CI. Sensible defaults keep local `go run ./cmd/ttsc` usable.
25
25
  var (
26
- version = "0.0.0-dev"
27
- commit = "dev"
28
- date = "unknown"
26
+ version = "0.0.0-dev"
27
+ commit = "dev"
28
+ date = "unknown"
29
29
  )
30
30
 
31
31
  // stdout / stderr are package-level to keep the CLI testable.
32
32
  var (
33
- stdout io.Writer = os.Stdout
34
- stderr io.Writer = os.Stderr
33
+ stdout io.Writer = os.Stdout
34
+ stderr io.Writer = os.Stderr
35
35
  )
36
36
 
37
37
  func main() {
38
- os.Exit(run(os.Args[1:]))
38
+ os.Exit(run(os.Args[1:]))
39
39
  }
40
40
 
41
41
  func run(args []string) int {
42
- if len(args) == 0 {
43
- return runBuild(nil)
44
- }
45
-
46
- switch args[0] {
47
- case "-h", "--help", "help":
48
- printHelp(stdout)
49
- return 0
50
- case "-v", "--version", "version":
51
- printVersion(stdout)
52
- return 0
53
- case "demo":
54
- return runDemo(args[1:])
55
- case "build":
56
- return runBuild(args[1:])
57
- case "api-compile":
58
- return runAPICompile(args[1:])
59
- case "api-transform":
60
- return runAPITransform(args[1:])
61
- case "check":
62
- // `ttsc check` runs the analyze pipeline without emitting JS — useful
63
- // in CI and pre-commit checks that only need schema validation.
64
- return runBuild(append([]string{"--noEmit"}, args[1:]...))
65
- case "-p", "--project":
66
- if len(args) < 2 {
67
- fmt.Fprintln(stderr, "ttsc: -p/--project requires a path argument")
68
- return 2
69
- }
70
- return runBuild(append([]string{"--tsconfig=" + args[1]}, args[2:]...))
71
- default:
72
- if isBuildAlias(args[0]) {
73
- return runBuild(args)
74
- }
75
- fmt.Fprintf(stderr, "ttsc: unknown command %q\n", args[0])
76
- fmt.Fprintln(stderr, `ttsc: run "ttsc --help" to see supported commands`)
77
- return 2
78
- }
42
+ if len(args) == 0 {
43
+ return runBuild(nil)
44
+ }
45
+
46
+ switch args[0] {
47
+ case "-h", "--help", "help":
48
+ printHelp(stdout)
49
+ return 0
50
+ case "-v", "--version", "version":
51
+ printVersion(stdout)
52
+ return 0
53
+ case "demo":
54
+ return runDemo(args[1:])
55
+ case "build":
56
+ return runBuild(args[1:])
57
+ case "api-compile":
58
+ return runAPICompile(args[1:])
59
+ case "api-transform":
60
+ return runAPITransform(args[1:])
61
+ case "check":
62
+ // `ttsc check` runs the analyze pipeline without emitting JS — useful
63
+ // in CI and pre-commit checks that only need schema validation.
64
+ return runBuild(append([]string{"--noEmit"}, args[1:]...))
65
+ case "-p", "--project":
66
+ if len(args) < 2 {
67
+ fmt.Fprintln(stderr, "ttsc: -p/--project requires a path argument")
68
+ return 2
69
+ }
70
+ return runBuild(append([]string{"--tsconfig=" + args[1]}, args[2:]...))
71
+ default:
72
+ if isBuildAlias(args[0]) {
73
+ return runBuild(args)
74
+ }
75
+ fmt.Fprintf(stderr, "ttsc: unknown command %q\n", args[0])
76
+ fmt.Fprintln(stderr, `ttsc: run "ttsc --help" to see supported commands`)
77
+ return 2
78
+ }
79
79
  }
80
80
 
81
81
  func isBuildAlias(arg string) bool {
82
- if strings.HasPrefix(arg, "-") {
83
- return true
84
- }
85
- switch {
86
- case strings.HasSuffix(arg, ".json"),
87
- strings.HasSuffix(arg, ".ts"),
88
- strings.HasSuffix(arg, ".tsx"),
89
- strings.HasSuffix(arg, ".mts"),
90
- strings.HasSuffix(arg, ".cts"):
91
- return true
92
- default:
93
- return false
94
- }
82
+ if strings.HasPrefix(arg, "-") {
83
+ return true
84
+ }
85
+ switch {
86
+ case strings.HasSuffix(arg, ".json"),
87
+ strings.HasSuffix(arg, ".ts"),
88
+ strings.HasSuffix(arg, ".tsx"),
89
+ strings.HasSuffix(arg, ".mts"),
90
+ strings.HasSuffix(arg, ".cts"):
91
+ return true
92
+ default:
93
+ return false
94
+ }
95
95
  }
96
96
 
97
97
  func printVersion(w io.Writer) {
98
- fmt.Fprintf(
99
- w,
100
- "ttsc %s (commit %s, built %s, %s/%s, go %s)\n",
101
- version,
102
- commit,
103
- date,
104
- runtime.GOOS,
105
- runtime.GOARCH,
106
- runtime.Version(),
107
- )
98
+ fmt.Fprintf(
99
+ w,
100
+ "ttsc %s (commit %s, built %s, %s/%s, go %s)\n",
101
+ version,
102
+ commit,
103
+ date,
104
+ runtime.GOOS,
105
+ runtime.GOARCH,
106
+ runtime.Version(),
107
+ )
108
108
  }
109
109
 
110
110
  func printHelp(w io.Writer) {
111
- fmt.Fprintln(w, strings.TrimSpace(`
111
+ fmt.Fprintln(w, strings.TrimSpace(`
112
112
  ttsc — standalone typescript-go host.
113
113
 
114
114
  Usage:
@@ -154,37 +154,37 @@ Integration guide (bundlers):
154
154
  }
155
155
 
156
156
  func runDemo(args []string) int {
157
- fs := flag.NewFlagSet("demo", flag.ContinueOnError)
158
- fs.SetOutput(stderr)
159
- typ := fs.String("type", "string", "atomic type to simulate")
160
- if err := fs.Parse(args); err != nil {
161
- return 2
162
- }
163
-
164
- arrow, err := demoArrow(*typ)
165
- if err != nil {
166
- fmt.Fprintf(stderr, "ttsc demo: %v\n", err)
167
- return 2
168
- }
169
-
170
- fmt.Fprintf(stdout, "// demo<%s> -> emitted by ttsc %s\n", *typ, version)
171
- fmt.Fprintln(stdout, arrow)
172
- return 0
157
+ fs := flag.NewFlagSet("demo", flag.ContinueOnError)
158
+ fs.SetOutput(stderr)
159
+ typ := fs.String("type", "string", "atomic type to simulate")
160
+ if err := fs.Parse(args); err != nil {
161
+ return 2
162
+ }
163
+
164
+ arrow, err := demoArrow(*typ)
165
+ if err != nil {
166
+ fmt.Fprintf(stderr, "ttsc demo: %v\n", err)
167
+ return 2
168
+ }
169
+
170
+ fmt.Fprintf(stdout, "// demo<%s> -> emitted by ttsc %s\n", *typ, version)
171
+ fmt.Fprintln(stdout, arrow)
172
+ return 0
173
173
  }
174
174
 
175
175
  func demoArrow(name string) (string, error) {
176
- switch strings.ToLower(name) {
177
- case "any":
178
- return "(input) => true", nil
179
- case "boolean":
180
- return `(input) => "boolean" === typeof input`, nil
181
- case "number":
182
- return `(input) => "number" === typeof input`, nil
183
- case "bigint":
184
- return `(input) => "bigint" === typeof input`, nil
185
- case "string", "":
186
- return `(input) => "string" === typeof input`, nil
187
- default:
188
- return "", fmt.Errorf("unknown --type value %q (want: string|number|boolean|bigint|any)", name)
189
- }
176
+ switch strings.ToLower(name) {
177
+ case "any":
178
+ return "(input) => true", nil
179
+ case "boolean":
180
+ return `(input) => "boolean" === typeof input`, nil
181
+ case "number":
182
+ return `(input) => "number" === typeof input`, nil
183
+ case "bigint":
184
+ return `(input) => "bigint" === typeof input`, nil
185
+ case "string", "":
186
+ return `(input) => "string" === typeof input`, nil
187
+ default:
188
+ return "", fmt.Errorf("unknown --type value %q (want: string|number|boolean|bigint|any)", name)
189
+ }
190
190
  }
@@ -0,0 +1,27 @@
1
+ package main
2
+
3
+ import (
4
+ "io"
5
+ "testing"
6
+ )
7
+
8
+ // withIO swaps the package-level stdin/stdout/stderr around fn and
9
+ // restores them on exit. Internal cmd tests use it to capture writer
10
+ // output without touching os.Stdout/os.Stderr.
11
+ func withIO(t *testing.T, out io.Writer, err io.Writer, in io.Reader, fn func()) {
12
+ t.Helper()
13
+ prevOut, prevErr, prevIn := stdout, stderr, stdin
14
+ defer func() {
15
+ stdout, stderr, stdin = prevOut, prevErr, prevIn
16
+ }()
17
+ if out != nil {
18
+ stdout = out
19
+ }
20
+ if err != nil {
21
+ stderr = err
22
+ }
23
+ if in != nil {
24
+ stdin = in
25
+ }
26
+ fn()
27
+ }