ttsc 0.12.3 → 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 +22 -9
- 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/shim.go +24 -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 +22 -10
- 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/shim/checker/shim.go
CHANGED
|
@@ -59,34 +59,50 @@ const (
|
|
|
59
59
|
ElementFlagsVariadic = innerchecker.ElementFlagsVariadic
|
|
60
60
|
)
|
|
61
61
|
|
|
62
|
+
// IsTupleType reports whether t is a fixed-length tuple type.
|
|
62
63
|
func IsTupleType(t *innerchecker.Type) bool {
|
|
63
64
|
return innerchecker.IsTupleType(t)
|
|
64
65
|
}
|
|
65
66
|
|
|
67
|
+
// Checker_getIndexInfosOfType returns the index signatures (string/number/symbol
|
|
68
|
+
// index infos) declared on t.
|
|
66
69
|
func Checker_getIndexInfosOfType(recv *innerchecker.Checker, t *innerchecker.Type) []*innerchecker.IndexInfo {
|
|
67
70
|
return recv.GetIndexInfosOfType(t)
|
|
68
71
|
}
|
|
69
72
|
|
|
73
|
+
// Checker_getPropertiesOfType returns the named property symbols of t. For
|
|
74
|
+
// union and intersection types this is the set of properties visible on every
|
|
75
|
+
// member.
|
|
70
76
|
func Checker_getPropertiesOfType(recv *innerchecker.Checker, t *innerchecker.Type) []*innerast.Symbol {
|
|
71
77
|
return recv.GetPropertiesOfType(t)
|
|
72
78
|
}
|
|
73
79
|
|
|
80
|
+
// Checker_getApparentProperties returns the properties visible on t after
|
|
81
|
+
// resolving primitive wrapper types (e.g. string → String).
|
|
74
82
|
func Checker_getApparentProperties(recv *innerchecker.Checker, t *innerchecker.Type) []*innerast.Symbol {
|
|
75
83
|
return recv.GetApparentProperties(t)
|
|
76
84
|
}
|
|
77
85
|
|
|
86
|
+
// Checker_getTypeArguments returns the type arguments of a generic reference
|
|
87
|
+
// type, or nil when t is not a reference.
|
|
78
88
|
func Checker_getTypeArguments(recv *innerchecker.Checker, t *innerchecker.Type) []*innerchecker.Type {
|
|
79
89
|
return recv.GetTypeArguments(t)
|
|
80
90
|
}
|
|
81
91
|
|
|
92
|
+
// Checker_getTypeOfSymbol returns the declared type of symbol, resolving
|
|
93
|
+
// aliases and following late-bound types.
|
|
82
94
|
func Checker_getTypeOfSymbol(recv *innerchecker.Checker, symbol *innerast.Symbol) *innerchecker.Type {
|
|
83
95
|
return recv.GetTypeOfSymbol(symbol)
|
|
84
96
|
}
|
|
85
97
|
|
|
98
|
+
// Checker_getTypeOfSymbolAtLocation returns the contextual type of symbol as
|
|
99
|
+
// observed at the given AST node (useful for narrowed types in control flow).
|
|
86
100
|
func Checker_getTypeOfSymbolAtLocation(recv *innerchecker.Checker, symbol *innerast.Symbol, node *innerast.Node) *innerchecker.Type {
|
|
87
101
|
return recv.GetTypeOfSymbolAtLocation(symbol, node)
|
|
88
102
|
}
|
|
89
103
|
|
|
104
|
+
// Checker_getTypeOfPropertyOfType looks up the type of the named property on t
|
|
105
|
+
// and returns nil when no such property exists.
|
|
90
106
|
func Checker_getTypeOfPropertyOfType(recv *innerchecker.Checker, t *innerchecker.Type, name string) *innerchecker.Type {
|
|
91
107
|
return recv.GetTypeOfPropertyOfType(t, name)
|
|
92
108
|
}
|
|
@@ -94,6 +110,8 @@ func Checker_getTypeOfPropertyOfType(recv *innerchecker.Checker, t *innerchecker
|
|
|
94
110
|
//go:linkname checkerGetAliasSymbolForTypeNode github.com/microsoft/typescript-go/internal/checker.(*Checker).getAliasSymbolForTypeNode
|
|
95
111
|
func checkerGetAliasSymbolForTypeNode(recv *innerchecker.Checker, node *innerast.Node) *innerast.Symbol
|
|
96
112
|
|
|
113
|
+
// Checker_getAliasSymbolForTypeNode returns the alias symbol that a type node
|
|
114
|
+
// refers to when the node is itself a type alias reference (e.g. `type Foo = ...`).
|
|
97
115
|
func Checker_getAliasSymbolForTypeNode(recv *innerchecker.Checker, node *innerast.Node) *innerast.Symbol {
|
|
98
116
|
return checkerGetAliasSymbolForTypeNode(recv, node)
|
|
99
117
|
}
|
|
@@ -101,6 +119,8 @@ func Checker_getAliasSymbolForTypeNode(recv *innerchecker.Checker, node *inneras
|
|
|
101
119
|
//go:linkname checkerGetDeclarationOfAliasSymbol github.com/microsoft/typescript-go/internal/checker.(*Checker).getDeclarationOfAliasSymbol
|
|
102
120
|
func checkerGetDeclarationOfAliasSymbol(recv *innerchecker.Checker, symbol *innerast.Symbol) *innerast.Node
|
|
103
121
|
|
|
122
|
+
// Checker_getDeclarationOfAliasSymbol resolves an import/export alias symbol to
|
|
123
|
+
// its original declaration node.
|
|
104
124
|
func Checker_getDeclarationOfAliasSymbol(recv *innerchecker.Checker, symbol *innerast.Symbol) *innerast.Node {
|
|
105
125
|
return checkerGetDeclarationOfAliasSymbol(recv, symbol)
|
|
106
126
|
}
|
|
@@ -108,6 +128,8 @@ func Checker_getDeclarationOfAliasSymbol(recv *innerchecker.Checker, symbol *inn
|
|
|
108
128
|
//go:linkname checkerGetTargetOfImportSpecifier github.com/microsoft/typescript-go/internal/checker.(*Checker).getTargetOfImportSpecifier
|
|
109
129
|
func checkerGetTargetOfImportSpecifier(recv *innerchecker.Checker, node *innerast.Node) *innerast.Symbol
|
|
110
130
|
|
|
131
|
+
// Checker_getTargetOfImportSpecifier resolves an import specifier node to the
|
|
132
|
+
// exported symbol it binds. Returns nil if recv or node is nil.
|
|
111
133
|
func Checker_getTargetOfImportSpecifier(recv *innerchecker.Checker, node *innerast.Node) *innerast.Symbol {
|
|
112
134
|
if recv == nil || node == nil {
|
|
113
135
|
return nil
|
|
@@ -115,6 +137,8 @@ func Checker_getTargetOfImportSpecifier(recv *innerchecker.Checker, node *innera
|
|
|
115
137
|
return checkerGetTargetOfImportSpecifier(recv, node)
|
|
116
138
|
}
|
|
117
139
|
|
|
140
|
+
// Checker_getAliasedSymbol follows an alias chain to its final target symbol.
|
|
141
|
+
// Returns nil if recv or symbol is nil.
|
|
118
142
|
func Checker_getAliasedSymbol(recv *innerchecker.Checker, symbol *innerast.Symbol) *innerast.Symbol {
|
|
119
143
|
if recv == nil || symbol == nil {
|
|
120
144
|
return nil
|
|
@@ -132,6 +156,11 @@ func checkerResolveEntityName(
|
|
|
132
156
|
location *innerast.Node,
|
|
133
157
|
) *innerast.Symbol
|
|
134
158
|
|
|
159
|
+
// Checker_resolveEntityName resolves a dotted entity name (identifier or
|
|
160
|
+
// qualified name) to the symbol it denotes, filtered by meaning flags.
|
|
161
|
+
// When ignoreErrors is true, resolution failures are silent. When
|
|
162
|
+
// dontResolveAlias is true, the returned symbol may still be an alias.
|
|
163
|
+
// Returns nil if recv or name is nil.
|
|
135
164
|
func Checker_resolveEntityName(
|
|
136
165
|
recv *innerchecker.Checker,
|
|
137
166
|
name *innerast.Node,
|
|
@@ -149,6 +178,9 @@ func Checker_resolveEntityName(
|
|
|
149
178
|
//go:linkname checkerGetTypeNameSymbol github.com/microsoft/typescript-go/internal/checker.getTypeNameSymbol
|
|
150
179
|
func checkerGetTypeNameSymbol(t *innerchecker.Type) *innerast.Symbol
|
|
151
180
|
|
|
181
|
+
// Type_getTypeNameSymbol returns the symbol attached to t's type name field,
|
|
182
|
+
// or nil when t has no name symbol or t is nil. Linked via go:linkname because
|
|
183
|
+
// getTypeNameSymbol is a package-level unexported function in the checker.
|
|
152
184
|
func Type_getTypeNameSymbol(t *innerchecker.Type) *innerast.Symbol {
|
|
153
185
|
if t == nil {
|
|
154
186
|
return nil
|
|
@@ -159,6 +191,7 @@ func Type_getTypeNameSymbol(t *innerchecker.Type) *innerast.Symbol {
|
|
|
159
191
|
//go:linkname checkerIsArrayType github.com/microsoft/typescript-go/internal/checker.(*Checker).isArrayType
|
|
160
192
|
func checkerIsArrayType(recv *innerchecker.Checker, t *innerchecker.Type) bool
|
|
161
193
|
|
|
194
|
+
// Checker_isArrayType reports whether t is the built-in Array<T> reference type.
|
|
162
195
|
func Checker_isArrayType(recv *innerchecker.Checker, t *innerchecker.Type) bool {
|
|
163
196
|
return checkerIsArrayType(recv, t)
|
|
164
197
|
}
|
|
@@ -166,6 +199,8 @@ func Checker_isArrayType(recv *innerchecker.Checker, t *innerchecker.Type) bool
|
|
|
166
199
|
//go:linkname checkerGetBaseTypes github.com/microsoft/typescript-go/internal/checker.(*Checker).getBaseTypes
|
|
167
200
|
func checkerGetBaseTypes(recv *innerchecker.Checker, t *innerchecker.Type) []*innerchecker.Type
|
|
168
201
|
|
|
202
|
+
// Checker_getBaseTypes returns the list of base types (from `extends` clauses)
|
|
203
|
+
// for a class or interface type. Returns nil if recv or t is nil.
|
|
169
204
|
func Checker_getBaseTypes(recv *innerchecker.Checker, t *innerchecker.Type) []*innerchecker.Type {
|
|
170
205
|
if recv == nil || t == nil {
|
|
171
206
|
return nil
|
package/shim/core/shim.go
CHANGED
|
@@ -1,17 +1,34 @@
|
|
|
1
|
+
// Package core re-exports the subset of typescript-go's internal/core types
|
|
2
|
+
// and constants that plugins and the ttsc driver need. It provides compiler
|
|
3
|
+
// options, script-kind discrimination, tri-state booleans, and text-range
|
|
4
|
+
// primitives without exposing the full internal surface.
|
|
1
5
|
package core
|
|
2
6
|
|
|
3
7
|
import innercore "github.com/microsoft/typescript-go/internal/core"
|
|
4
8
|
|
|
9
|
+
// CompilerOptions holds the parsed tsconfig compiler options passed to the
|
|
10
|
+
// TypeScript-Go program host.
|
|
5
11
|
type CompilerOptions = innercore.CompilerOptions
|
|
12
|
+
|
|
13
|
+
// Tristate is a three-valued boolean: TSFalse, TSTrue, or TSUnknown. Used by
|
|
14
|
+
// CompilerOptions fields that can be explicitly unset.
|
|
6
15
|
type Tristate = innercore.Tristate
|
|
16
|
+
|
|
17
|
+
// TextPos is a zero-based byte offset into a source file's text.
|
|
7
18
|
type TextPos = innercore.TextPos
|
|
19
|
+
|
|
20
|
+
// TextRange is a half-open [Pos, End) byte range inside a source file.
|
|
8
21
|
type TextRange = innercore.TextRange
|
|
22
|
+
|
|
23
|
+
// ScriptKind identifies the syntactic flavour of a source file.
|
|
9
24
|
type ScriptKind = innercore.ScriptKind
|
|
10
25
|
|
|
11
26
|
const (
|
|
27
|
+
// TSFalse and TSTrue are the explicit-false and explicit-true Tristate values.
|
|
12
28
|
TSFalse = innercore.TSFalse
|
|
13
29
|
TSTrue = innercore.TSTrue
|
|
14
30
|
|
|
31
|
+
// ScriptKind* constants enumerate the file flavours typescript-go recognises.
|
|
15
32
|
ScriptKindUnknown = innercore.ScriptKindUnknown
|
|
16
33
|
ScriptKindJS = innercore.ScriptKindJS
|
|
17
34
|
ScriptKindJSX = innercore.ScriptKindJSX
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// Package diagnosticwriter re-exports the subset of typescript-go's
|
|
2
|
+
// internal/diagnosticwriter surface that the ttsc driver uses. It provides
|
|
3
|
+
// FormatASTDiagnosticsWithColorAndContext for rendering pure tsgo diagnostics
|
|
4
|
+
// and delegates the mixed lint+tsgo rendering path to the adjacent lint.go.
|
|
1
5
|
package diagnosticwriter
|
|
2
6
|
|
|
3
7
|
import (
|
package/shim/lsp/shim.go
CHANGED
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
package lsp
|
|
9
9
|
|
|
10
10
|
import (
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
"io"
|
|
12
|
+
_ "unsafe"
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
innerlsp "github.com/microsoft/typescript-go/internal/lsp"
|
|
15
15
|
)
|
|
16
16
|
|
|
17
17
|
// Server is the opaque LSP server type from tsgo.
|
package/shim/printer/shim.go
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// Package printer re-exports the typescript-go internal/printer types and
|
|
2
|
+
// wraps the three functions that the ttsc driver and transform plugins need
|
|
3
|
+
// to emit source text from an AST. The surface is intentionally narrow: only
|
|
4
|
+
// the construction and single-file emit path are exposed.
|
|
1
5
|
package printer
|
|
2
6
|
|
|
3
7
|
import (
|
|
@@ -5,19 +9,35 @@ import (
|
|
|
5
9
|
innerprinter "github.com/microsoft/typescript-go/internal/printer"
|
|
6
10
|
)
|
|
7
11
|
|
|
12
|
+
// PrintHandlers provides optional hooks (e.g. substituteNode) called during
|
|
13
|
+
// AST emission.
|
|
8
14
|
type PrintHandlers = innerprinter.PrintHandlers
|
|
15
|
+
|
|
16
|
+
// Printer holds the stateful emitter produced by NewPrinter.
|
|
9
17
|
type Printer = innerprinter.Printer
|
|
18
|
+
|
|
19
|
+
// PrinterOptions configures newline style, source-map generation, and other
|
|
20
|
+
// emission knobs.
|
|
10
21
|
type PrinterOptions = innerprinter.PrinterOptions
|
|
22
|
+
|
|
23
|
+
// EmitContext accumulates per-emit metadata (source maps, comment positions)
|
|
24
|
+
// and must be created fresh for each emit round via NewEmitContext.
|
|
11
25
|
type EmitContext = innerprinter.EmitContext
|
|
12
26
|
|
|
27
|
+
// NewPrinter creates an emitter with the supplied options, substitution hooks,
|
|
28
|
+
// and emit context. Callers must pass the same EmitContext to all operations
|
|
29
|
+
// in a single emit round.
|
|
13
30
|
func NewPrinter(options PrinterOptions, handlers PrintHandlers, emitContext *EmitContext) *Printer {
|
|
14
31
|
return innerprinter.NewPrinter(options, handlers, emitContext)
|
|
15
32
|
}
|
|
16
33
|
|
|
34
|
+
// NewEmitContext allocates a fresh EmitContext for a new emit round.
|
|
17
35
|
func NewEmitContext() *EmitContext {
|
|
18
36
|
return innerprinter.NewEmitContext()
|
|
19
37
|
}
|
|
20
38
|
|
|
39
|
+
// EmitSourceFile renders the full source file through the printer and returns
|
|
40
|
+
// the emitted text.
|
|
21
41
|
func EmitSourceFile(p *Printer, sourceFile *ast.SourceFile) string {
|
|
22
42
|
return p.EmitSourceFile(sourceFile)
|
|
23
43
|
}
|
package/src/TtscCompiler.ts
CHANGED
|
@@ -36,6 +36,13 @@ import type { TtscBuildResult } from "./structures/internal/TtscBuildResult";
|
|
|
36
36
|
export class TtscCompiler {
|
|
37
37
|
private readonly context: ITtscCompilerContext;
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Create a new compiler instance bound to the given project context.
|
|
41
|
+
*
|
|
42
|
+
* The context is defensively copied: mutations to the original object after
|
|
43
|
+
* construction do not affect this instance. Omit `context` (or pass `{}`) to
|
|
44
|
+
* inherit all defaults from the running process.
|
|
45
|
+
*/
|
|
39
46
|
public constructor(context: ITtscCompilerContext = {}) {
|
|
40
47
|
this.context = {
|
|
41
48
|
...context,
|
|
@@ -3,7 +3,17 @@ import path from "node:path";
|
|
|
3
3
|
|
|
4
4
|
import { buildSourcePlugin } from "../../plugin/internal/buildSourcePlugin";
|
|
5
5
|
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Build (or retrieve from cache) the native ttsc compiler host binary used by
|
|
8
|
+
* the in-memory API compilation paths (`compileProjectInMemory`,
|
|
9
|
+
* `transformProjectInMemory`).
|
|
10
|
+
*
|
|
11
|
+
* The host is the `cmd/ttsc` Go entrypoint compiled with `buildSourcePlugin`.
|
|
12
|
+
* The cache key incorporates the ttsc package version and the full `go.mod`
|
|
13
|
+
* contents so a toolchain upgrade automatically produces a fresh binary.
|
|
14
|
+
*
|
|
15
|
+
* @returns Absolute path to the compiled host executable.
|
|
16
|
+
*/
|
|
7
17
|
export function buildNativeCompiler(options: {
|
|
8
18
|
cacheBaseDir: string;
|
|
9
19
|
cacheDir?: string;
|
|
@@ -22,6 +32,10 @@ export function buildNativeCompiler(options: {
|
|
|
22
32
|
});
|
|
23
33
|
}
|
|
24
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Read the `version` field from `package.json` inside `packageRoot`, falling
|
|
37
|
+
* back to `"0.0.0"` when the file is absent or malformed.
|
|
38
|
+
*/
|
|
25
39
|
function readOwnPackageVersion(packageRoot: string): string {
|
|
26
40
|
try {
|
|
27
41
|
const pkg = JSON.parse(
|
|
@@ -33,10 +47,16 @@ function readOwnPackageVersion(packageRoot: string): string {
|
|
|
33
47
|
}
|
|
34
48
|
}
|
|
35
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Read the full contents of `go.mod` inside `packageRoot` and use it as a
|
|
52
|
+
* version token for the binary cache key. Returns `"unknown"` on read error.
|
|
53
|
+
*
|
|
54
|
+
* Using the entire `go.mod` ensures that any dependency bump (including
|
|
55
|
+
* indirect ones) invalidates the cached binary.
|
|
56
|
+
*/
|
|
36
57
|
function readGoModuleVersion(packageRoot: string): string {
|
|
37
58
|
try {
|
|
38
|
-
|
|
39
|
-
return goMod;
|
|
59
|
+
return fs.readFileSync(path.join(packageRoot, "go.mod"), "utf8");
|
|
40
60
|
} catch {
|
|
41
61
|
return "unknown";
|
|
42
62
|
}
|
|
@@ -9,12 +9,22 @@ import type { ITtscCompilerDiagnostic } from "../../structures/ITtscCompilerDiag
|
|
|
9
9
|
import type { ITtscParsedProjectConfig } from "../../structures/internal/ITtscParsedProjectConfig";
|
|
10
10
|
import type { TtscBuildResult } from "../../structures/internal/TtscBuildResult";
|
|
11
11
|
import { buildNativeCompiler } from "./buildNativeCompiler";
|
|
12
|
+
import { isOutsideRelativePath, packageRootDir } from "./paths";
|
|
12
13
|
import { readProjectConfig } from "./project/readProjectConfig";
|
|
13
14
|
import { runBuild } from "./runBuild";
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Compile a project and capture emitted files without writing to the project
|
|
17
18
|
* tree.
|
|
19
|
+
*
|
|
20
|
+
* When no plugins are configured the fast path spawns the native ttsc compiler
|
|
21
|
+
* host (`cmd/ttsc api-compile`) which returns a structured JSON response
|
|
22
|
+
* containing diagnostics and an output file map. When plugins are present the
|
|
23
|
+
* slow path goes through `runBuild` into a temp directory and reads the files
|
|
24
|
+
* back from disk.
|
|
25
|
+
*
|
|
26
|
+
* @returns A map of output path → file content plus a `TtscBuildResult` with
|
|
27
|
+
* diagnostics and the exit status.
|
|
18
28
|
*/
|
|
19
29
|
export function compileProjectInMemory(options: ITtscCompilerContext): {
|
|
20
30
|
output: Record<string, string>;
|
|
@@ -64,6 +74,7 @@ export function compileProjectInMemory(options: ITtscCompilerContext): {
|
|
|
64
74
|
};
|
|
65
75
|
}
|
|
66
76
|
|
|
77
|
+
/** Return true when the project or the call-level options declare any plugins. */
|
|
67
78
|
function hasConfiguredPlugins(
|
|
68
79
|
options: ITtscCompilerContext,
|
|
69
80
|
project: ITtscParsedProjectConfig,
|
|
@@ -71,6 +82,10 @@ function hasConfiguredPlugins(
|
|
|
71
82
|
return hasProjectPluginEntries(project, options.plugins);
|
|
72
83
|
}
|
|
73
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Plugin-backed compilation: emit into a temp directory via `runBuild`, then
|
|
87
|
+
* read back every file the build wrote so they can be returned as strings.
|
|
88
|
+
*/
|
|
74
89
|
function compileProjectWithPlugins(
|
|
75
90
|
options: ITtscCompilerContext,
|
|
76
91
|
cwd: string,
|
|
@@ -101,6 +116,15 @@ function compileProjectWithPlugins(
|
|
|
101
116
|
}
|
|
102
117
|
}
|
|
103
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Build a function that maps a path relative to the temp output directory to
|
|
121
|
+
* the key used in the returned `output` map.
|
|
122
|
+
*
|
|
123
|
+
* When `outDir` is inside the project root the key is relative to the project
|
|
124
|
+
* root (preserving the `outDir` prefix). When `outDir` is outside the project
|
|
125
|
+
* root the key is absolute-style (`/absolute/outDir/relative`). When `outDir`
|
|
126
|
+
* is absent the key is the bare relative path.
|
|
127
|
+
*/
|
|
104
128
|
function outputKeyMapper(
|
|
105
129
|
project: ITtscParsedProjectConfig,
|
|
106
130
|
): (relativePath: string) => string {
|
|
@@ -116,14 +140,7 @@ function outputKeyMapper(
|
|
|
116
140
|
return (relativePath) => pathToKey(path.join(outDir, relativePath));
|
|
117
141
|
}
|
|
118
142
|
|
|
119
|
-
|
|
120
|
-
return (
|
|
121
|
-
relative === ".." ||
|
|
122
|
-
relative.startsWith(`..${path.sep}`) ||
|
|
123
|
-
path.isAbsolute(relative)
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
|
|
143
|
+
/** Read every file in `directory` recursively and return a `path→content` map. */
|
|
127
144
|
function readOutputDirectory(
|
|
128
145
|
directory: string,
|
|
129
146
|
keyOf: (relativePath: string) => string,
|
|
@@ -141,6 +158,7 @@ function readOutputDirectory(
|
|
|
141
158
|
return output;
|
|
142
159
|
}
|
|
143
160
|
|
|
161
|
+
/** Recursively list all files under `directory`, sorted for stable output. */
|
|
144
162
|
function listFiles(directory: string): string[] {
|
|
145
163
|
const out: string[] = [];
|
|
146
164
|
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
|
|
@@ -154,10 +172,18 @@ function listFiles(directory: string): string[] {
|
|
|
154
172
|
return out.sort();
|
|
155
173
|
}
|
|
156
174
|
|
|
175
|
+
/** Normalise a file path to a forward-slash key suitable for the output map. */
|
|
157
176
|
function pathToKey(file: string): string {
|
|
158
177
|
return file.replace(/\\/g, "/");
|
|
159
178
|
}
|
|
160
179
|
|
|
180
|
+
/**
|
|
181
|
+
* Parse the JSON envelope written by the native compiler host to stdout.
|
|
182
|
+
*
|
|
183
|
+
* On success returns `{ diagnostics, output }`. On JSON parse failure throws a
|
|
184
|
+
* descriptive error using stderr (preferred) or stdout as context, so callers
|
|
185
|
+
* see the original compiler error rather than a generic JSON parse message.
|
|
186
|
+
*/
|
|
161
187
|
function parseNativeCompileOutput(
|
|
162
188
|
stdout: string,
|
|
163
189
|
stderr: string,
|
|
@@ -181,20 +207,3 @@ function parseNativeCompileOutput(
|
|
|
181
207
|
);
|
|
182
208
|
}
|
|
183
209
|
}
|
|
184
|
-
|
|
185
|
-
function packageRootDir(): string {
|
|
186
|
-
let current = path.resolve(__dirname);
|
|
187
|
-
while (true) {
|
|
188
|
-
if (
|
|
189
|
-
fs.existsSync(path.join(current, "package.json")) &&
|
|
190
|
-
fs.existsSync(path.join(current, "go.mod"))
|
|
191
|
-
) {
|
|
192
|
-
return fs.realpathSync.native?.(current) ?? fs.realpathSync(current);
|
|
193
|
-
}
|
|
194
|
-
const parent = path.dirname(current);
|
|
195
|
-
if (parent === current) {
|
|
196
|
-
throw new Error("ttsc: package root not found for native compiler build");
|
|
197
|
-
}
|
|
198
|
-
current = parent;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Walk up the directory tree from `__dirname` until a directory that contains
|
|
6
|
+
* both `package.json` and `go.mod` is found. This is the `packages/ttsc` root
|
|
7
|
+
* and must be passed to `buildNativeCompiler` so it can locate `cmd/ttsc`.
|
|
8
|
+
*
|
|
9
|
+
* Uses `fs.realpathSync.native` when available to resolve symlinks identically
|
|
10
|
+
* to the Go toolchain's own path resolution.
|
|
11
|
+
*
|
|
12
|
+
* Throws when the root cannot be found (i.e. the package is not in a Go
|
|
13
|
+
* workspace), which would indicate a broken installation.
|
|
14
|
+
*/
|
|
15
|
+
export function packageRootDir(): string {
|
|
16
|
+
let current = path.resolve(__dirname);
|
|
17
|
+
while (true) {
|
|
18
|
+
if (
|
|
19
|
+
fs.existsSync(path.join(current, "package.json")) &&
|
|
20
|
+
fs.existsSync(path.join(current, "go.mod"))
|
|
21
|
+
) {
|
|
22
|
+
return fs.realpathSync.native?.(current) ?? fs.realpathSync(current);
|
|
23
|
+
}
|
|
24
|
+
const parent = path.dirname(current);
|
|
25
|
+
if (parent === current) {
|
|
26
|
+
throw new Error("ttsc: package root not found for native compiler build");
|
|
27
|
+
}
|
|
28
|
+
current = parent;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Walk up the directory tree from `from` looking for a `go.mod` file. Stops
|
|
34
|
+
* after `maxDepth` hops so callers can bound the search to a known
|
|
35
|
+
* neighbourhood of the plugin source directory.
|
|
36
|
+
*
|
|
37
|
+
* Returns the absolute path to the first `go.mod` found, or `null` when no
|
|
38
|
+
* `go.mod` exists within the depth limit or filesystem root is reached first.
|
|
39
|
+
*/
|
|
40
|
+
export function findNearestGoMod(
|
|
41
|
+
from: string,
|
|
42
|
+
maxDepth: number,
|
|
43
|
+
): string | null {
|
|
44
|
+
let current = path.resolve(from);
|
|
45
|
+
let depth = 0;
|
|
46
|
+
while (true) {
|
|
47
|
+
const candidate = path.join(current, "go.mod");
|
|
48
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
49
|
+
if (depth >= maxDepth) return null;
|
|
50
|
+
const parent = path.dirname(current);
|
|
51
|
+
if (parent === current) return null;
|
|
52
|
+
current = parent;
|
|
53
|
+
depth += 1;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Return `true` when a relative path escapes its base directory — i.e. starts
|
|
59
|
+
* with `..` or is an absolute path. Used by callers that need to guard against
|
|
60
|
+
* path traversal before building output keys or spawning subprocesses.
|
|
61
|
+
*/
|
|
62
|
+
export function isOutsideRelativePath(relative: string): boolean {
|
|
63
|
+
return (
|
|
64
|
+
relative === ".." ||
|
|
65
|
+
relative.startsWith(`..${path.sep}`) ||
|
|
66
|
+
path.isAbsolute(relative)
|
|
67
|
+
);
|
|
68
|
+
}
|
|
@@ -7,18 +7,36 @@ import type { ITtscParsedProjectConfig } from "../../../structures/internal/ITts
|
|
|
7
7
|
import type { ITtscProjectLocatorOptions } from "../../../structures/internal/ITtscProjectLocatorOptions";
|
|
8
8
|
import { resolveProjectConfig } from "./resolveProjectConfig";
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Compiler option keys whose values are file-system paths that must be resolved
|
|
12
|
+
* relative to the tsconfig that declares them, not the project root.
|
|
13
|
+
*/
|
|
10
14
|
const PATH_OPTIONS = new Set(["baseUrl", "declarationDir", "rootDir"]);
|
|
11
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Intermediate type used during `extends`-chain resolution before the result is
|
|
18
|
+
* projected into `ITtscParsedProjectConfig`.
|
|
19
|
+
*/
|
|
12
20
|
type ResolvedCompilerOptions = {
|
|
13
21
|
options: Record<string, unknown>;
|
|
22
|
+
/** Directory of the tsconfig that last declared each option key. */
|
|
14
23
|
optionBaseDirs: Record<string, string>;
|
|
15
24
|
outDir?: string;
|
|
16
25
|
pluginBaseDirs: string[];
|
|
26
|
+
/** True when any tsconfig in the chain explicitly declared `plugins`. */
|
|
17
27
|
pluginsDeclared: boolean;
|
|
18
28
|
plugins: ITtscProjectPluginConfig[];
|
|
19
29
|
};
|
|
20
30
|
|
|
21
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* Read and resolve the project config subset used by ttsc.
|
|
33
|
+
*
|
|
34
|
+
* Follows `extends` chains (including arrays) and merges compiler options with
|
|
35
|
+
* later configs taking precedence. Path-typed options (`baseUrl`,
|
|
36
|
+
* `declarationDir`, `rootDir`) are resolved relative to the config that
|
|
37
|
+
* declares them. The `outDir` is resolved to an absolute path. Plugins are
|
|
38
|
+
* inherited from the nearest ancestor that declares them.
|
|
39
|
+
*/
|
|
22
40
|
export function readProjectConfig(
|
|
23
41
|
opts: ITtscProjectLocatorOptions = {},
|
|
24
42
|
): ITtscParsedProjectConfig {
|
|
@@ -39,12 +57,20 @@ export function readProjectConfig(
|
|
|
39
57
|
};
|
|
40
58
|
}
|
|
41
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Type guard: accept any non-null object as a plugin config entry. This is
|
|
62
|
+
* intentionally loose because the shape is validated later by plugin loaders.
|
|
63
|
+
*/
|
|
42
64
|
function isProjectPluginConfig(
|
|
43
65
|
value: unknown,
|
|
44
66
|
): value is ITtscProjectPluginConfig {
|
|
45
67
|
return typeof value === "object" && value !== null;
|
|
46
68
|
}
|
|
47
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Resolve symlinks on `location`, returning the original path when
|
|
72
|
+
* `realpathSync` fails (e.g. when the file does not yet exist).
|
|
73
|
+
*/
|
|
48
74
|
function resolveRealPath(location: string): string {
|
|
49
75
|
try {
|
|
50
76
|
return fs.realpathSync(location);
|
|
@@ -53,10 +79,18 @@ function resolveRealPath(location: string): string {
|
|
|
53
79
|
}
|
|
54
80
|
}
|
|
55
81
|
|
|
82
|
+
/** Resolve `target` against `cwd` when it is not already absolute. */
|
|
56
83
|
function resolveAbsolutePath(cwd: string, target: string): string {
|
|
57
84
|
return path.isAbsolute(target) ? target : path.resolve(cwd, target);
|
|
58
85
|
}
|
|
59
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Recursively read and merge `compilerOptions` from `tsconfig` and all configs
|
|
89
|
+
* in its `extends` chain. `seen` tracks canonical paths to detect circular
|
|
90
|
+
* `extends` references; the current config is removed from `seen` in the
|
|
91
|
+
* `finally` block so sibling-referenced configs can be visited again via a
|
|
92
|
+
* different parent.
|
|
93
|
+
*/
|
|
60
94
|
function readResolvedCompilerOptions(
|
|
61
95
|
tsconfig: string,
|
|
62
96
|
seen: Set<string> = new Set(),
|
|
@@ -117,6 +151,16 @@ function readResolvedCompilerOptions(
|
|
|
117
151
|
}
|
|
118
152
|
}
|
|
119
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Resolve the base compiler options from the `extends` field of a tsconfig.
|
|
156
|
+
*
|
|
157
|
+
* - String: a single base config; options are returned directly.
|
|
158
|
+
* - Array: multiple base configs merged left-to-right (later entries win).
|
|
159
|
+
* - Absent / non-string non-array: returns empty options.
|
|
160
|
+
*
|
|
161
|
+
* Plugin inheritance: when the current config in an array chain explicitly
|
|
162
|
+
* declares `plugins`, subsequent configs in the array do not override them.
|
|
163
|
+
*/
|
|
120
164
|
function resolveBaseCompilerOptions(
|
|
121
165
|
tsconfig: string,
|
|
122
166
|
extended: unknown,
|
|
@@ -172,6 +216,10 @@ function resolveBaseCompilerOptions(
|
|
|
172
216
|
return merged;
|
|
173
217
|
}
|
|
174
218
|
|
|
219
|
+
/**
|
|
220
|
+
* Resolve path-typed compiler options to absolute paths using the directory of
|
|
221
|
+
* the tsconfig that declared each option (`baseDirs`).
|
|
222
|
+
*/
|
|
175
223
|
function resolvePathOptions(
|
|
176
224
|
options: Record<string, unknown>,
|
|
177
225
|
baseDirs: Record<string, string>,
|
|
@@ -187,6 +235,16 @@ function resolvePathOptions(
|
|
|
187
235
|
return resolved;
|
|
188
236
|
}
|
|
189
237
|
|
|
238
|
+
/**
|
|
239
|
+
* Resolve an `extends` specifier to an absolute path using the same rules as
|
|
240
|
+
* TypeScript's config resolution:
|
|
241
|
+
*
|
|
242
|
+
* - Absolute path: used directly.
|
|
243
|
+
* - Relative specifier (`./`, `../`, `.`, `..`): resolved against the declaring
|
|
244
|
+
* tsconfig's directory with fallback extension candidates.
|
|
245
|
+
* - Bare package specifier: resolved through Node's module resolver (the resolver
|
|
246
|
+
* also tries appending `.json` when the first attempt fails).
|
|
247
|
+
*/
|
|
190
248
|
function resolveExtendsConfig(tsconfig: string, specifier: string): string {
|
|
191
249
|
const baseDir = path.dirname(tsconfig);
|
|
192
250
|
if (path.isAbsolute(specifier)) {
|
|
@@ -203,6 +261,10 @@ function resolveExtendsConfig(tsconfig: string, specifier: string): string {
|
|
|
203
261
|
}
|
|
204
262
|
}
|
|
205
263
|
|
|
264
|
+
/**
|
|
265
|
+
* Given an on-disk location, try the path as-is, with `.json` appended, and as
|
|
266
|
+
* a directory containing `tsconfig.json`. Returns the first match or throws.
|
|
267
|
+
*/
|
|
206
268
|
function resolveExistingExtendsPath(location: string): string {
|
|
207
269
|
const candidates = new Set<string>([
|
|
208
270
|
location,
|
|
@@ -217,6 +279,10 @@ function resolveExistingExtendsPath(location: string): string {
|
|
|
217
279
|
throw new Error(`ttsc: extended tsconfig not found: ${location}`);
|
|
218
280
|
}
|
|
219
281
|
|
|
282
|
+
/**
|
|
283
|
+
* Return true when `specifier` is a relative path reference: `.`, `..`, or a
|
|
284
|
+
* string starting with `./`, `../`, `.\\`, or `..\\`.
|
|
285
|
+
*/
|
|
220
286
|
function isRelativeSpecifier(specifier: string): boolean {
|
|
221
287
|
return (
|
|
222
288
|
specifier === "." ||
|
|
@@ -228,10 +294,19 @@ function isRelativeSpecifier(specifier: string): boolean {
|
|
|
228
294
|
);
|
|
229
295
|
}
|
|
230
296
|
|
|
297
|
+
/**
|
|
298
|
+
* Parse a JSONC (JSON with Comments) string by stripping comments and trailing
|
|
299
|
+
* commas before handing off to `JSON.parse`.
|
|
300
|
+
*/
|
|
231
301
|
function parseJsonc(input: string): unknown {
|
|
232
302
|
return JSON.parse(stripTrailingCommas(stripComments(input)));
|
|
233
303
|
}
|
|
234
304
|
|
|
305
|
+
/**
|
|
306
|
+
* Remove `//` line comments and `/* block comments *\/` from a JSONC string.
|
|
307
|
+
* Correctly handles strings that contain comment-like character sequences by
|
|
308
|
+
* tracking string boundaries and escape characters.
|
|
309
|
+
*/
|
|
235
310
|
function stripComments(input: string): string {
|
|
236
311
|
let output = "";
|
|
237
312
|
let inBlockComment = false;
|
|
@@ -292,6 +367,11 @@ function stripComments(input: string): string {
|
|
|
292
367
|
return output;
|
|
293
368
|
}
|
|
294
369
|
|
|
370
|
+
/**
|
|
371
|
+
* Remove trailing commas before `}` or `]` from a JSON string (after comments
|
|
372
|
+
* have already been stripped). Handles string boundaries and escape characters
|
|
373
|
+
* to avoid removing commas inside string values.
|
|
374
|
+
*/
|
|
295
375
|
function stripTrailingCommas(input: string): string {
|
|
296
376
|
let output = "";
|
|
297
377
|
let inString = false;
|
|
@@ -330,6 +410,11 @@ function stripTrailingCommas(input: string): string {
|
|
|
330
410
|
return output;
|
|
331
411
|
}
|
|
332
412
|
|
|
413
|
+
/**
|
|
414
|
+
* Return the first non-whitespace character at or after position `from` in
|
|
415
|
+
* `input`, or `undefined` when only whitespace remains. Used by
|
|
416
|
+
* `stripTrailingCommas` to detect whether a comma is trailing.
|
|
417
|
+
*/
|
|
333
418
|
function nextNonWhitespace(input: string, from: number): string | undefined {
|
|
334
419
|
for (let i = from; i < input.length; i += 1) {
|
|
335
420
|
const current = input[i]!;
|