ttsc 0.11.0 → 0.12.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.
- package/README.md +25 -6
- package/cmd/ttsc/api_compile.go +101 -106
- package/cmd/ttsc/api_compile_branches_test.go +81 -0
- package/cmd/ttsc/api_transform.go +49 -54
- package/cmd/ttsc/api_transform_branches_test.go +41 -0
- package/cmd/ttsc/build.go +108 -109
- package/cmd/ttsc/build_branches_test.go +130 -0
- package/cmd/ttsc/helpers_test.go +47 -0
- package/cmd/ttsc/main.go +104 -103
- package/cmd/ttsc/main_alias_branches_test.go +29 -0
- package/cmd/ttscserver/main.go +104 -96
- package/cmd/ttscserver/run_lsp_prefers_tsgo_flag_test.go +42 -0
- package/cmd/ttscserver/run_lsp_reports_server_error_test.go +23 -25
- package/cmd/ttscserver/run_lsp_uses_tsgo_environment_test.go +44 -0
- package/cmd/utility-host/main.go +42 -0
- package/driver/lsp.go +60 -0
- package/driver/plugins.go +122 -0
- package/driver/program.go +346 -356
- package/driver/rewrite.go +336 -339
- package/{driver → internal/lspserver}/lsp_envelope.go +70 -64
- package/{driver → internal/lspserver}/lsp_frame.go +62 -62
- package/{driver → internal/lspserver}/lsp_plugin.go +58 -58
- package/internal/lspserver/lsp_proxy.go +391 -0
- package/internal/lspserver/lsp_server.go +231 -0
- package/lib/TtscCompiler.d.ts +3 -3
- package/lib/TtscCompiler.js +20 -6
- package/lib/TtscCompiler.js.map +1 -1
- package/lib/compiler/internal/resolveTsgo.d.ts +1 -0
- package/lib/compiler/internal/resolveTsgo.js +15 -4
- package/lib/compiler/internal/resolveTsgo.js.map +1 -1
- package/lib/compiler/internal/runBuild.js +12 -4
- package/lib/compiler/internal/runBuild.js.map +1 -1
- package/lib/compiler/internal/sharedHostHelpers.d.ts +12 -33
- package/lib/compiler/internal/sharedHostHelpers.js +27 -70
- package/lib/compiler/internal/sharedHostHelpers.js.map +1 -1
- package/lib/compiler/internal/transformProjectInMemory.js +12 -5
- package/lib/compiler/internal/transformProjectInMemory.js.map +1 -1
- package/lib/index.d.ts +0 -1
- package/lib/index.js +0 -1
- package/lib/index.js.map +1 -1
- package/lib/launcher/internal/runTtsc.js +9 -4
- package/lib/launcher/internal/runTtsc.js.map +1 -1
- package/lib/launcher/internal/runTtscserver.d.ts +1 -0
- package/lib/launcher/internal/runTtscserver.js +38 -1
- package/lib/launcher/internal/runTtscserver.js.map +1 -1
- package/lib/plugin/internal/buildSourcePlugin.d.ts +3 -0
- package/lib/plugin/internal/buildSourcePlugin.js +444 -41
- package/lib/plugin/internal/buildSourcePlugin.js.map +1 -1
- package/lib/plugin/internal/loadProjectPlugins.js +153 -34
- package/lib/plugin/internal/loadProjectPlugins.js.map +1 -1
- package/lib/structures/ITtscCompilerContext.d.ts +2 -1
- package/lib/structures/ITtscPlugin.d.ts +8 -13
- package/lib/structures/ITtscPluginFactoryContext.d.ts +4 -5
- package/lib/structures/ITtscProjectPluginConfig.d.ts +2 -2
- package/lib/structures/internal/ITtscLoadedNativePlugin.d.ts +4 -2
- package/package.json +8 -8
- package/shim/lsp/shim.go +11 -17
- package/src/TtscCompiler.ts +20 -7
- package/src/compiler/internal/resolveTsgo.ts +18 -5
- package/src/compiler/internal/runBuild.ts +17 -4
- package/src/compiler/internal/sharedHostHelpers.ts +34 -67
- package/src/compiler/internal/transformProjectInMemory.ts +18 -5
- package/src/index.ts +0 -1
- package/src/launcher/internal/runTtsc.ts +9 -4
- package/src/launcher/internal/runTtscserver.ts +43 -1
- package/src/plugin/internal/buildSourcePlugin.ts +475 -41
- package/src/plugin/internal/loadProjectPlugins.ts +199 -39
- package/src/structures/ITtscCompilerContext.ts +2 -1
- package/src/structures/ITtscPlugin.ts +9 -13
- package/src/structures/ITtscPluginFactoryContext.ts +4 -5
- package/src/structures/ITtscProjectPluginConfig.ts +2 -2
- package/src/structures/internal/ITtscLoadedNativePlugin.ts +4 -2
- package/utility/host.go +267 -1296
- package/driver/lsp_proxy.go +0 -394
- package/driver/lsp_server.go +0 -197
- package/lib/defineTtscPlugin.d.ts +0 -18
- package/lib/defineTtscPlugin.js +0 -7
- package/lib/defineTtscPlugin.js.map +0 -1
- package/src/defineTtscPlugin.ts +0 -26
package/cmd/ttsc/build.go
CHANGED
|
@@ -8,15 +8,15 @@
|
|
|
8
8
|
package main
|
|
9
9
|
|
|
10
10
|
import (
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
"encoding/json"
|
|
12
|
+
"flag"
|
|
13
|
+
"fmt"
|
|
14
|
+
"os"
|
|
15
|
+
"path/filepath"
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
shimcompiler "github.com/microsoft/typescript-go/shim/compiler"
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
"github.com/samchon/ttsc/packages/ttsc/driver"
|
|
20
20
|
)
|
|
21
21
|
|
|
22
22
|
// runBuild implements the `ttsc` project-build lane. Two modes:
|
|
@@ -25,111 +25,110 @@ import (
|
|
|
25
25
|
// - --emit: also run tsgo's emit pipeline, patching every recognized native
|
|
26
26
|
// consumer call in the resulting .js files.
|
|
27
27
|
func runBuild(args []string) int {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
28
|
+
fs := flag.NewFlagSet("build", flag.ContinueOnError)
|
|
29
|
+
fs.SetOutput(stderr)
|
|
30
|
+
tsconfigPath := fs.String("tsconfig", "tsconfig.json", "path to tsconfig.json")
|
|
31
|
+
cwdOverride := fs.String("cwd", "", "override the working directory (defaults to process cwd)")
|
|
32
|
+
quiet := fs.Bool("quiet", true, "suppress the per-call diagnostic summary")
|
|
33
|
+
verbose := fs.Bool("verbose", false, "print the per-call diagnostic summary")
|
|
34
|
+
emit := fs.Bool("emit", false, "force emitted .js files (runs tsgo + ttsc rewrite)")
|
|
35
|
+
noEmit := fs.Bool("noEmit", false, "force analysis-only run with no file writes")
|
|
36
|
+
outDir := fs.String("outDir", "", "override compilerOptions.outDir for this build")
|
|
37
|
+
manifestPath := fs.String("manifest", "", "write emitted file list as JSON to this path")
|
|
38
|
+
if err := fs.Parse(args); err != nil {
|
|
39
|
+
return 2
|
|
40
|
+
}
|
|
41
|
+
if *emit && *noEmit {
|
|
42
|
+
fmt.Fprintln(stderr, "ttsc: --emit and --noEmit are mutually exclusive")
|
|
43
|
+
return 2
|
|
44
|
+
}
|
|
45
|
+
if *verbose {
|
|
46
|
+
*quiet = false
|
|
47
|
+
}
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
49
|
+
cwd := *cwdOverride
|
|
50
|
+
if cwd == "" {
|
|
51
|
+
var err error
|
|
52
|
+
cwd, err = getwd()
|
|
53
|
+
if err != nil {
|
|
54
|
+
fmt.Fprintf(stderr, "ttsc: could not get working directory: %v\n", err)
|
|
55
|
+
return 2
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
59
|
+
prog, diags, err := driver.LoadProgram(cwd, *tsconfigPath, driver.LoadProgramOptions{
|
|
60
|
+
ForceEmit: *emit,
|
|
61
|
+
ForceNoEmit: *noEmit,
|
|
62
|
+
OutDir: *outDir,
|
|
63
|
+
})
|
|
64
|
+
if err != nil {
|
|
65
|
+
fmt.Fprintf(stderr, "ttsc: %v\n", err)
|
|
66
|
+
return 2
|
|
67
|
+
}
|
|
68
|
+
if len(diags) > 0 {
|
|
69
|
+
driver.WritePrettyDiagnostics(stderr, diags, cwd)
|
|
70
|
+
return 2
|
|
71
|
+
}
|
|
72
|
+
defer prog.Close()
|
|
73
|
+
if diags := prog.Diagnostics(); len(diags) > 0 {
|
|
74
|
+
driver.WritePrettyDiagnostics(stderr, diags, cwd)
|
|
75
|
+
return 2
|
|
76
|
+
}
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
78
|
+
rewrites := driver.NewRewriteSet()
|
|
79
|
+
shouldEmit := !prog.ParsedConfig.ParsedConfig.CompilerOptions.NoEmit.IsTrue()
|
|
80
|
+
if !*quiet {
|
|
81
|
+
fmt.Fprintf(stdout, "// ttsc: tsconfig=%s cwd=%s sites=%d emit=%v\n", *tsconfigPath, cwd, 0, shouldEmit)
|
|
82
|
+
}
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
84
|
+
if shouldEmit {
|
|
85
|
+
// Emit is callback-driven in TypeScript-Go. ttsc keeps that shape and
|
|
86
|
+
// wraps only the final WriteFile step so native rewrites and custom output
|
|
87
|
+
// capture share the same path.
|
|
88
|
+
writeFile := shimcompiler.WriteFile(
|
|
89
|
+
func(fileName, text string, _ *shimcompiler.WriteFileData) error {
|
|
90
|
+
return driver.DefaultWriteFile(fileName, text)
|
|
91
|
+
},
|
|
92
|
+
)
|
|
93
|
+
res, eDiags, err := prog.EmitAll(rewrites, writeFile)
|
|
94
|
+
if err != nil {
|
|
95
|
+
fmt.Fprintf(stderr, "ttsc: emit failed: %v\n", err)
|
|
96
|
+
return 3
|
|
97
|
+
}
|
|
98
|
+
for _, d := range eDiags {
|
|
99
|
+
fmt.Fprintln(stderr, " -", d.String())
|
|
100
|
+
}
|
|
101
|
+
if driver.CountErrors(eDiags) > 0 {
|
|
102
|
+
return 2
|
|
103
|
+
}
|
|
104
|
+
if !*quiet {
|
|
105
|
+
fmt.Fprintf(stdout, "// ttsc: emitted=%d files\n", len(res.EmittedFiles))
|
|
106
|
+
for _, f := range res.EmittedFiles {
|
|
107
|
+
rel := f
|
|
108
|
+
if abs, err := filepath.Rel(cwd, f); err == nil {
|
|
109
|
+
rel = abs
|
|
110
|
+
}
|
|
111
|
+
fmt.Fprintln(stdout, " +", rel)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if *manifestPath != "" {
|
|
115
|
+
// The manifest is intentionally just the emitted file list. Higher
|
|
116
|
+
// layers already know the project and tsconfig, and tests compare this
|
|
117
|
+
// array as the build contract.
|
|
118
|
+
data, _ := json.Marshal(res.EmittedFiles)
|
|
119
|
+
if err := os.MkdirAll(filepath.Dir(*manifestPath), 0o755); err != nil {
|
|
120
|
+
fmt.Fprintf(stderr, "ttsc: manifest mkdir failed: %v\n", err)
|
|
121
|
+
return 3
|
|
122
|
+
}
|
|
123
|
+
if err := os.WriteFile(*manifestPath, data, 0o644); err != nil {
|
|
124
|
+
fmt.Fprintf(stderr, "ttsc: manifest write failed: %v\n", err)
|
|
125
|
+
return 3
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
130
129
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
130
|
+
if !*quiet {
|
|
131
|
+
fmt.Fprintf(stdout, "// ttsc: recognized=%d total=%d rewrites=%d\n", 0, 0, rewrites.Len())
|
|
132
|
+
}
|
|
133
|
+
return 0
|
|
135
134
|
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"errors"
|
|
5
|
+
"path/filepath"
|
|
6
|
+
"strings"
|
|
7
|
+
"testing"
|
|
8
|
+
|
|
9
|
+
"github.com/samchon/ttsc/packages/ttsc/driver"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
type buildApplyErrorPlugin struct{}
|
|
13
|
+
|
|
14
|
+
func (buildApplyErrorPlugin) ApplyProgram(*driver.Program, driver.PluginContext) error {
|
|
15
|
+
return errors.New("build apply boom")
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Verifies build command branches report setup, emit, and manifest failures.
|
|
20
|
+
*
|
|
21
|
+
* The native build command is the fallback compiler host behind ttsc. It must
|
|
22
|
+
* fail before writing partial output when flags, cwd, tsconfig, disk emit, or
|
|
23
|
+
* manifest paths are invalid.
|
|
24
|
+
*
|
|
25
|
+
* 1. Exercise bad flags, cwd failure, and project-load failures.
|
|
26
|
+
* 2. Force emit through an invalid outDir.
|
|
27
|
+
* 3. Force manifest mkdir and write failures after a valid emit.
|
|
28
|
+
*/
|
|
29
|
+
func TestBuildBranches(t *testing.T) {
|
|
30
|
+
code, _, _ := captureCommand(t, func() int {
|
|
31
|
+
return runBuild([]string{"--cwd"})
|
|
32
|
+
})
|
|
33
|
+
if code != 2 {
|
|
34
|
+
t.Fatalf("bad flag status mismatch: %d", code)
|
|
35
|
+
}
|
|
36
|
+
code, _, errText := captureCommand(t, func() int {
|
|
37
|
+
getwd = failGetwd
|
|
38
|
+
return runBuild(nil)
|
|
39
|
+
})
|
|
40
|
+
if code != 2 || !strings.Contains(errText, "cwd boom") {
|
|
41
|
+
t.Fatalf("cwd error mismatch: code=%d stderr=%q", code, errText)
|
|
42
|
+
}
|
|
43
|
+
root := t.TempDir()
|
|
44
|
+
code, _, errText = captureCommand(t, func() int {
|
|
45
|
+
return runBuild([]string{"--cwd", root, "--tsconfig", "missing.json"})
|
|
46
|
+
})
|
|
47
|
+
if code != 2 || !strings.Contains(errText, "tsconfig not found") {
|
|
48
|
+
t.Fatalf("missing config mismatch: code=%d stderr=%q", code, errText)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
writeCommandProjectFile(t, root, "tsconfig.json", `{
|
|
52
|
+
"compilerOptions": { "module": "commonjs", "target": "es2020", "strict": true },
|
|
53
|
+
"files": ["index.ts"]
|
|
54
|
+
}
|
|
55
|
+
`)
|
|
56
|
+
writeCommandProjectFile(t, root, "index.ts", `const value: number = "text";
|
|
57
|
+
export { value };
|
|
58
|
+
`)
|
|
59
|
+
code, _, errText = captureCommand(t, func() int {
|
|
60
|
+
return runBuild([]string{"--cwd", root, "--tsconfig", "tsconfig.json"})
|
|
61
|
+
})
|
|
62
|
+
if code != 2 || !strings.Contains(errText, "number") {
|
|
63
|
+
t.Fatalf("semantic diagnostics mismatch: code=%d stderr=%q", code, errText)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
writeCommandProjectFile(t, root, "tsconfig.json", `{
|
|
67
|
+
"compilerOptions": { "module": "not-a-module-kind", "target": "es2020" },
|
|
68
|
+
"files": ["index.ts"]
|
|
69
|
+
}
|
|
70
|
+
`)
|
|
71
|
+
code, _, errText = captureCommand(t, func() int {
|
|
72
|
+
return runBuild([]string{"--cwd", root, "--tsconfig", "tsconfig.json"})
|
|
73
|
+
})
|
|
74
|
+
if code != 2 || !strings.Contains(errText, "not-a-module-kind") {
|
|
75
|
+
t.Fatalf("invalid config mismatch: code=%d stderr=%q", code, errText)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
writeCommandProjectFile(t, root, "tsconfig.json", `{
|
|
79
|
+
"compilerOptions": { "module": "commonjs", "target": "es2020", "strict": true },
|
|
80
|
+
"files": ["index.ts"]
|
|
81
|
+
}
|
|
82
|
+
`)
|
|
83
|
+
writeCommandProjectFile(t, root, "index.ts", `export const value = 1;
|
|
84
|
+
`)
|
|
85
|
+
writeCommandProjectFile(t, root, "blocked", `not a directory`)
|
|
86
|
+
code, _, errText = captureCommand(t, func() int {
|
|
87
|
+
return runBuild([]string{"--cwd", root, "--tsconfig", "tsconfig.json", "--emit", "--outDir", "blocked"})
|
|
88
|
+
})
|
|
89
|
+
if code != 2 || !strings.Contains(errText, "not a directory") {
|
|
90
|
+
t.Fatalf("emit failure mismatch: code=%d stderr=%q", code, errText)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
resetCommandLinkedPluginRegistry()
|
|
94
|
+
driver.RegisterPlugin(buildApplyErrorPlugin{})
|
|
95
|
+
t.Cleanup(resetCommandLinkedPluginRegistry)
|
|
96
|
+
t.Setenv(driver.LinkedPluginsEnv, `[{"name":"error","stage":"transform","config":{}}]`)
|
|
97
|
+
code, _, errText = captureCommand(t, func() int {
|
|
98
|
+
return runBuild([]string{"--cwd", root, "--tsconfig", "tsconfig.json", "--emit", "--outDir", "dist"})
|
|
99
|
+
})
|
|
100
|
+
if code != 3 || !strings.Contains(errText, "build apply boom") {
|
|
101
|
+
t.Fatalf("linked apply failure mismatch: code=%d stderr=%q", code, errText)
|
|
102
|
+
}
|
|
103
|
+
resetCommandLinkedPluginRegistry()
|
|
104
|
+
t.Setenv(driver.LinkedPluginsEnv, "")
|
|
105
|
+
|
|
106
|
+
code, _, errText = captureCommand(t, func() int {
|
|
107
|
+
return runBuild([]string{
|
|
108
|
+
"--cwd", root,
|
|
109
|
+
"--tsconfig", "tsconfig.json",
|
|
110
|
+
"--emit",
|
|
111
|
+
"--outDir", "dist",
|
|
112
|
+
"--manifest", filepath.Join(root, "index.ts", "manifest.json"),
|
|
113
|
+
})
|
|
114
|
+
})
|
|
115
|
+
if code != 3 || !strings.Contains(errText, "manifest mkdir failed") {
|
|
116
|
+
t.Fatalf("manifest mkdir mismatch: code=%d stderr=%q", code, errText)
|
|
117
|
+
}
|
|
118
|
+
code, _, errText = captureCommand(t, func() int {
|
|
119
|
+
return runBuild([]string{
|
|
120
|
+
"--cwd", root,
|
|
121
|
+
"--tsconfig", "tsconfig.json",
|
|
122
|
+
"--emit",
|
|
123
|
+
"--outDir", "dist",
|
|
124
|
+
"--manifest", root,
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
if code != 3 || !strings.Contains(errText, "manifest write failed") {
|
|
128
|
+
t.Fatalf("manifest write mismatch: code=%d stderr=%q", code, errText)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"bytes"
|
|
5
|
+
"errors"
|
|
6
|
+
"os"
|
|
7
|
+
"path/filepath"
|
|
8
|
+
"testing"
|
|
9
|
+
_ "unsafe"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
//go:linkname driverPluginRegistry github.com/samchon/ttsc/packages/ttsc/driver.pluginRegistry
|
|
13
|
+
var driverPluginRegistry []any
|
|
14
|
+
|
|
15
|
+
func captureCommand(t *testing.T, fn func() int) (int, string, string) {
|
|
16
|
+
t.Helper()
|
|
17
|
+
prevOut, prevErr, prevGetwd := stdout, stderr, getwd
|
|
18
|
+
var out, err bytes.Buffer
|
|
19
|
+
stdout = &out
|
|
20
|
+
stderr = &err
|
|
21
|
+
defer func() {
|
|
22
|
+
stdout = prevOut
|
|
23
|
+
stderr = prevErr
|
|
24
|
+
getwd = prevGetwd
|
|
25
|
+
}()
|
|
26
|
+
code := fn()
|
|
27
|
+
return code, out.String(), err.String()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
func failGetwd() (string, error) {
|
|
31
|
+
return "", errors.New("cwd boom")
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
func writeCommandProjectFile(t *testing.T, root, name, contents string) {
|
|
35
|
+
t.Helper()
|
|
36
|
+
file := filepath.Join(root, filepath.FromSlash(name))
|
|
37
|
+
if err := os.MkdirAll(filepath.Dir(file), 0o755); err != nil {
|
|
38
|
+
t.Fatal(err)
|
|
39
|
+
}
|
|
40
|
+
if err := os.WriteFile(file, []byte(contents), 0o644); err != nil {
|
|
41
|
+
t.Fatal(err)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
func resetCommandLinkedPluginRegistry() {
|
|
46
|
+
driverPluginRegistry = nil
|
|
47
|
+
}
|
package/cmd/ttsc/main.go
CHANGED
|
@@ -12,103 +12,104 @@
|
|
|
12
12
|
package main
|
|
13
13
|
|
|
14
14
|
import (
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
34
|
-
|
|
33
|
+
stdout io.Writer = os.Stdout
|
|
34
|
+
stderr io.Writer = os.Stderr
|
|
35
|
+
getwd = os.Getwd
|
|
35
36
|
)
|
|
36
37
|
|
|
37
38
|
func main() {
|
|
38
|
-
|
|
39
|
+
os.Exit(run(os.Args[1:]))
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
func run(args []string) int {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
43
|
+
if len(args) == 0 {
|
|
44
|
+
return runBuild(nil)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
switch args[0] {
|
|
48
|
+
case "-h", "--help", "help":
|
|
49
|
+
printHelp(stdout)
|
|
50
|
+
return 0
|
|
51
|
+
case "-v", "--version", "version":
|
|
52
|
+
printVersion(stdout)
|
|
53
|
+
return 0
|
|
54
|
+
case "demo":
|
|
55
|
+
return runDemo(args[1:])
|
|
56
|
+
case "build":
|
|
57
|
+
return runBuild(args[1:])
|
|
58
|
+
case "api-compile":
|
|
59
|
+
return runAPICompile(args[1:])
|
|
60
|
+
case "api-transform":
|
|
61
|
+
return runAPITransform(args[1:])
|
|
62
|
+
case "check":
|
|
63
|
+
// `ttsc check` runs the analyze pipeline without emitting JS — useful
|
|
64
|
+
// in CI and pre-commit checks that only need schema validation.
|
|
65
|
+
return runBuild(append([]string{"--noEmit"}, args[1:]...))
|
|
66
|
+
case "-p", "--project":
|
|
67
|
+
if len(args) < 2 {
|
|
68
|
+
fmt.Fprintln(stderr, "ttsc: -p/--project requires a path argument")
|
|
69
|
+
return 2
|
|
70
|
+
}
|
|
71
|
+
return runBuild(append([]string{"--tsconfig=" + args[1]}, args[2:]...))
|
|
72
|
+
default:
|
|
73
|
+
if isBuildAlias(args[0]) {
|
|
74
|
+
return runBuild(args)
|
|
75
|
+
}
|
|
76
|
+
fmt.Fprintf(stderr, "ttsc: unknown command %q\n", args[0])
|
|
77
|
+
fmt.Fprintln(stderr, `ttsc: run "ttsc --help" to see supported commands`)
|
|
78
|
+
return 2
|
|
79
|
+
}
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
func isBuildAlias(arg string) bool {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
83
|
+
if strings.HasPrefix(arg, "-") {
|
|
84
|
+
return true
|
|
85
|
+
}
|
|
86
|
+
switch {
|
|
87
|
+
case strings.HasSuffix(arg, ".json"),
|
|
88
|
+
strings.HasSuffix(arg, ".ts"),
|
|
89
|
+
strings.HasSuffix(arg, ".tsx"),
|
|
90
|
+
strings.HasSuffix(arg, ".mts"),
|
|
91
|
+
strings.HasSuffix(arg, ".cts"):
|
|
92
|
+
return true
|
|
93
|
+
default:
|
|
94
|
+
return false
|
|
95
|
+
}
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
func printVersion(w io.Writer) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
99
|
+
fmt.Fprintf(
|
|
100
|
+
w,
|
|
101
|
+
"ttsc %s (commit %s, built %s, %s/%s, go %s)\n",
|
|
102
|
+
version,
|
|
103
|
+
commit,
|
|
104
|
+
date,
|
|
105
|
+
runtime.GOOS,
|
|
106
|
+
runtime.GOARCH,
|
|
107
|
+
runtime.Version(),
|
|
108
|
+
)
|
|
108
109
|
}
|
|
109
110
|
|
|
110
111
|
func printHelp(w io.Writer) {
|
|
111
|
-
|
|
112
|
+
fmt.Fprintln(w, strings.TrimSpace(`
|
|
112
113
|
ttsc — standalone typescript-go host.
|
|
113
114
|
|
|
114
115
|
Usage:
|
|
@@ -154,37 +155,37 @@ Integration guide (bundlers):
|
|
|
154
155
|
}
|
|
155
156
|
|
|
156
157
|
func runDemo(args []string) int {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
158
|
+
fs := flag.NewFlagSet("demo", flag.ContinueOnError)
|
|
159
|
+
fs.SetOutput(stderr)
|
|
160
|
+
typ := fs.String("type", "string", "atomic type to simulate")
|
|
161
|
+
if err := fs.Parse(args); err != nil {
|
|
162
|
+
return 2
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
arrow, err := demoArrow(*typ)
|
|
166
|
+
if err != nil {
|
|
167
|
+
fmt.Fprintf(stderr, "ttsc demo: %v\n", err)
|
|
168
|
+
return 2
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
fmt.Fprintf(stdout, "// demo<%s> -> emitted by ttsc %s\n", *typ, version)
|
|
172
|
+
fmt.Fprintln(stdout, arrow)
|
|
173
|
+
return 0
|
|
173
174
|
}
|
|
174
175
|
|
|
175
176
|
func demoArrow(name string) (string, error) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
177
|
+
switch strings.ToLower(name) {
|
|
178
|
+
case "any":
|
|
179
|
+
return "(input) => true", nil
|
|
180
|
+
case "boolean":
|
|
181
|
+
return `(input) => "boolean" === typeof input`, nil
|
|
182
|
+
case "number":
|
|
183
|
+
return `(input) => "number" === typeof input`, nil
|
|
184
|
+
case "bigint":
|
|
185
|
+
return `(input) => "bigint" === typeof input`, nil
|
|
186
|
+
case "string", "":
|
|
187
|
+
return `(input) => "string" === typeof input`, nil
|
|
188
|
+
default:
|
|
189
|
+
return "", fmt.Errorf("unknown --type value %q (want: string|number|boolean|bigint|any)", name)
|
|
190
|
+
}
|
|
190
191
|
}
|