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