ttsc 0.11.0-dev.20260518-2 → 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 +27 -8
- 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 +9 -9
- 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/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# `ttsc`
|
|
2
2
|
|
|
3
|
-

|
|
4
4
|
|
|
5
5
|
[](https://github.com/samchon/ttsc/blob/master/LICENSE)
|
|
6
6
|
[](https://www.npmjs.com/package/ttsc)
|
|
7
7
|
[](https://www.npmjs.com/package/ttsc)
|
|
8
8
|
[](https://github.com/samchon/ttsc/actions?query=workflow%3Atest)
|
|
9
|
-
[](https://
|
|
9
|
+
[](https://ttsc.dev/docs)
|
|
10
10
|
[](https://discord.gg/E94XhzrUCZ)
|
|
11
11
|
|
|
12
12
|
A `typescript-go` toolchain for compiler-powered plugins and type-safe execution.
|
|
@@ -15,17 +15,19 @@ A `typescript-go` toolchain for compiler-powered plugins and type-safe execution
|
|
|
15
15
|
- **`ttsx`**: execute TypeScript with type checking.
|
|
16
16
|
- native TypeScript-Go execution instead of transpile-only runners.
|
|
17
17
|
- type checking that `tsx` does not provide.
|
|
18
|
+
- **`@ttsc/lint`**: replaces `eslint` and `prettier`.
|
|
19
|
+
- lint violations as TS compile errors.
|
|
20
|
+
- format autofixes via `ttsc format`.
|
|
18
21
|
- **plugin support**: compiler-powered libraries, such as `typia`.
|
|
19
|
-
- `@ttsc/lint`: lint violations as TS compile errors.
|
|
20
22
|
|
|
21
23
|
## Setup
|
|
22
24
|
|
|
23
25
|
### Install
|
|
24
26
|
|
|
25
|
-
Install the native TypeScript preview package
|
|
27
|
+
Install `ttsc`, `@ttsc/lint`, and the native TypeScript preview package:
|
|
26
28
|
|
|
27
29
|
```bash
|
|
28
|
-
npm install -D ttsc @typescript/native-preview
|
|
30
|
+
npm install -D ttsc @ttsc/lint @typescript/native-preview
|
|
29
31
|
```
|
|
30
32
|
|
|
31
33
|
### Commands
|
|
@@ -44,6 +46,23 @@ npx ttsc --noEmit
|
|
|
44
46
|
npx ttsc --watch
|
|
45
47
|
```
|
|
46
48
|
|
|
49
|
+
Rewrite source files in place with the `@ttsc/lint` format rules:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npx ttsc format
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Editor
|
|
56
|
+
|
|
57
|
+
Install the VS Code extension to see lint and plugin diagnostics live as you type:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npm install -D @ttsc/vscode
|
|
61
|
+
npx ttsc-vscode
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
See [`@ttsc/vscode`](https://github.com/samchon/ttsc/tree/master/packages/vscode) for requirements, settings, and uninstall.
|
|
65
|
+
|
|
47
66
|
### Bundlers
|
|
48
67
|
|
|
49
68
|
Use `@ttsc/unplugin` when a bundler owns your build.
|
|
@@ -51,7 +70,7 @@ Use `@ttsc/unplugin` when a bundler owns your build.
|
|
|
51
70
|
It runs `ttsc` plugins inside supported bundlers.
|
|
52
71
|
|
|
53
72
|
```bash
|
|
54
|
-
npm install -D ttsc @typescript/native-preview
|
|
73
|
+
npm install -D ttsc @ttsc/lint @typescript/native-preview
|
|
55
74
|
npm install -D @ttsc/unplugin
|
|
56
75
|
```
|
|
57
76
|
|
|
@@ -150,12 +169,12 @@ console.log(matched); // true
|
|
|
150
169
|
`ttsc` ships a few small utility plugins in this repository.
|
|
151
170
|
|
|
152
171
|
- [`@ttsc/banner`](https://github.com/samchon/ttsc/tree/master/packages/banner): adds `@packageDocumentation` JSDoc banners.
|
|
153
|
-
- [`@ttsc/lint`](https://github.com/samchon/ttsc/tree/master/packages/lint):
|
|
172
|
+
- [`@ttsc/lint`](https://github.com/samchon/ttsc/tree/master/packages/lint): lints and formats TypeScript source.
|
|
154
173
|
- [`@ttsc/paths`](https://github.com/samchon/ttsc/tree/master/packages/paths): rewrites source path aliases so JS and declaration emit receive relative imports.
|
|
155
174
|
- [`@ttsc/strip`](https://github.com/samchon/ttsc/tree/master/packages/strip): removes configured calls and `debugger` statements.
|
|
156
175
|
- [`@ttsc/unplugin`](https://github.com/samchon/ttsc/tree/master/packages/unplugin): runs `ttsc` plugins inside bundlers supported by `unplugin`.
|
|
157
176
|
|
|
158
|
-
Plugin authors should start from the [`Guide Documents`](https://
|
|
177
|
+
Plugin authors should start from the [`Guide Documents`](https://ttsc.dev/docs).
|
|
159
178
|
|
|
160
179
|
Ecosystem plugins are listed below; PRs adding `ttsc` plugins are welcome.
|
|
161
180
|
|
package/cmd/ttsc/api_compile.go
CHANGED
|
@@ -7,25 +7,24 @@
|
|
|
7
7
|
package main
|
|
8
8
|
|
|
9
9
|
import (
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"strings"
|
|
10
|
+
"encoding/json"
|
|
11
|
+
"flag"
|
|
12
|
+
"fmt"
|
|
13
|
+
"path/filepath"
|
|
14
|
+
"strings"
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
shimcompiler "github.com/microsoft/typescript-go/shim/compiler"
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
"github.com/samchon/ttsc/packages/ttsc/driver"
|
|
19
|
+
cwdutil "github.com/samchon/ttsc/packages/ttsc/internal/cwd"
|
|
21
20
|
)
|
|
22
21
|
|
|
23
22
|
type apiCompileResult struct {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
// Diagnostics is omitted only when the compiler produced no diagnostics.
|
|
24
|
+
// Output is still returned in diagnostic cases because TypeScript-Go may
|
|
25
|
+
// produce partial emit text before a build-failing error is reported.
|
|
26
|
+
Diagnostics []apiCompileDiagnostic `json:"diagnostics,omitempty"`
|
|
27
|
+
Output map[string]string `json:"output"`
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
// apiCompileDiagnostic mirrors the public TypeScript-side diagnostic DTO.
|
|
@@ -33,113 +32,109 @@ type apiCompileResult struct {
|
|
|
33
32
|
// `character`) instead of Go naming so callers can pass the data through
|
|
34
33
|
// without remapping.
|
|
35
34
|
type apiCompileDiagnostic struct {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
35
|
+
File *string `json:"file"`
|
|
36
|
+
Category string `json:"category"`
|
|
37
|
+
Code int32 `json:"code"`
|
|
38
|
+
Start *int `json:"start,omitempty"`
|
|
39
|
+
Length *int `json:"length,omitempty"`
|
|
40
|
+
Line int `json:"line,omitempty"`
|
|
41
|
+
Character int `json:"character,omitempty"`
|
|
42
|
+
MessageText string `json:"messageText"`
|
|
44
43
|
}
|
|
45
44
|
|
|
46
45
|
func runAPICompile(args []string) int {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
46
|
+
fs := flag.NewFlagSet("api-compile", flag.ContinueOnError)
|
|
47
|
+
fs.SetOutput(stderr)
|
|
48
|
+
tsconfigPath := fs.String("tsconfig", "tsconfig.json", "path to tsconfig.json")
|
|
49
|
+
cwdOverride := fs.String("cwd", "", "override the working directory")
|
|
50
|
+
if err := fs.Parse(args); err != nil {
|
|
51
|
+
return 2
|
|
52
|
+
}
|
|
54
53
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
cwd, err := cwdutil.Resolve(*cwdOverride, getwd)
|
|
55
|
+
if err != nil {
|
|
56
|
+
fmt.Fprintf(stderr, "ttsc: %v\n", err)
|
|
57
|
+
return 2
|
|
58
|
+
}
|
|
60
59
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
60
|
+
prog, diags, err := driver.LoadProgram(cwd, *tsconfigPath, driver.LoadProgramOptions{
|
|
61
|
+
ForceEmit: true,
|
|
62
|
+
})
|
|
63
|
+
if err != nil {
|
|
64
|
+
fmt.Fprintf(stderr, "ttsc api-compile: %v\n", err)
|
|
65
|
+
return 2
|
|
66
|
+
}
|
|
67
|
+
if prog != nil {
|
|
68
|
+
defer prog.Close()
|
|
69
|
+
diags = append(diags, prog.Diagnostics()...)
|
|
70
|
+
}
|
|
72
71
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
72
|
+
output := map[string]string{}
|
|
73
|
+
if prog != nil {
|
|
74
|
+
rewrites := driver.NewRewriteSet()
|
|
75
|
+
// Capture WriteFile output in a map keyed by project-relative paths. This
|
|
76
|
+
// gives the JS API a deterministic object and avoids touching outDir.
|
|
77
|
+
writeFile := shimcompiler.WriteFile(
|
|
78
|
+
func(fileName, text string, _ *shimcompiler.WriteFileData) error {
|
|
79
|
+
output[apiOutputKey(cwd, fileName)] = text
|
|
80
|
+
return nil
|
|
81
|
+
},
|
|
82
|
+
)
|
|
83
|
+
_, emitDiags, err := prog.EmitAll(rewrites, writeFile)
|
|
84
|
+
if err != nil {
|
|
85
|
+
fmt.Fprintf(stderr, "ttsc api-compile: emit failed: %v\n", err)
|
|
86
|
+
return 3
|
|
87
|
+
}
|
|
88
|
+
diags = append(diags, emitDiags...)
|
|
89
|
+
}
|
|
91
90
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
91
|
+
result := apiCompileResult{
|
|
92
|
+
Diagnostics: make([]apiCompileDiagnostic, 0, len(diags)),
|
|
93
|
+
Output: output,
|
|
94
|
+
}
|
|
95
|
+
for _, diag := range diags {
|
|
96
|
+
result.Diagnostics = append(result.Diagnostics, toAPICompileDiagnostic(diag))
|
|
97
|
+
}
|
|
99
98
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if driver.CountErrors(diags) > 0 {
|
|
107
|
-
return 2
|
|
108
|
-
}
|
|
109
|
-
return 0
|
|
99
|
+
data, _ := json.Marshal(result)
|
|
100
|
+
fmt.Fprintln(stdout, string(data))
|
|
101
|
+
if driver.CountErrors(diags) > 0 {
|
|
102
|
+
return 2
|
|
103
|
+
}
|
|
104
|
+
return 0
|
|
110
105
|
}
|
|
111
106
|
|
|
112
107
|
func toAPICompileDiagnostic(diag driver.Diagnostic) apiCompileDiagnostic {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
108
|
+
var file *string
|
|
109
|
+
if diag.File != "" {
|
|
110
|
+
value := diag.File
|
|
111
|
+
file = &value
|
|
112
|
+
}
|
|
113
|
+
category := "error"
|
|
114
|
+
if diag.Severity == driver.SeverityWarning {
|
|
115
|
+
category = "warning"
|
|
116
|
+
}
|
|
117
|
+
return apiCompileDiagnostic{
|
|
118
|
+
File: file,
|
|
119
|
+
Category: category,
|
|
120
|
+
Code: diag.Code,
|
|
121
|
+
Start: diag.Start,
|
|
122
|
+
Length: diag.Length,
|
|
123
|
+
Line: diag.Line,
|
|
124
|
+
Character: diag.Column,
|
|
125
|
+
MessageText: diag.Message,
|
|
126
|
+
}
|
|
132
127
|
}
|
|
133
128
|
|
|
134
129
|
func apiOutputKey(cwd, fileName string) string {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
130
|
+
// Relative keys are the API contract for files inside the project. Absolute
|
|
131
|
+
// keys are preserved for uncommon compiler outputs outside cwd.
|
|
132
|
+
if rel, err := filepath.Rel(cwd, fileName); err == nil && !isOutsideRelativePath(rel) {
|
|
133
|
+
return filepath.ToSlash(rel)
|
|
134
|
+
}
|
|
135
|
+
return filepath.ToSlash(fileName)
|
|
141
136
|
}
|
|
142
137
|
|
|
143
138
|
func isOutsideRelativePath(rel string) bool {
|
|
144
|
-
|
|
139
|
+
return rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator))
|
|
145
140
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"errors"
|
|
5
|
+
"strings"
|
|
6
|
+
"testing"
|
|
7
|
+
|
|
8
|
+
"github.com/samchon/ttsc/packages/ttsc/driver"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
type apiCompileApplyErrorPlugin struct{}
|
|
12
|
+
|
|
13
|
+
func (apiCompileApplyErrorPlugin) ApplyProgram(*driver.Program, driver.PluginContext) error {
|
|
14
|
+
return errors.New("api compile apply boom")
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Verifies api-compile handles parse, cwd, diagnostic, and emit failures.
|
|
19
|
+
*
|
|
20
|
+
* The JSON API path is used by the JS wrapper, so its command entrypoint must
|
|
21
|
+
* return stable status codes for wrapper misuse, project diagnostics, and
|
|
22
|
+
* linked transform failures.
|
|
23
|
+
*
|
|
24
|
+
* 1. Exercise bad flags and a failing cwd resolver.
|
|
25
|
+
* 2. Compile missing and type-invalid projects.
|
|
26
|
+
* 3. Assert linked ApplyProgram errors surface through the emit branch.
|
|
27
|
+
*/
|
|
28
|
+
func TestAPICompileBranches(t *testing.T) {
|
|
29
|
+
code, _, _ := captureCommand(t, func() int {
|
|
30
|
+
return runAPICompile([]string{"--cwd"})
|
|
31
|
+
})
|
|
32
|
+
if code != 2 {
|
|
33
|
+
t.Fatalf("bad flag status mismatch: %d", code)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
code, _, errText := captureCommand(t, func() int {
|
|
37
|
+
getwd = failGetwd
|
|
38
|
+
return runAPICompile(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
|
+
|
|
44
|
+
root := t.TempDir()
|
|
45
|
+
code, _, errText = captureCommand(t, func() int {
|
|
46
|
+
return runAPICompile([]string{"--cwd", root, "--tsconfig", "missing.json"})
|
|
47
|
+
})
|
|
48
|
+
if code != 2 || !strings.Contains(errText, "tsconfig not found") {
|
|
49
|
+
t.Fatalf("missing config mismatch: code=%d stderr=%q", code, errText)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
writeCommandProjectFile(t, root, "tsconfig.json", `{
|
|
53
|
+
"compilerOptions": { "module": "commonjs", "target": "es2020", "strict": true },
|
|
54
|
+
"files": ["index.ts"]
|
|
55
|
+
}
|
|
56
|
+
`)
|
|
57
|
+
writeCommandProjectFile(t, root, "index.ts", `const value: number = "text";
|
|
58
|
+
export { value };
|
|
59
|
+
`)
|
|
60
|
+
code, out, _ := captureCommand(t, func() int {
|
|
61
|
+
return runAPICompile([]string{"--cwd", root, "--tsconfig", "tsconfig.json"})
|
|
62
|
+
})
|
|
63
|
+
if code != 2 || !strings.Contains(out, `"diagnostics"`) {
|
|
64
|
+
t.Fatalf("diagnostic compile mismatch: code=%d stdout=%q", code, out)
|
|
65
|
+
}
|
|
66
|
+
if got := toAPICompileDiagnostic(driver.Diagnostic{Severity: driver.SeverityWarning}).Category; got != "warning" {
|
|
67
|
+
t.Fatalf("warning category mismatch: %q", got)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
resetCommandLinkedPluginRegistry()
|
|
71
|
+
driver.RegisterPlugin(apiCompileApplyErrorPlugin{})
|
|
72
|
+
t.Setenv(driver.LinkedPluginsEnv, `[{"name":"error","stage":"transform","config":{}}]`)
|
|
73
|
+
writeCommandProjectFile(t, root, "index.ts", `export const value = 1;
|
|
74
|
+
`)
|
|
75
|
+
code, _, errText = captureCommand(t, func() int {
|
|
76
|
+
return runAPICompile([]string{"--cwd", root, "--tsconfig", "tsconfig.json"})
|
|
77
|
+
})
|
|
78
|
+
if code != 3 || !strings.Contains(errText, "api compile apply boom") {
|
|
79
|
+
t.Fatalf("emit error mismatch: code=%d stderr=%q", code, errText)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -7,69 +7,64 @@
|
|
|
7
7
|
package main
|
|
8
8
|
|
|
9
9
|
import (
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"os"
|
|
10
|
+
"encoding/json"
|
|
11
|
+
"flag"
|
|
12
|
+
"fmt"
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
"github.com/samchon/ttsc/packages/ttsc/driver"
|
|
15
|
+
cwdutil "github.com/samchon/ttsc/packages/ttsc/internal/cwd"
|
|
17
16
|
)
|
|
18
17
|
|
|
19
18
|
type apiTransformResult struct {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
// TypeScript contains every non-library source file visible through the
|
|
20
|
+
// Program facade, keyed the same way api-compile keys emitted files.
|
|
21
|
+
Diagnostics []apiCompileDiagnostic `json:"diagnostics,omitempty"`
|
|
22
|
+
TypeScript map[string]string `json:"typescript"`
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
func runAPITransform(args []string) int {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
fs := flag.NewFlagSet("api-transform", flag.ContinueOnError)
|
|
27
|
+
fs.SetOutput(stderr)
|
|
28
|
+
tsconfigPath := fs.String("tsconfig", "tsconfig.json", "path to tsconfig.json")
|
|
29
|
+
cwdOverride := fs.String("cwd", "", "override the working directory")
|
|
30
|
+
if err := fs.Parse(args); err != nil {
|
|
31
|
+
return 2
|
|
32
|
+
}
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
cwd, err := cwdutil.Resolve(*cwdOverride, getwd)
|
|
35
|
+
if err != nil {
|
|
36
|
+
fmt.Fprintf(stderr, "ttsc: %v\n", err)
|
|
37
|
+
return 2
|
|
38
|
+
}
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
40
|
+
prog, diags, err := driver.LoadProgram(cwd, *tsconfigPath, driver.LoadProgramOptions{
|
|
41
|
+
ForceNoEmit: true,
|
|
42
|
+
})
|
|
43
|
+
if err != nil {
|
|
44
|
+
fmt.Fprintf(stderr, "ttsc api-transform: %v\n", err)
|
|
45
|
+
return 2
|
|
46
|
+
}
|
|
47
|
+
typescript := map[string]string{}
|
|
48
|
+
if prog != nil {
|
|
49
|
+
defer prog.Close()
|
|
50
|
+
for _, file := range prog.SourceFiles() {
|
|
51
|
+
typescript[apiOutputKey(cwd, file.FileName())] = file.Text()
|
|
52
|
+
}
|
|
53
|
+
diags = append(diags, prog.Diagnostics()...)
|
|
54
|
+
}
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
56
|
+
result := apiTransformResult{
|
|
57
|
+
Diagnostics: make([]apiCompileDiagnostic, 0, len(diags)),
|
|
58
|
+
TypeScript: typescript,
|
|
59
|
+
}
|
|
60
|
+
for _, diag := range diags {
|
|
61
|
+
result.Diagnostics = append(result.Diagnostics, toAPICompileDiagnostic(diag))
|
|
62
|
+
}
|
|
64
63
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if driver.CountErrors(diags) > 0 {
|
|
72
|
-
return 2
|
|
73
|
-
}
|
|
74
|
-
return 0
|
|
64
|
+
data, _ := json.Marshal(result)
|
|
65
|
+
fmt.Fprintln(stdout, string(data))
|
|
66
|
+
if driver.CountErrors(diags) > 0 {
|
|
67
|
+
return 2
|
|
68
|
+
}
|
|
69
|
+
return 0
|
|
75
70
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"strings"
|
|
5
|
+
"testing"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Verifies api-transform rejects invalid command and project setup.
|
|
10
|
+
*
|
|
11
|
+
* Source-to-source API callers need the same stable wrapper diagnostics as the
|
|
12
|
+
* compile API, but without touching emit. These branches are command-frontdoor
|
|
13
|
+
* behavior rather than TypeScript-Go internals.
|
|
14
|
+
*
|
|
15
|
+
* 1. Pass an incomplete flag.
|
|
16
|
+
* 2. Force cwd resolution to fail.
|
|
17
|
+
* 3. Point the API at a missing tsconfig.
|
|
18
|
+
*/
|
|
19
|
+
func TestAPITransformBranches(t *testing.T) {
|
|
20
|
+
code, _, _ := captureCommand(t, func() int {
|
|
21
|
+
return runAPITransform([]string{"--cwd"})
|
|
22
|
+
})
|
|
23
|
+
if code != 2 {
|
|
24
|
+
t.Fatalf("bad flag status mismatch: %d", code)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
code, _, errText := captureCommand(t, func() int {
|
|
28
|
+
getwd = failGetwd
|
|
29
|
+
return runAPITransform(nil)
|
|
30
|
+
})
|
|
31
|
+
if code != 2 || !strings.Contains(errText, "cwd boom") {
|
|
32
|
+
t.Fatalf("cwd error mismatch: code=%d stderr=%q", code, errText)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
code, _, errText = captureCommand(t, func() int {
|
|
36
|
+
return runAPITransform([]string{"--cwd", t.TempDir(), "--tsconfig", "missing.json"})
|
|
37
|
+
})
|
|
38
|
+
if code != 2 || !strings.Contains(errText, "tsconfig not found") {
|
|
39
|
+
t.Fatalf("missing config mismatch: code=%d stderr=%q", code, errText)
|
|
40
|
+
}
|
|
41
|
+
}
|