typenative 0.2.0 → 0.3.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/.github/workflows/ci.yml +38 -1
- package/.github/workflows/npm-publish-github-packages.yml +6 -1
- package/CHANGELOG.md +46 -0
- package/CONTRIBUTION.md +7 -5
- package/README.md +11 -7
- package/bin/cli.js +4 -0
- package/bin/index.js +50 -6
- package/bin/main.js +8 -4
- package/bin/node/system_extra.js +54 -1
- package/bin/node/timers.js +14 -1
- package/bin/parse-native.js +10 -0
- package/bin/parse-node.js +10 -0
- package/bin/transpiler.js +195 -34
- package/bin/typecheck-node.js +78 -0
- package/bin/version.js +1 -1
- package/conformance.md +2 -1
- package/package.json +2 -1
- package/tsparser/check.go +157 -0
- package/tsparser/main.go +30 -1
- package/types/typenative-npm.d.ts +7 -4
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// Type-checking for the self-hosted compiler (`tsparser --check`): the same
|
|
2
|
+
// program the Node CLI checks with the typescript package (src/typecheck-node.ts),
|
|
3
|
+
// built with typescript-go. Prints the errors as a JSON array.
|
|
4
|
+
package main
|
|
5
|
+
|
|
6
|
+
import (
|
|
7
|
+
"context"
|
|
8
|
+
"encoding/json"
|
|
9
|
+
"fmt"
|
|
10
|
+
"os"
|
|
11
|
+
|
|
12
|
+
"github.com/buke/typescript-go-internal/pkg/ast"
|
|
13
|
+
"github.com/buke/typescript-go-internal/pkg/bundled"
|
|
14
|
+
"github.com/buke/typescript-go-internal/pkg/compiler"
|
|
15
|
+
"github.com/buke/typescript-go-internal/pkg/core"
|
|
16
|
+
"github.com/buke/typescript-go-internal/pkg/diagnostics"
|
|
17
|
+
"github.com/buke/typescript-go-internal/pkg/diagnosticwriter"
|
|
18
|
+
"github.com/buke/typescript-go-internal/pkg/locale"
|
|
19
|
+
"github.com/buke/typescript-go-internal/pkg/scanner"
|
|
20
|
+
"github.com/buke/typescript-go-internal/pkg/tsoptions"
|
|
21
|
+
"github.com/buke/typescript-go-internal/pkg/tspath"
|
|
22
|
+
"github.com/buke/typescript-go-internal/pkg/vfs"
|
|
23
|
+
"github.com/buke/typescript-go-internal/pkg/vfs/osvfs"
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
// checkDiagnostic is one error, in the shape src/parse-native.ts reads
|
|
27
|
+
// (file is absolute; line and column are 1-based, 0 for global errors)
|
|
28
|
+
type checkDiagnostic struct {
|
|
29
|
+
File string `json:"file"`
|
|
30
|
+
Line int `json:"line"`
|
|
31
|
+
Column int `json:"column"`
|
|
32
|
+
Code int32 `json:"code"`
|
|
33
|
+
Message string `json:"message"`
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
type configHost struct {
|
|
37
|
+
fs vfs.FS
|
|
38
|
+
cwd string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
func (h configHost) FS() vfs.FS { return h.fs }
|
|
42
|
+
func (h configHost) GetCurrentDirectory() string { return h.cwd }
|
|
43
|
+
|
|
44
|
+
// The bundled declarations that replace the default lib (types/ in the package)
|
|
45
|
+
var typenativeTypes = []string{"typenative.d.ts", "typenative-go.d.ts", "typenative-npm.d.ts"}
|
|
46
|
+
|
|
47
|
+
// TS18003: "No inputs were found in config file" (only the entry is checked)
|
|
48
|
+
const noInputsFound = 18003
|
|
49
|
+
|
|
50
|
+
// runCheck type-checks entry with the nearest tsconfig.json's options (or
|
|
51
|
+
// TypeNative's defaults) and prints the errors. The program's roots are the
|
|
52
|
+
// entry plus the config's .d.ts files, so other entry points in the same
|
|
53
|
+
// project don't redeclare each other's globals.
|
|
54
|
+
func runCheck(entry string, typesDir string) {
|
|
55
|
+
wd, err := os.Getwd()
|
|
56
|
+
if err != nil {
|
|
57
|
+
fmt.Fprintln(os.Stderr, "getwd:", err)
|
|
58
|
+
os.Exit(1)
|
|
59
|
+
}
|
|
60
|
+
cwd := tspath.NormalizePath(wd)
|
|
61
|
+
fs := bundled.WrapFS(osvfs.FS())
|
|
62
|
+
entryPath := tspath.GetNormalizedAbsolutePath(entry, cwd)
|
|
63
|
+
roots := []string{entryPath}
|
|
64
|
+
out := []checkDiagnostic{}
|
|
65
|
+
|
|
66
|
+
var options *core.CompilerOptions
|
|
67
|
+
if configPath := findConfigFile(fs, tspath.GetDirectoryPath(entryPath)); configPath != "" {
|
|
68
|
+
parsed, errs := tsoptions.GetParsedCommandLineOfConfigFile(configPath, &core.CompilerOptions{}, nil, configHost{fs, cwd}, nil)
|
|
69
|
+
for _, d := range errs {
|
|
70
|
+
out = append(out, toCheckDiagnostic(d))
|
|
71
|
+
}
|
|
72
|
+
if parsed == nil {
|
|
73
|
+
printDiagnostics(out)
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
for _, d := range parsed.Errors {
|
|
77
|
+
if d.Code() != noInputsFound {
|
|
78
|
+
out = append(out, toCheckDiagnostic(d))
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
options = parsed.CompilerOptions()
|
|
82
|
+
for _, name := range parsed.FileNames() {
|
|
83
|
+
if tspath.IsDeclarationFileName(name) && name != entryPath {
|
|
84
|
+
roots = append(roots, name)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
options = &core.CompilerOptions{
|
|
89
|
+
Target: core.ScriptTargetES2020,
|
|
90
|
+
Module: core.ModuleKindESNext,
|
|
91
|
+
ModuleResolution: core.ModuleResolutionKindBundler,
|
|
92
|
+
Lib: []string{},
|
|
93
|
+
Types: []string{},
|
|
94
|
+
Strict: core.TSTrue,
|
|
95
|
+
NoImplicitAny: core.TSTrue,
|
|
96
|
+
AllowSyntheticDefaultImports: core.TSTrue,
|
|
97
|
+
AllowImportingTsExtensions: core.TSTrue,
|
|
98
|
+
Jsx: core.JsxEmitPreserve,
|
|
99
|
+
SkipLibCheck: core.TSTrue,
|
|
100
|
+
}
|
|
101
|
+
typesPath := tspath.GetNormalizedAbsolutePath(typesDir, cwd)
|
|
102
|
+
for _, name := range typenativeTypes {
|
|
103
|
+
roots = append(roots, tspath.CombinePaths(typesPath, name))
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
options.NoEmit = core.TSTrue
|
|
107
|
+
|
|
108
|
+
config := tsoptions.NewParsedCommandLine(options, roots, tspath.ComparePathsOptions{
|
|
109
|
+
UseCaseSensitiveFileNames: fs.UseCaseSensitiveFileNames(),
|
|
110
|
+
CurrentDirectory: cwd,
|
|
111
|
+
})
|
|
112
|
+
host := compiler.NewCompilerHost(cwd, fs, bundled.LibPath(), nil, nil)
|
|
113
|
+
program := compiler.NewProgram(compiler.ProgramOptions{Config: config, Host: host})
|
|
114
|
+
ctx := context.Background()
|
|
115
|
+
for _, d := range compiler.GetDiagnosticsOfAnyProgram(ctx, program, nil, false, program.GetBindDiagnostics, program.GetSemanticDiagnostics) {
|
|
116
|
+
if d.Category() == diagnostics.CategoryError {
|
|
117
|
+
out = append(out, toCheckDiagnostic(d))
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
printDiagnostics(out)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// findConfigFile walks up from dir to the nearest tsconfig.json
|
|
124
|
+
func findConfigFile(fs vfs.FS, dir string) string {
|
|
125
|
+
for {
|
|
126
|
+
candidate := tspath.CombinePaths(dir, "tsconfig.json")
|
|
127
|
+
if fs.FileExists(candidate) {
|
|
128
|
+
return candidate
|
|
129
|
+
}
|
|
130
|
+
parent := tspath.GetDirectoryPath(dir)
|
|
131
|
+
if parent == dir {
|
|
132
|
+
return ""
|
|
133
|
+
}
|
|
134
|
+
dir = parent
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
func toCheckDiagnostic(d *ast.Diagnostic) checkDiagnostic {
|
|
139
|
+
out := checkDiagnostic{
|
|
140
|
+
Code: d.Code(),
|
|
141
|
+
Message: diagnosticwriter.FlattenDiagnosticMessage(&diagnosticwriter.ASTDiagnostic{Diagnostic: d}, "\n", locale.Default),
|
|
142
|
+
}
|
|
143
|
+
if file := d.File(); file != nil {
|
|
144
|
+
line, character := scanner.GetECMALineAndUTF16CharacterOfPosition(file, d.Pos())
|
|
145
|
+
out.File = file.FileName()
|
|
146
|
+
out.Line = line + 1
|
|
147
|
+
out.Column = int(character) + 1
|
|
148
|
+
}
|
|
149
|
+
return out
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
func printDiagnostics(out []checkDiagnostic) {
|
|
153
|
+
if err := json.NewEncoder(os.Stdout).Encode(out); err != nil {
|
|
154
|
+
fmt.Fprintln(os.Stderr, "encode:", err)
|
|
155
|
+
os.Exit(1)
|
|
156
|
+
}
|
|
157
|
+
}
|
package/tsparser/main.go
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
// the same transpiler code can consume ASTs from either source.
|
|
7
7
|
//
|
|
8
8
|
// Usage: tsparser < file.ts > ast.json
|
|
9
|
+
//
|
|
10
|
+
// tsparser --check <file.ts> <types dir> type-checks a program (see check.go)
|
|
9
11
|
package main
|
|
10
12
|
|
|
11
13
|
import (
|
|
@@ -25,7 +27,18 @@ import (
|
|
|
25
27
|
// The parsed source, for template raw text
|
|
26
28
|
var sourceText string
|
|
27
29
|
|
|
30
|
+
// The parsed file, for node positions
|
|
31
|
+
var parsedFile *ast.SourceFile
|
|
32
|
+
|
|
28
33
|
func main() {
|
|
34
|
+
if len(os.Args) > 1 && os.Args[1] == "--check" {
|
|
35
|
+
if len(os.Args) < 4 {
|
|
36
|
+
fmt.Fprintln(os.Stderr, "usage: tsparser --check <file.ts> <types dir>")
|
|
37
|
+
os.Exit(2)
|
|
38
|
+
}
|
|
39
|
+
runCheck(os.Args[2], os.Args[3])
|
|
40
|
+
return
|
|
41
|
+
}
|
|
29
42
|
sourceBytes, err := io.ReadAll(os.Stdin)
|
|
30
43
|
if err != nil {
|
|
31
44
|
fmt.Fprintln(os.Stderr, "read stdin:", err)
|
|
@@ -44,6 +57,7 @@ func main() {
|
|
|
44
57
|
string(sourceBytes),
|
|
45
58
|
scriptKind,
|
|
46
59
|
)
|
|
60
|
+
parsedFile = sourceFile
|
|
47
61
|
out := serializeNode(sourceFile.AsNode())
|
|
48
62
|
enc := json.NewEncoder(os.Stdout)
|
|
49
63
|
enc.SetIndent("", " ")
|
|
@@ -126,6 +140,7 @@ func serializeNode(n *ast.Node) any {
|
|
|
126
140
|
inProgress[n] = true
|
|
127
141
|
defer delete(inProgress, n)
|
|
128
142
|
obj := map[string]any{"kind": strings.TrimPrefix(n.Kind.String(), "Kind")}
|
|
143
|
+
setPosition(n, obj)
|
|
129
144
|
// SourceFile bookkeeping fields are not part of the language AST
|
|
130
145
|
if n.Kind == ast.KindSourceFile {
|
|
131
146
|
statements := []any{}
|
|
@@ -166,7 +181,9 @@ func serializeNode(n *ast.Node) any {
|
|
|
166
181
|
// BindingElement; the TypeScript API exposes them as OmittedExpression
|
|
167
182
|
if n.Kind == ast.KindBindingElement {
|
|
168
183
|
if be := n.AsBindingElement(); be != nil && be.Name() == nil && be.DotDotDotToken == nil {
|
|
169
|
-
|
|
184
|
+
hole := map[string]any{"kind": "OmittedExpression"}
|
|
185
|
+
setPosition(n, hole)
|
|
186
|
+
return hole
|
|
170
187
|
}
|
|
171
188
|
}
|
|
172
189
|
|
|
@@ -194,6 +211,18 @@ func serializeNode(n *ast.Node) any {
|
|
|
194
211
|
return obj
|
|
195
212
|
}
|
|
196
213
|
|
|
214
|
+
// setPosition records the 1-based line and column of the node's first token
|
|
215
|
+
// (columns count UTF-16 units, as in the TypeScript API); the transpiler maps
|
|
216
|
+
// Go positions back to them
|
|
217
|
+
func setPosition(n *ast.Node, obj map[string]any) {
|
|
218
|
+
if n.Kind == ast.KindSourceFile || n.Pos() < 0 || parsedFile == nil {
|
|
219
|
+
return
|
|
220
|
+
}
|
|
221
|
+
line, character := scanner.GetECMALineAndUTF16CharacterOfPosition(parsedFile, scanner.GetTokenPosOfNode(n, parsedFile, false))
|
|
222
|
+
obj["line"] = line + 1
|
|
223
|
+
obj["column"] = int(character) + 1
|
|
224
|
+
}
|
|
225
|
+
|
|
197
226
|
// collectFields serializes a typed data struct's fields into obj, recursing
|
|
198
227
|
// into embedded base structs (DeclarationBase, FunctionLikeBase, ...) so their
|
|
199
228
|
// fields are hoisted like the TypeScript API exposes them.
|
|
@@ -2463,11 +2463,14 @@ declare module 'node:sqlite' {
|
|
|
2463
2463
|
useBigIntArguments?: boolean;
|
|
2464
2464
|
varargs?: boolean;
|
|
2465
2465
|
}
|
|
2466
|
+
// Callbacks get each SQL argument converted to the type their parameter
|
|
2467
|
+
// declares ((x: number) => …), so their arguments are typed `any` here
|
|
2468
|
+
// rather than SQLOutputValue as in @types/node
|
|
2466
2469
|
interface AggregateOptions<T extends SQLInputValue = SQLInputValue> extends FunctionOptions {
|
|
2467
2470
|
start: T | (() => T);
|
|
2468
|
-
step: (accumulator: T, ...args:
|
|
2471
|
+
step: (accumulator: T, ...args: any[]) => T;
|
|
2469
2472
|
result?: (accumulator: T) => SQLInputValue;
|
|
2470
|
-
inverse?: (accumulator: T, ...args:
|
|
2473
|
+
inverse?: (accumulator: T, ...args: any[]) => T;
|
|
2471
2474
|
}
|
|
2472
2475
|
interface PrepareOptions {
|
|
2473
2476
|
readBigInts?: boolean;
|
|
@@ -2488,8 +2491,8 @@ declare module 'node:sqlite' {
|
|
|
2488
2491
|
exec(sql: string): void;
|
|
2489
2492
|
prepare(sql: string, options?: PrepareOptions): StatementSync;
|
|
2490
2493
|
location(dbName?: string): string | null;
|
|
2491
|
-
function(name: string, options: FunctionOptions, fn: (...args:
|
|
2492
|
-
function(name: string, fn: (...args:
|
|
2494
|
+
function(name: string, options: FunctionOptions, fn: (...args: any[]) => SQLInputValue): void;
|
|
2495
|
+
function(name: string, fn: (...args: any[]) => SQLInputValue): void;
|
|
2493
2496
|
aggregate(name: string, options: AggregateOptions): void;
|
|
2494
2497
|
aggregate<T extends SQLInputValue>(name: string, options: AggregateOptions<T>): void;
|
|
2495
2498
|
setAuthorizer(
|