ttsc 0.30.0 → 0.30.1
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/ttsc/build.go +2 -3
- package/driver/emit_plugin.go +63 -24
- package/driver/emit_plugin_output.go +83 -0
- package/driver/program.go +19 -5
- package/package.json +8 -8
- package/utility/host.go +2 -3
package/cmd/ttsc/build.go
CHANGED
|
@@ -114,10 +114,9 @@ func runBuild(args []string) int {
|
|
|
114
114
|
fmt.Fprintf(stderr, "ttsc: emit failed: %v\n", err)
|
|
115
115
|
return 3
|
|
116
116
|
}
|
|
117
|
-
|
|
118
|
-
fmt.Fprintln(stderr, " -", d.String())
|
|
119
|
-
}
|
|
117
|
+
driver.WritePrettyDiagnostics(stderr, eDiags, cwd)
|
|
120
118
|
if driver.CountErrors(eDiags) > 0 {
|
|
119
|
+
fmt.Fprintln(stderr, "ttsc: emit failed; build output is incomplete")
|
|
121
120
|
return 2
|
|
122
121
|
}
|
|
123
122
|
if !*quiet {
|
package/driver/emit_plugin.go
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
package driver
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
|
+
"context"
|
|
4
5
|
"errors"
|
|
6
|
+
"fmt"
|
|
5
7
|
"strings"
|
|
6
8
|
"sync"
|
|
7
9
|
|
|
@@ -37,26 +39,35 @@ func (h *pluginEmitHost) GetEmitModuleFormatOfFile(file shimast.HasFileName) shi
|
|
|
37
39
|
return h.program.GetEmitModuleFormatOfFile(file)
|
|
38
40
|
}
|
|
39
41
|
func (h *pluginEmitHost) GetEmitResolver() shimprinter.EmitResolver {
|
|
40
|
-
return
|
|
42
|
+
return h.emitResolver
|
|
41
43
|
}
|
|
42
44
|
|
|
43
|
-
// guardedEmitResolver
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
45
|
+
// guardedEmitResolver only resolves member accesses from the program's input
|
|
46
|
+
// trees. ParseNode follows original links but trusts the synthesized flag:
|
|
47
|
+
// standalone factories leave it clear, even on generated nodes with copied
|
|
48
|
+
// source positions. Recovering a checker panic is too late to prevent that
|
|
49
|
+
// lookup from recording diagnostics on a parameter the binder never saw.
|
|
48
50
|
type guardedEmitResolver struct {
|
|
49
51
|
shimprinter.EmitResolver
|
|
52
|
+
originalMembers map[*shimast.Node]struct{}
|
|
50
53
|
}
|
|
51
54
|
|
|
52
|
-
func (g guardedEmitResolver) GetConstantValue(node *shimast.Node)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
}()
|
|
55
|
+
func (g guardedEmitResolver) GetConstantValue(node *shimast.Node) any {
|
|
56
|
+
if _, original := g.originalMembers[node]; !original {
|
|
57
|
+
return nil
|
|
58
|
+
}
|
|
58
59
|
return g.EmitResolver.GetConstantValue(node)
|
|
59
60
|
}
|
|
61
|
+
|
|
62
|
+
func collectOriginalMembers(node *shimast.Node, members map[*shimast.Node]struct{}) {
|
|
63
|
+
if node.Kind == shimast.KindPropertyAccessExpression || node.Kind == shimast.KindElementAccessExpression {
|
|
64
|
+
members[node] = struct{}{}
|
|
65
|
+
}
|
|
66
|
+
node.ForEachChild(func(child *shimast.Node) bool {
|
|
67
|
+
collectOriginalMembers(child, members)
|
|
68
|
+
return false
|
|
69
|
+
})
|
|
70
|
+
}
|
|
60
71
|
func (h *pluginEmitHost) GetProjectReferenceFromSource(path shimtspath.Path) *shimtsoptions.SourceOutputAndProjectReference {
|
|
61
72
|
return h.program.GetProjectReferenceFromSource(path)
|
|
62
73
|
}
|
|
@@ -180,8 +191,31 @@ func (p *Program) EmitWithPluginTransformers(transforms []PluginTransform, write
|
|
|
180
191
|
if len(linked) != 0 {
|
|
181
192
|
transforms = append(append([]PluginTransform{}, transforms...), linked...)
|
|
182
193
|
}
|
|
183
|
-
host := &pluginEmitHost{program: p.TSProgram, emitResolver: p.Checker.GetEmitResolver()}
|
|
184
194
|
options := p.TSProgram.Options()
|
|
195
|
+
if options.NoEmit.IsTrue() {
|
|
196
|
+
// Analysis-only incremental projects may still write build information.
|
|
197
|
+
// Delegate that policy to the ordinary emitter without running JS hooks.
|
|
198
|
+
result, diagnostics, err := p.EmitAllRaw(writeFile)
|
|
199
|
+
if err != nil {
|
|
200
|
+
return diagnostics, err
|
|
201
|
+
}
|
|
202
|
+
return p.pluginEmitDiagnostics("analysis-only emit", result.Diagnostics)
|
|
203
|
+
}
|
|
204
|
+
if result := shimcompiler.HandleNoEmitOnError(context.Background(), p.TSProgram, nil); result != nil {
|
|
205
|
+
return p.pluginEmitDiagnostics("pre-emit checking", result.Diagnostics)
|
|
206
|
+
}
|
|
207
|
+
// Snapshot ownership before any transformer runs, including transforms that
|
|
208
|
+
// mutate their input in place or reuse a member from another source file.
|
|
209
|
+
members := make(map[*shimast.Node]struct{})
|
|
210
|
+
for _, sf := range p.TSProgram.SourceFiles() {
|
|
211
|
+
collectOriginalMembers(sf.AsNode(), members)
|
|
212
|
+
}
|
|
213
|
+
host := &pluginEmitHost{program: p.TSProgram, emitResolver: guardedEmitResolver{p.Checker.GetEmitResolver(), members}}
|
|
214
|
+
|
|
215
|
+
// noEmitOnError applies to the whole build. The JS lane runs before the
|
|
216
|
+
// declaration lane, so defer callbacks until both have succeeded. Outside
|
|
217
|
+
// that option keep upstream's emit-despite-errors behavior.
|
|
218
|
+
output := newPluginEmitOutput(writeFile, options.NoEmitOnError.IsTrue())
|
|
185
219
|
for _, sf := range shimcompiler.GetSourceFilesToEmit(host, nil, false) {
|
|
186
220
|
paths := shimcompiler.GetOutputPathsFor(sf, options, host, false)
|
|
187
221
|
if paths.JsFilePath() != "" && !p.outputEscapesOutDir(paths.JsFilePath()) {
|
|
@@ -262,11 +296,11 @@ func (p *Program) EmitWithPluginTransformers(transforms []PluginTransform, write
|
|
|
262
296
|
// why the remaining fields stay zero.
|
|
263
297
|
if err := p.writePluginEmitOutput(paths.JsFilePath(), printed.JS, &shimcompiler.WriteFileData{
|
|
264
298
|
SourceMapUrlPos: printed.SourceMapUrlPos,
|
|
265
|
-
},
|
|
266
|
-
return nil, err
|
|
299
|
+
}, output.write); err != nil {
|
|
300
|
+
return nil, fmt.Errorf("driver: native plugin JavaScript emit failed: %w", err)
|
|
267
301
|
}
|
|
268
|
-
if err := p.writePluginEmitOutput(printed.MapPath, printed.MapText, nil,
|
|
269
|
-
return nil, err
|
|
302
|
+
if err := p.writePluginEmitOutput(printed.MapPath, printed.MapText, nil, output.write); err != nil {
|
|
303
|
+
return nil, fmt.Errorf("driver: native plugin source map emit failed: %w", err)
|
|
270
304
|
}
|
|
271
305
|
}
|
|
272
306
|
}
|
|
@@ -274,7 +308,10 @@ func (p *Program) EmitWithPluginTransformers(transforms []PluginTransform, write
|
|
|
274
308
|
// so it also runs for a JavaScript-only `incremental` / `composite` project
|
|
275
309
|
// that has no declarations to write at all.
|
|
276
310
|
if !options.GetEmitDeclarations() && !p.emitsBuildInfo() {
|
|
277
|
-
|
|
311
|
+
if result := shimcompiler.HandleNoEmitOnError(context.Background(), p.TSProgram, nil); result != nil {
|
|
312
|
+
return p.pluginEmitDiagnostics("JavaScript emit", result.Diagnostics)
|
|
313
|
+
}
|
|
314
|
+
return nil, output.flush()
|
|
278
315
|
}
|
|
279
316
|
|
|
280
317
|
// What the build information this pass writes does and does not claim.
|
|
@@ -304,16 +341,18 @@ func (p *Program) EmitWithPluginTransformers(transforms []PluginTransform, write
|
|
|
304
341
|
}
|
|
305
342
|
return nil
|
|
306
343
|
}
|
|
307
|
-
|
|
308
|
-
return writeFile(fileName, text, data)
|
|
309
|
-
}
|
|
310
|
-
return DefaultWriteFile(fileName, text)
|
|
344
|
+
return output.write(fileName, text, data)
|
|
311
345
|
},
|
|
312
346
|
})
|
|
347
|
+
var diagnostics []Diagnostic
|
|
313
348
|
if result != nil && len(result.Diagnostics) != 0 {
|
|
314
|
-
|
|
349
|
+
var err error
|
|
350
|
+
diagnostics, err = p.pluginEmitDiagnostics("declaration emit", result.Diagnostics)
|
|
351
|
+
if err != nil {
|
|
352
|
+
return diagnostics, err
|
|
353
|
+
}
|
|
315
354
|
}
|
|
316
|
-
return
|
|
355
|
+
return diagnostics, output.flush()
|
|
317
356
|
}
|
|
318
357
|
|
|
319
358
|
// writePluginEmitOutput writes one artifact of the hand-assembled emit, passing
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
package driver
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"strings"
|
|
6
|
+
|
|
7
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
8
|
+
shimcompiler "github.com/microsoft/typescript-go/shim/compiler"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
// PluginEmitError reports compiler errors from a native plugin emit. The same
|
|
12
|
+
// diagnostics remain in the returned slice for structured consumers. Hosts
|
|
13
|
+
// that only check the Go error still reject an incomplete build and display
|
|
14
|
+
// the compiler's code, severity and available source context.
|
|
15
|
+
type PluginEmitError struct {
|
|
16
|
+
Diagnostics []Diagnostic
|
|
17
|
+
Phase string
|
|
18
|
+
Declarations bool
|
|
19
|
+
cwd string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
func (e *PluginEmitError) Error() string {
|
|
23
|
+
var out strings.Builder
|
|
24
|
+
fmt.Fprintf(&out, "driver: native plugin %s failed; build output is incomplete", e.Phase)
|
|
25
|
+
if e.Declarations {
|
|
26
|
+
out.WriteString("; declaration output is incomplete or skipped")
|
|
27
|
+
}
|
|
28
|
+
out.WriteByte('\n')
|
|
29
|
+
WritePrettyDiagnostics(&out, e.Diagnostics, e.cwd)
|
|
30
|
+
return strings.TrimSpace(out.String())
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
func (p *Program) pluginEmitDiagnostics(phase string, raw []*shimast.Diagnostic) ([]Diagnostic, error) {
|
|
34
|
+
diagnostics := p.convertProgramDiagnostics(raw)
|
|
35
|
+
if CountErrors(diagnostics) == 0 {
|
|
36
|
+
return diagnostics, nil
|
|
37
|
+
}
|
|
38
|
+
return diagnostics, &PluginEmitError{
|
|
39
|
+
Diagnostics: diagnostics,
|
|
40
|
+
Phase: phase,
|
|
41
|
+
Declarations: p.TSProgram.Options().GetEmitDeclarations(),
|
|
42
|
+
cwd: p.TSProgram.GetCurrentDirectory(),
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
type pluginEmitOutput struct {
|
|
47
|
+
writeFile shimcompiler.WriteFile
|
|
48
|
+
buffered bool
|
|
49
|
+
pending []pluginEmitFile
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type pluginEmitFile struct {
|
|
53
|
+
name string
|
|
54
|
+
text string
|
|
55
|
+
data *shimcompiler.WriteFileData
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
func newPluginEmitOutput(writeFile shimcompiler.WriteFile, buffered bool) *pluginEmitOutput {
|
|
59
|
+
if writeFile == nil {
|
|
60
|
+
writeFile = func(name, text string, _ *shimcompiler.WriteFileData) error {
|
|
61
|
+
return DefaultWriteFile(name, text)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return &pluginEmitOutput{writeFile: writeFile, buffered: buffered}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// The caller serializes declaration writes; JavaScript and flush are serial.
|
|
68
|
+
func (o *pluginEmitOutput) write(name, text string, data *shimcompiler.WriteFileData) error {
|
|
69
|
+
if !o.buffered {
|
|
70
|
+
return o.writeFile(name, text, data)
|
|
71
|
+
}
|
|
72
|
+
o.pending = append(o.pending, pluginEmitFile{name, text, data})
|
|
73
|
+
return nil
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
func (o *pluginEmitOutput) flush() error {
|
|
77
|
+
for _, file := range o.pending {
|
|
78
|
+
if err := o.writeFile(file.name, file.text, file.data); err != nil {
|
|
79
|
+
return fmt.Errorf("driver: native plugin output write failed for %s; build output is incomplete: %w", file.name, err)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return nil
|
|
83
|
+
}
|
package/driver/program.go
CHANGED
|
@@ -142,7 +142,9 @@ func WritePrettyDiagnostics(w io.Writer, diagnostics []Diagnostic, cwd string) {
|
|
|
142
142
|
rich := make([]Diagnostic, 0, len(diagnostics))
|
|
143
143
|
plain := make([]Diagnostic, 0)
|
|
144
144
|
for _, d := range diagnostics {
|
|
145
|
-
if d.raw != nil
|
|
145
|
+
if d.raw != nil && d.raw.File() != nil && d.raw.Pos() < 0 {
|
|
146
|
+
plain = append(plain, d)
|
|
147
|
+
} else if d.raw != nil || d.lint != nil {
|
|
146
148
|
rich = append(rich, d)
|
|
147
149
|
} else {
|
|
148
150
|
plain = append(plain, d)
|
|
@@ -162,7 +164,18 @@ func WritePrettyDiagnostics(w io.Writer, diagnostics []Diagnostic, cwd string) {
|
|
|
162
164
|
shimdiagnosticwriter.FormatMixedDiagnostics(w, astDiags, lintDiags, cwd)
|
|
163
165
|
}
|
|
164
166
|
for _, d := range plain {
|
|
165
|
-
|
|
167
|
+
severity := "error"
|
|
168
|
+
if d.Severity == SeverityWarning {
|
|
169
|
+
severity = "warning"
|
|
170
|
+
}
|
|
171
|
+
code := ""
|
|
172
|
+
if d.Code != 0 {
|
|
173
|
+
code = fmt.Sprintf(" TS%d", d.Code)
|
|
174
|
+
}
|
|
175
|
+
fmt.Fprintf(w, " - %s%s: %s\n", severity, code, d.String())
|
|
176
|
+
if d.raw != nil && d.raw.File() != nil && d.raw.Pos() < 0 {
|
|
177
|
+
fmt.Fprintln(w, " Diagnostic refers to generated code; no authored source location is available.")
|
|
178
|
+
}
|
|
166
179
|
}
|
|
167
180
|
}
|
|
168
181
|
|
|
@@ -187,9 +200,10 @@ func CountErrors(diagnostics []Diagnostic) int {
|
|
|
187
200
|
}
|
|
188
201
|
continue
|
|
189
202
|
}
|
|
190
|
-
// Plain
|
|
191
|
-
|
|
192
|
-
|
|
203
|
+
// Plain diagnostics default to error but may explicitly declare warning.
|
|
204
|
+
if d.Severity != SeverityWarning {
|
|
205
|
+
n++
|
|
206
|
+
}
|
|
193
207
|
}
|
|
194
208
|
return n
|
|
195
209
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ttsc",
|
|
3
|
-
"version": "0.30.
|
|
3
|
+
"version": "0.30.1",
|
|
4
4
|
"description": "General-purpose TypeScript-Go compiler, runtime, plugin host, and LSP host.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -47,13 +47,13 @@
|
|
|
47
47
|
"typescript": "^7.0.2"
|
|
48
48
|
},
|
|
49
49
|
"optionalDependencies": {
|
|
50
|
-
"@ttsc/linux-x64": "0.30.
|
|
51
|
-
"@ttsc/linux-
|
|
52
|
-
"@ttsc/
|
|
53
|
-
"@ttsc/darwin-
|
|
54
|
-
"@ttsc/
|
|
55
|
-
"@ttsc/
|
|
56
|
-
"@ttsc/win32-
|
|
50
|
+
"@ttsc/linux-x64": "0.30.1",
|
|
51
|
+
"@ttsc/linux-arm": "0.30.1",
|
|
52
|
+
"@ttsc/darwin-arm64": "0.30.1",
|
|
53
|
+
"@ttsc/darwin-x64": "0.30.1",
|
|
54
|
+
"@ttsc/linux-arm64": "0.30.1",
|
|
55
|
+
"@ttsc/win32-arm64": "0.30.1",
|
|
56
|
+
"@ttsc/win32-x64": "0.30.1"
|
|
57
57
|
},
|
|
58
58
|
"sideEffects": [
|
|
59
59
|
"./lib/register.js",
|
package/utility/host.go
CHANGED
|
@@ -115,10 +115,9 @@ func RunBuildWithIO(args []string, stdout, stderr io.Writer) int {
|
|
|
115
115
|
fmt.Fprintf(opts.stderr, "ttsc utility: emit failed: %v\n", err)
|
|
116
116
|
return 3
|
|
117
117
|
}
|
|
118
|
-
|
|
119
|
-
fmt.Fprintln(opts.stderr, " -", d.String())
|
|
120
|
-
}
|
|
118
|
+
driver.WritePrettyDiagnostics(opts.stderr, eDiags, opts.cwd)
|
|
121
119
|
if driver.CountErrors(eDiags) > 0 {
|
|
120
|
+
fmt.Fprintln(opts.stderr, "ttsc utility: emit failed; build output is incomplete")
|
|
122
121
|
return 2
|
|
123
122
|
}
|
|
124
123
|
if res != nil && !opts.quiet {
|