goscript 0.1.4 → 0.2.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 +5 -2
- package/cmd/go_js_wasm_exec/main.go +201 -0
- package/cmd/go_js_wasm_exec/main_test.go +83 -0
- package/cmd/goscript/{cmd_compile.go → cmd-compile.go} +7 -0
- package/cmd/goscript/cmd-test.go +14 -0
- package/cmd/goscript/cmd-test_test.go +1 -1
- package/compiler/compile-request.go +12 -9
- package/compiler/compliance_test.go +0 -1
- package/compiler/config.go +2 -0
- package/compiler/gotest/request.go +28 -0
- package/compiler/gotest/runner.go +353 -27
- package/compiler/gotest/runner_test.go +273 -1
- package/compiler/gotest/testdata/browserapi/browserapi_test.go +20 -0
- package/compiler/gotest/testdata/browserapi/go.mod +3 -0
- package/compiler/lowered-program.go +24 -17
- package/compiler/lowering.go +392 -127
- package/compiler/lowering_bench_test.go +41 -27
- package/compiler/override-facts.go +15 -0
- package/compiler/override-parity-verifier.go +450 -0
- package/compiler/override-parity.go +122 -0
- package/compiler/override-registry_test.go +559 -0
- package/compiler/protobuf-ts-binding.go +514 -0
- package/compiler/protobuf-ts-binding_test.go +172 -0
- package/compiler/semantic-model-types.go +9 -4
- package/compiler/semantic-model.go +282 -70
- package/compiler/semantic-model_test.go +82 -1
- package/compiler/service.go +20 -1
- package/compiler/skeleton_test.go +62 -8
- package/compiler/typescript-emitter.go +128 -13
- package/dist/gs/builtin/slice.d.ts +2 -1
- package/dist/gs/builtin/slice.js +29 -4
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.d.ts +13 -5
- package/dist/gs/builtin/type.js +153 -60
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/builtin/varRef.d.ts +11 -0
- package/dist/gs/builtin/varRef.js +57 -2
- package/dist/gs/builtin/varRef.js.map +1 -1
- package/dist/gs/bytes/buffer.gs.js +1 -1
- package/dist/gs/bytes/buffer.gs.js.map +1 -1
- package/dist/gs/bytes/reader.gs.js +1 -1
- package/dist/gs/bytes/reader.gs.js.map +1 -1
- package/dist/gs/compress/zlib/index.d.ts +10 -3
- package/dist/gs/compress/zlib/index.js +50 -16
- package/dist/gs/compress/zlib/index.js.map +1 -1
- package/dist/gs/encoding/json/index.d.ts +114 -0
- package/dist/gs/encoding/json/index.js +544 -36
- package/dist/gs/encoding/json/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +100 -0
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +564 -0
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/errors.js +54 -30
- package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
- package/dist/gs/go/scanner/index.d.ts +2 -0
- package/dist/gs/go/scanner/index.js +29 -5
- package/dist/gs/go/scanner/index.js.map +1 -1
- package/dist/gs/go/token/index.js +22 -6
- package/dist/gs/go/token/index.js.map +1 -1
- package/dist/gs/hash/index.d.ts +6 -0
- package/dist/gs/hash/index.js +20 -0
- package/dist/gs/hash/index.js.map +1 -1
- package/dist/gs/internal/goarch/index.d.ts +43 -3
- package/dist/gs/internal/goarch/index.js +42 -10
- package/dist/gs/internal/goarch/index.js.map +1 -1
- package/dist/gs/io/fs/fs.js +26 -14
- package/dist/gs/io/fs/fs.js.map +1 -1
- package/dist/gs/io/fs/readdir.js +4 -2
- package/dist/gs/io/fs/readdir.js.map +1 -1
- package/dist/gs/io/fs/sub.js +8 -1
- package/dist/gs/io/fs/sub.js.map +1 -1
- package/dist/gs/io/io.d.ts +2 -0
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/math/bits/index.d.ts +5 -0
- package/dist/gs/math/bits/index.js +16 -4
- package/dist/gs/math/bits/index.js.map +1 -1
- package/dist/gs/mime/index.d.ts +16 -0
- package/dist/gs/mime/index.js +315 -6
- package/dist/gs/mime/index.js.map +1 -1
- package/dist/gs/net/http/httptest/index.d.ts +12 -0
- package/dist/gs/net/http/httptest/index.js +85 -6
- package/dist/gs/net/http/httptest/index.js.map +1 -1
- package/dist/gs/net/http/index.d.ts +300 -5
- package/dist/gs/net/http/index.js +1598 -58
- package/dist/gs/net/http/index.js.map +1 -1
- package/dist/gs/os/dir_unix.gs.js +1 -1
- package/dist/gs/os/dir_unix.gs.js.map +1 -1
- package/dist/gs/os/error.gs.js +1 -1
- package/dist/gs/os/error.gs.js.map +1 -1
- package/dist/gs/os/exec.gs.d.ts +1 -0
- package/dist/gs/os/exec.gs.js +4 -8
- package/dist/gs/os/exec.gs.js.map +1 -1
- package/dist/gs/os/exec_posix.gs.js +1 -1
- package/dist/gs/os/exec_posix.gs.js.map +1 -1
- package/dist/gs/os/index.d.ts +1 -1
- package/dist/gs/os/index.js +1 -1
- package/dist/gs/os/index.js.map +1 -1
- package/dist/gs/os/proc.gs.d.ts +4 -0
- package/dist/gs/os/proc.gs.js +12 -6
- package/dist/gs/os/proc.gs.js.map +1 -1
- package/dist/gs/os/root_js.gs.js +1 -1
- package/dist/gs/os/root_js.gs.js.map +1 -1
- package/dist/gs/os/types.gs.js +1 -1
- package/dist/gs/os/types.gs.js.map +1 -1
- package/dist/gs/os/types_js.gs.js +1 -1
- package/dist/gs/os/types_js.gs.js.map +1 -1
- package/dist/gs/os/types_unix.gs.js +1 -1
- package/dist/gs/os/types_unix.gs.js.map +1 -1
- package/dist/gs/path/path.js +11 -7
- package/dist/gs/path/path.js.map +1 -1
- package/dist/gs/reflect/index.d.ts +5 -4
- package/dist/gs/reflect/index.js +4 -3
- package/dist/gs/reflect/index.js.map +1 -1
- package/dist/gs/reflect/map.js +15 -0
- package/dist/gs/reflect/map.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +25 -6
- package/dist/gs/reflect/type.js +1418 -228
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/reflect/types.d.ts +14 -6
- package/dist/gs/reflect/types.js +35 -1
- package/dist/gs/reflect/types.js.map +1 -1
- package/dist/gs/reflect/value.d.ts +1 -0
- package/dist/gs/reflect/value.js +83 -41
- package/dist/gs/reflect/value.js.map +1 -1
- package/dist/gs/reflect/visiblefields.js +4 -140
- package/dist/gs/reflect/visiblefields.js.map +1 -1
- package/dist/gs/runtime/pprof/index.d.ts +8 -2
- package/dist/gs/runtime/pprof/index.js +50 -30
- package/dist/gs/runtime/pprof/index.js.map +1 -1
- package/dist/gs/runtime/runtime.js +5 -4
- package/dist/gs/runtime/runtime.js.map +1 -1
- package/dist/gs/runtime/trace/index.js +5 -19
- package/dist/gs/runtime/trace/index.js.map +1 -1
- package/dist/gs/strconv/atoi.gs.js +1 -1
- package/dist/gs/strconv/atoi.gs.js.map +1 -1
- package/dist/gs/strconv/complex.gs.d.ts +3 -0
- package/dist/gs/strconv/complex.gs.js +148 -0
- package/dist/gs/strconv/complex.gs.js.map +1 -0
- package/dist/gs/strconv/index.d.ts +1 -0
- package/dist/gs/strconv/index.js +1 -0
- package/dist/gs/strconv/index.js.map +1 -1
- package/dist/gs/strings/builder.js +1 -1
- package/dist/gs/strings/reader.js +9 -5
- package/dist/gs/strings/reader.js.map +1 -1
- package/dist/gs/strings/replace.js +15 -7
- package/dist/gs/strings/replace.js.map +1 -1
- package/dist/gs/strings/strings.d.ts +5 -0
- package/dist/gs/strings/strings.js +57 -5
- package/dist/gs/strings/strings.js.map +1 -1
- package/dist/gs/sync/atomic/type.gs.js +9 -9
- package/dist/gs/sync/atomic/type.gs.js.map +1 -1
- package/dist/gs/sync/atomic/value.gs.js +2 -2
- package/dist/gs/sync/atomic/value.gs.js.map +1 -1
- package/dist/gs/syscall/env.js +22 -14
- package/dist/gs/syscall/env.js.map +1 -1
- package/dist/gs/testing/testing.js +55 -13
- package/dist/gs/testing/testing.js.map +1 -1
- package/dist/gs/time/time.d.ts +24 -1
- package/dist/gs/time/time.js +43 -3
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unique/index.js +7 -1
- package/dist/gs/unique/index.js.map +1 -1
- package/go.mod +3 -3
- package/go.sum +16 -0
- package/gs/builtin/runtime-contract.test.ts +218 -21
- package/gs/builtin/slice.ts +44 -4
- package/gs/builtin/type.ts +226 -59
- package/gs/builtin/varRef.ts +85 -2
- package/gs/bytes/buffer.gs.ts +1 -1
- package/gs/bytes/reader.gs.ts +1 -1
- package/gs/compress/zlib/index.test.ts +62 -1
- package/gs/compress/zlib/index.ts +53 -16
- package/gs/compress/zlib/parity.json +51 -0
- package/gs/encoding/json/index.test.ts +360 -6
- package/gs/encoding/json/index.ts +679 -38
- package/gs/encoding/json/parity.json +81 -0
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +211 -3
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +857 -1
- package/gs/github.com/pkg/errors/errors.ts +54 -30
- package/gs/go/scanner/index.test.ts +39 -56
- package/gs/go/scanner/index.ts +33 -5
- package/gs/go/scanner/parity.json +27 -0
- package/gs/go/token/index.ts +22 -6
- package/gs/hash/index.test.ts +20 -33
- package/gs/hash/index.ts +28 -0
- package/gs/hash/parity.json +21 -0
- package/gs/internal/goarch/index.test.ts +32 -0
- package/gs/internal/goarch/index.ts +45 -13
- package/gs/internal/goarch/parity.json +144 -0
- package/gs/io/fs/fs.ts +26 -14
- package/gs/io/fs/readdir.ts +4 -4
- package/gs/io/fs/sub.ts +8 -1
- package/gs/io/io.ts +1 -0
- package/gs/io/parity.json +162 -0
- package/gs/math/bits/index.test.ts +14 -1
- package/gs/math/bits/index.ts +23 -4
- package/gs/math/bits/parity.json +156 -0
- package/gs/mime/index.test.ts +90 -0
- package/gs/mime/index.ts +369 -6
- package/gs/mime/parity.json +36 -0
- package/gs/net/http/httptest/index.test.ts +98 -2
- package/gs/net/http/httptest/index.ts +101 -6
- package/gs/net/http/httptest/parity.json +15 -0
- package/gs/net/http/index.test.ts +781 -12
- package/gs/net/http/index.ts +1860 -139
- package/gs/net/http/meta.json +16 -1
- package/gs/net/http/parity.json +193 -0
- package/gs/os/dir_unix.gs.ts +1 -1
- package/gs/os/error.gs.ts +1 -1
- package/gs/os/exec.gs.ts +4 -8
- package/gs/os/exec_posix.gs.ts +1 -1
- package/gs/os/index.test.ts +9 -0
- package/gs/os/index.ts +1 -0
- package/gs/os/parity.json +9 -0
- package/gs/os/proc.gs.ts +18 -5
- package/gs/os/proc.test.ts +26 -0
- package/gs/os/root_js.gs.ts +1 -1
- package/gs/os/types.gs.ts +1 -1
- package/gs/os/types_js.gs.ts +1 -1
- package/gs/os/types_unix.gs.ts +1 -1
- package/gs/path/path.ts +11 -7
- package/gs/reflect/field.test.ts +37 -15
- package/gs/reflect/function-types.test.ts +518 -22
- package/gs/reflect/index.ts +8 -6
- package/gs/reflect/map.ts +20 -0
- package/gs/reflect/meta.json +6 -4
- package/gs/reflect/parity.json +234 -0
- package/gs/reflect/sliceat.test.ts +156 -0
- package/gs/reflect/structof.test.ts +401 -0
- package/gs/reflect/type.ts +1897 -317
- package/gs/reflect/typefor.test.ts +510 -10
- package/gs/reflect/types.ts +43 -18
- package/gs/reflect/value.ts +105 -45
- package/gs/reflect/visiblefields.ts +5 -168
- package/gs/runtime/parity.json +24 -0
- package/gs/runtime/pprof/index.test.ts +29 -7
- package/gs/runtime/pprof/index.ts +56 -30
- package/gs/runtime/pprof/parity.json +27 -0
- package/gs/runtime/runtime.test.ts +3 -1
- package/gs/runtime/runtime.ts +4 -3
- package/gs/runtime/trace/index.test.ts +5 -3
- package/gs/runtime/trace/index.ts +8 -20
- package/gs/runtime/trace/parity.json +36 -0
- package/gs/strconv/atoi.gs.ts +1 -1
- package/gs/strconv/complex.gs.ts +174 -0
- package/gs/strconv/complex.test.ts +65 -0
- package/gs/strconv/index.ts +1 -0
- package/gs/strconv/parity.json +120 -0
- package/gs/strings/builder.ts +1 -1
- package/gs/strings/parity.json +186 -0
- package/gs/strings/reader.ts +9 -5
- package/gs/strings/replace.ts +15 -7
- package/gs/strings/strings.test.ts +22 -2
- package/gs/strings/strings.ts +64 -6
- package/gs/sync/atomic/type.gs.ts +9 -9
- package/gs/sync/atomic/value.gs.ts +2 -2
- package/gs/syscall/env.ts +29 -14
- package/gs/testing/testing.test.ts +67 -0
- package/gs/testing/testing.ts +87 -19
- package/gs/time/parity.json +225 -0
- package/gs/time/time.test.ts +20 -2
- package/gs/time/time.ts +49 -7
- package/gs/unique/index.ts +7 -1
- package/package.json +4 -2
- package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +0 -217
- package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +0 -926
- package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +0 -1
- package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +0 -38
- package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +0 -1361
- package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +0 -46
- /package/compiler/{wasm_api.go → wasm-api.go} +0 -0
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"go/ast"
|
|
6
|
+
"os"
|
|
7
|
+
"path/filepath"
|
|
8
|
+
"strings"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
type protobufTypeScriptBinding struct {
|
|
12
|
+
sourcePath string
|
|
13
|
+
outputName string
|
|
14
|
+
importSource string
|
|
15
|
+
messageNames map[string]string
|
|
16
|
+
hasOneof bool
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
func protobufTypeScriptBindings(semPkg *semanticPackage, options LoweringOptions) (map[string]protobufTypeScriptBinding, []Diagnostic) {
|
|
20
|
+
if semPkg == nil || semPkg.source == nil || !options.ProtobufTypeScriptBinding {
|
|
21
|
+
return nil, nil
|
|
22
|
+
}
|
|
23
|
+
bindings := make(map[string]protobufTypeScriptBinding)
|
|
24
|
+
var diagnostics []Diagnostic
|
|
25
|
+
for idx, syntax := range semPkg.source.Syntax {
|
|
26
|
+
sourcePath := sourceFilePath(semPkg, idx, syntax)
|
|
27
|
+
if !strings.HasSuffix(sourcePath, ".pb.go") {
|
|
28
|
+
continue
|
|
29
|
+
}
|
|
30
|
+
if strings.HasSuffix(filepath.Base(sourcePath), "_srpc.pb.go") {
|
|
31
|
+
continue
|
|
32
|
+
}
|
|
33
|
+
if !protobufTypeScriptBindingInSourceRoot(options.SourceRoot, sourcePath) {
|
|
34
|
+
continue
|
|
35
|
+
}
|
|
36
|
+
tsPath := strings.TrimSuffix(sourcePath, ".go") + ".ts"
|
|
37
|
+
if _, err := os.Stat(tsPath); err != nil {
|
|
38
|
+
if os.IsNotExist(err) {
|
|
39
|
+
diagnostics = append(diagnostics, Diagnostic{
|
|
40
|
+
Severity: DiagnosticSeverityError,
|
|
41
|
+
Code: "goscript/protobuf-ts-binding:missing",
|
|
42
|
+
Message: "protobuf TypeScript binding is missing sibling .pb.ts",
|
|
43
|
+
Detail: fmt.Sprintf("%s requires %s", sourcePath, tsPath),
|
|
44
|
+
})
|
|
45
|
+
continue
|
|
46
|
+
}
|
|
47
|
+
diagnostics = append(diagnostics, Diagnostic{
|
|
48
|
+
Severity: DiagnosticSeverityError,
|
|
49
|
+
Code: "goscript/protobuf-ts-binding:stat",
|
|
50
|
+
Message: "failed to inspect protobuf TypeScript binding",
|
|
51
|
+
Detail: err.Error(),
|
|
52
|
+
})
|
|
53
|
+
continue
|
|
54
|
+
}
|
|
55
|
+
importSource, err := protobufTypeScriptBindingImportSource(options.OutputPath, semPkg.pkgPath, tsPath)
|
|
56
|
+
if err != nil {
|
|
57
|
+
diagnostics = append(diagnostics, Diagnostic{
|
|
58
|
+
Severity: DiagnosticSeverityError,
|
|
59
|
+
Code: "goscript/protobuf-ts-binding:import-source",
|
|
60
|
+
Message: "failed to compute protobuf TypeScript binding import",
|
|
61
|
+
Detail: err.Error(),
|
|
62
|
+
})
|
|
63
|
+
continue
|
|
64
|
+
}
|
|
65
|
+
bindings[sourcePath] = protobufTypeScriptBinding{
|
|
66
|
+
sourcePath: sourcePath,
|
|
67
|
+
outputName: strings.TrimSuffix(filepath.Base(sourcePath), ".go") + ".ts",
|
|
68
|
+
importSource: importSource,
|
|
69
|
+
messageNames: protobufTypeScriptBindingMessageNames(syntax),
|
|
70
|
+
hasOneof: protobufTypeScriptBindingHasOneof(syntax),
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return bindings, diagnostics
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
func protobufTypeScriptBindingRoot(dir string) string {
|
|
77
|
+
dir = strings.TrimSpace(dir)
|
|
78
|
+
if dir == "" {
|
|
79
|
+
return ""
|
|
80
|
+
}
|
|
81
|
+
abs, err := filepath.Abs(dir)
|
|
82
|
+
if err != nil {
|
|
83
|
+
return dir
|
|
84
|
+
}
|
|
85
|
+
for {
|
|
86
|
+
if _, err := os.Stat(filepath.Join(abs, "go.mod")); err == nil {
|
|
87
|
+
return abs
|
|
88
|
+
}
|
|
89
|
+
parent := filepath.Dir(abs)
|
|
90
|
+
if parent == abs {
|
|
91
|
+
return dir
|
|
92
|
+
}
|
|
93
|
+
abs = parent
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
func protobufTypeScriptBindingInSourceRoot(sourceRoot, sourcePath string) bool {
|
|
98
|
+
if strings.TrimSpace(sourceRoot) == "" {
|
|
99
|
+
return true
|
|
100
|
+
}
|
|
101
|
+
rootAbs, err := filepath.Abs(sourceRoot)
|
|
102
|
+
if err != nil {
|
|
103
|
+
return false
|
|
104
|
+
}
|
|
105
|
+
sourceAbs, err := filepath.Abs(sourcePath)
|
|
106
|
+
if err != nil {
|
|
107
|
+
return false
|
|
108
|
+
}
|
|
109
|
+
rel, err := filepath.Rel(rootAbs, sourceAbs)
|
|
110
|
+
if err != nil {
|
|
111
|
+
return false
|
|
112
|
+
}
|
|
113
|
+
return rel == "." || !strings.HasPrefix(rel, ".."+string(filepath.Separator)) && rel != ".." && !filepath.IsAbs(rel)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
func protobufTypeScriptBindingImportSource(outputPath, pkgPath, tsPath string) (string, error) {
|
|
117
|
+
outputDir := filepath.Join(outputPath, "@goscript", filepath.FromSlash(pkgPath))
|
|
118
|
+
outputDir, err := filepath.Abs(outputDir)
|
|
119
|
+
if err != nil {
|
|
120
|
+
return "", err
|
|
121
|
+
}
|
|
122
|
+
rel, err := filepath.Rel(outputDir, tsPath)
|
|
123
|
+
if err != nil {
|
|
124
|
+
return "", err
|
|
125
|
+
}
|
|
126
|
+
rel = filepath.ToSlash(rel)
|
|
127
|
+
if !strings.HasPrefix(rel, ".") {
|
|
128
|
+
rel = "./" + rel
|
|
129
|
+
}
|
|
130
|
+
return strings.TrimSuffix(rel, ".ts") + ".js", nil
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
func protobufTypeScriptBindingHasOneof(file *ast.File) bool {
|
|
134
|
+
if file == nil {
|
|
135
|
+
return false
|
|
136
|
+
}
|
|
137
|
+
for _, decl := range file.Decls {
|
|
138
|
+
genDecl, ok := decl.(*ast.GenDecl)
|
|
139
|
+
if !ok {
|
|
140
|
+
continue
|
|
141
|
+
}
|
|
142
|
+
for _, spec := range genDecl.Specs {
|
|
143
|
+
typeSpec, ok := spec.(*ast.TypeSpec)
|
|
144
|
+
if !ok {
|
|
145
|
+
continue
|
|
146
|
+
}
|
|
147
|
+
structType, ok := typeSpec.Type.(*ast.StructType)
|
|
148
|
+
if !ok || structType.Fields == nil {
|
|
149
|
+
continue
|
|
150
|
+
}
|
|
151
|
+
for _, field := range structType.Fields.List {
|
|
152
|
+
if field.Tag != nil && strings.Contains(field.Tag.Value, "protobuf_oneof") {
|
|
153
|
+
return true
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return false
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
func protobufTypeScriptBindingMessageNames(file *ast.File) map[string]string {
|
|
162
|
+
names := make(map[string]string)
|
|
163
|
+
if file == nil {
|
|
164
|
+
return names
|
|
165
|
+
}
|
|
166
|
+
for _, decl := range file.Decls {
|
|
167
|
+
genDecl, ok := decl.(*ast.GenDecl)
|
|
168
|
+
if !ok {
|
|
169
|
+
continue
|
|
170
|
+
}
|
|
171
|
+
for _, spec := range genDecl.Specs {
|
|
172
|
+
typeSpec, ok := spec.(*ast.TypeSpec)
|
|
173
|
+
if !ok {
|
|
174
|
+
continue
|
|
175
|
+
}
|
|
176
|
+
if _, ok := typeSpec.Type.(*ast.StructType); !ok {
|
|
177
|
+
continue
|
|
178
|
+
}
|
|
179
|
+
name := typeSpec.Name.Name
|
|
180
|
+
names[name] = protobufTypeScriptBindingSafeIdentifier(name)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return names
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
func protobufTypeScriptBindingSafeIdentifier(name string) string {
|
|
187
|
+
switch name {
|
|
188
|
+
case "break",
|
|
189
|
+
"case",
|
|
190
|
+
"catch",
|
|
191
|
+
"class",
|
|
192
|
+
"const",
|
|
193
|
+
"continue",
|
|
194
|
+
"debugger",
|
|
195
|
+
"default",
|
|
196
|
+
"delete",
|
|
197
|
+
"do",
|
|
198
|
+
"else",
|
|
199
|
+
"export",
|
|
200
|
+
"extends",
|
|
201
|
+
"false",
|
|
202
|
+
"finally",
|
|
203
|
+
"for",
|
|
204
|
+
"function",
|
|
205
|
+
"if",
|
|
206
|
+
"import",
|
|
207
|
+
"in",
|
|
208
|
+
"instanceof",
|
|
209
|
+
"new",
|
|
210
|
+
"null",
|
|
211
|
+
"return",
|
|
212
|
+
"super",
|
|
213
|
+
"switch",
|
|
214
|
+
"this",
|
|
215
|
+
"throw",
|
|
216
|
+
"true",
|
|
217
|
+
"try",
|
|
218
|
+
"typeof",
|
|
219
|
+
"var",
|
|
220
|
+
"void",
|
|
221
|
+
"while",
|
|
222
|
+
"with",
|
|
223
|
+
"yield",
|
|
224
|
+
"enum",
|
|
225
|
+
"implements",
|
|
226
|
+
"interface",
|
|
227
|
+
"let",
|
|
228
|
+
"package",
|
|
229
|
+
"private",
|
|
230
|
+
"protected",
|
|
231
|
+
"public",
|
|
232
|
+
"static",
|
|
233
|
+
"Object",
|
|
234
|
+
"bigint",
|
|
235
|
+
"number",
|
|
236
|
+
"boolean",
|
|
237
|
+
"string",
|
|
238
|
+
"object",
|
|
239
|
+
"globalThis",
|
|
240
|
+
"Uint8Array",
|
|
241
|
+
"Partial":
|
|
242
|
+
return name + "$"
|
|
243
|
+
default:
|
|
244
|
+
return name
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
func rewriteProtobufTypeScriptBindingFile(file *loweredFile, binding protobufTypeScriptBinding) {
|
|
249
|
+
if file == nil {
|
|
250
|
+
return
|
|
251
|
+
}
|
|
252
|
+
file.outputName = binding.outputName
|
|
253
|
+
if binding.hasOneof {
|
|
254
|
+
return
|
|
255
|
+
}
|
|
256
|
+
const importAlias = "__protobuf_ts"
|
|
257
|
+
file.imports = append(file.imports, loweredImport{
|
|
258
|
+
alias: importAlias,
|
|
259
|
+
source: binding.importSource,
|
|
260
|
+
sideEffect: true,
|
|
261
|
+
})
|
|
262
|
+
var setupDecls []loweredDecl
|
|
263
|
+
for _, decl := range file.decls {
|
|
264
|
+
if decl.structType == nil {
|
|
265
|
+
continue
|
|
266
|
+
}
|
|
267
|
+
if protobufTypeScriptBindingSyntheticMapEntry(decl.structType.name) {
|
|
268
|
+
continue
|
|
269
|
+
}
|
|
270
|
+
rewriteProtobufTypeScriptBindingStruct(decl.structType)
|
|
271
|
+
setup := protobufTypeScriptBindingStructSetupDecl(decl.structType, importAlias, binding.messageNames[decl.structType.name])
|
|
272
|
+
if setup.code != "" {
|
|
273
|
+
setupDecls = append(setupDecls, setup)
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
file.decls = append(file.decls, setupDecls...)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
func protobufTypeScriptBindingSyntheticMapEntry(name string) bool {
|
|
280
|
+
return strings.Contains(name, "_") && strings.HasSuffix(name, "Entry")
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
func lowerProtobufSRPCTypeScriptBindingStub(semPkg *semanticPackage, sourcePath string, options LoweringOptions) (*loweredFile, []Diagnostic) {
|
|
284
|
+
tsPath := strings.TrimSuffix(sourcePath, ".go") + ".ts"
|
|
285
|
+
if _, err := os.Stat(tsPath); err != nil {
|
|
286
|
+
if os.IsNotExist(err) {
|
|
287
|
+
return nil, nil
|
|
288
|
+
}
|
|
289
|
+
return nil, []Diagnostic{{
|
|
290
|
+
Severity: DiagnosticSeverityError,
|
|
291
|
+
Code: "goscript/protobuf-ts-binding:srpc-stat",
|
|
292
|
+
Message: "failed to inspect SRPC TypeScript binding",
|
|
293
|
+
Detail: err.Error(),
|
|
294
|
+
}}
|
|
295
|
+
}
|
|
296
|
+
importSource, err := protobufTypeScriptBindingImportSource(options.OutputPath, semPkg.pkgPath, tsPath)
|
|
297
|
+
if err != nil {
|
|
298
|
+
return nil, []Diagnostic{{
|
|
299
|
+
Severity: DiagnosticSeverityError,
|
|
300
|
+
Code: "goscript/protobuf-ts-binding:srpc-import-source",
|
|
301
|
+
Message: "failed to compute SRPC TypeScript binding import",
|
|
302
|
+
Detail: err.Error(),
|
|
303
|
+
}}
|
|
304
|
+
}
|
|
305
|
+
return &loweredFile{
|
|
306
|
+
sourcePath: sourcePath,
|
|
307
|
+
outputName: sourceOutputName(sourcePath),
|
|
308
|
+
decls: []loweredDecl{{
|
|
309
|
+
code: "export * from " + strconvQuote(importSource),
|
|
310
|
+
}},
|
|
311
|
+
exportAll: true,
|
|
312
|
+
}, nil
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
func protobufSRPCHasGoScriptReplacement(sourcePath string) bool {
|
|
316
|
+
base := filepath.Base(sourcePath)
|
|
317
|
+
if !strings.HasSuffix(base, "_srpc.pb.go") {
|
|
318
|
+
return false
|
|
319
|
+
}
|
|
320
|
+
replacement := strings.TrimSuffix(base, "_srpc.pb.go") + "-srpc-goscript.go"
|
|
321
|
+
_, err := os.Stat(filepath.Join(filepath.Dir(sourcePath), replacement))
|
|
322
|
+
return err == nil
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
func rewriteProtobufTypeScriptBindingStruct(structType *loweredStruct) {
|
|
326
|
+
if structType == nil {
|
|
327
|
+
return
|
|
328
|
+
}
|
|
329
|
+
for idx := range structType.methods {
|
|
330
|
+
method := &structType.methods[idx]
|
|
331
|
+
body := protobufTypeScriptBindingMethodBody(structType, method)
|
|
332
|
+
if body == "" {
|
|
333
|
+
continue
|
|
334
|
+
}
|
|
335
|
+
method.async = false
|
|
336
|
+
method.paramBindings = nil
|
|
337
|
+
method.namedResults = nil
|
|
338
|
+
method.deferState = nil
|
|
339
|
+
method.body = []loweredStmt{{text: body}}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
func protobufTypeScriptBindingMethodBody(structType *loweredStruct, method *loweredFunction) string {
|
|
344
|
+
if structType == nil || method == nil {
|
|
345
|
+
return ""
|
|
346
|
+
}
|
|
347
|
+
ctor := structType.name
|
|
348
|
+
if !protobufTypeScriptBindingReplacesMethodName(method.name) {
|
|
349
|
+
return ""
|
|
350
|
+
}
|
|
351
|
+
switch method.name {
|
|
352
|
+
case "CloneMessageVT":
|
|
353
|
+
return "return $.interfaceValue<protobuf_go_lite.CloneMessage | null>(protobuf_go_lite.CloneBoundMessage(" +
|
|
354
|
+
ctor + ", this) as any, " + strconvQuote("*"+structType.typeName) + ")"
|
|
355
|
+
case "CloneVT":
|
|
356
|
+
return "return protobuf_go_lite.CloneBoundMessage(" + ctor + ", this) as any"
|
|
357
|
+
case "EqualVT":
|
|
358
|
+
return "return protobuf_go_lite.EqualBoundMessage(" + ctor + ", this, " + protobufBindingParam(method, 0, "null") + ")"
|
|
359
|
+
case "MarshalJSON":
|
|
360
|
+
return "return protobuf_go_lite.MarshalBoundMessageJSON(" + ctor + ", this)"
|
|
361
|
+
case "MarshalProtoJSON":
|
|
362
|
+
return "protobuf_go_lite.MarshalBoundMessageProtoJSON(" + ctor + ", this, " + protobufBindingParam(method, 0, "null") + ")"
|
|
363
|
+
case "MarshalProtoText", "String":
|
|
364
|
+
return "return protobuf_go_lite.MarshalBoundMessageProtoText(" + ctor + ", this)"
|
|
365
|
+
case "MarshalToSizedBufferVT":
|
|
366
|
+
return "return protobuf_go_lite.MarshalBoundMessageToSizedBufferVT(" + ctor + ", this, " + protobufBindingParam(method, 0, "null") + ")"
|
|
367
|
+
case "MarshalVT":
|
|
368
|
+
return "return protobuf_go_lite.MarshalBoundMessageVT(" + ctor + ", this)"
|
|
369
|
+
case "ProtoMessage":
|
|
370
|
+
return "return"
|
|
371
|
+
case "Reset":
|
|
372
|
+
return "$.assignStruct($.pointerValue<" + ctor + ">(this), $.markAsStructValue(new " + ctor + "()))"
|
|
373
|
+
case "SizeVT":
|
|
374
|
+
return "return protobuf_go_lite.SizeBoundMessageVT(" + ctor + ", this)"
|
|
375
|
+
case "UnmarshalJSON":
|
|
376
|
+
return "return protobuf_go_lite.UnmarshalBoundMessageJSON(" + ctor + ", this, " + protobufBindingParam(method, 0, "null") + ")"
|
|
377
|
+
case "UnmarshalProtoJSON":
|
|
378
|
+
return "protobuf_go_lite.UnmarshalBoundMessageProtoJSON(" + ctor + ", this, " + protobufBindingParam(method, 0, "null") + ")"
|
|
379
|
+
case "UnmarshalVT":
|
|
380
|
+
return "return protobuf_go_lite.UnmarshalBoundMessageVT(" + ctor + ", this, " + protobufBindingParam(method, 0, "null") + ")"
|
|
381
|
+
default:
|
|
382
|
+
return ""
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
func protobufTypeScriptBindingReplacesMethodName(name string) bool {
|
|
387
|
+
switch name {
|
|
388
|
+
case "CloneMessageVT",
|
|
389
|
+
"CloneVT",
|
|
390
|
+
"EqualVT",
|
|
391
|
+
"MarshalJSON",
|
|
392
|
+
"MarshalProtoJSON",
|
|
393
|
+
"MarshalProtoText",
|
|
394
|
+
"MarshalToSizedBufferVT",
|
|
395
|
+
"MarshalVT",
|
|
396
|
+
"ProtoMessage",
|
|
397
|
+
"Reset",
|
|
398
|
+
"SizeVT",
|
|
399
|
+
"String",
|
|
400
|
+
"UnmarshalJSON",
|
|
401
|
+
"UnmarshalProtoJSON",
|
|
402
|
+
"UnmarshalVT":
|
|
403
|
+
return true
|
|
404
|
+
default:
|
|
405
|
+
return false
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
func protobufBindingParam(method *loweredFunction, idx int, fallback string) string {
|
|
410
|
+
if method == nil || idx < 0 || idx >= len(method.params) || strings.TrimSpace(method.params[idx].name) == "" {
|
|
411
|
+
return fallback
|
|
412
|
+
}
|
|
413
|
+
return method.params[idx].name
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
func protobufTypeScriptBindingStructSetupDecl(structType *loweredStruct, importAlias, messageName string) loweredDecl {
|
|
417
|
+
if structType == nil {
|
|
418
|
+
return loweredDecl{}
|
|
419
|
+
}
|
|
420
|
+
if messageName == "" {
|
|
421
|
+
messageName = structType.name
|
|
422
|
+
}
|
|
423
|
+
entries := make([]string, 0, len(structType.fields))
|
|
424
|
+
for _, field := range structType.fields {
|
|
425
|
+
ctor := protobufTypeScriptBindingFieldCtor(field)
|
|
426
|
+
if ctor == "" {
|
|
427
|
+
continue
|
|
428
|
+
}
|
|
429
|
+
entries = append(entries, strconvQuote(protobufTypeScriptBindingFieldLocalName(field))+": "+ctor)
|
|
430
|
+
}
|
|
431
|
+
return loweredDecl{code: "(" + structType.name + " as any).__protobufTypeScriptMessage = " + importAlias + "." + messageName + ";\n" +
|
|
432
|
+
"(" + structType.name + " as any).__protobufTypeScriptFields = {" + strings.Join(entries, ", ") + "};"}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
func protobufTypeScriptBindingFieldLocalName(field loweredStructField) string {
|
|
436
|
+
if tag := field.tag; tag != "" {
|
|
437
|
+
if value := protobufTypeScriptBindingTagValue(tag, "json="); value != "" {
|
|
438
|
+
return value
|
|
439
|
+
}
|
|
440
|
+
if value := protobufTypeScriptBindingTagValue(tag, "name="); value != "" {
|
|
441
|
+
return protobufTypeScriptBindingProtoCamel(value)
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
if field.name == "" {
|
|
445
|
+
return field.name
|
|
446
|
+
}
|
|
447
|
+
return strings.ToLower(field.name[:1]) + field.name[1:]
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
func protobufTypeScriptBindingTagValue(tag, key string) string {
|
|
451
|
+
idx := strings.Index(tag, key)
|
|
452
|
+
if idx < 0 {
|
|
453
|
+
return ""
|
|
454
|
+
}
|
|
455
|
+
rest := tag[idx+len(key):]
|
|
456
|
+
end := len(rest)
|
|
457
|
+
for idx, ch := range rest {
|
|
458
|
+
if ch == ',' || ch == '"' || ch == '`' || ch == ' ' {
|
|
459
|
+
end = idx
|
|
460
|
+
break
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
return rest[:end]
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
func protobufTypeScriptBindingProtoCamel(name string) string {
|
|
467
|
+
if name == "" {
|
|
468
|
+
return ""
|
|
469
|
+
}
|
|
470
|
+
parts := strings.Split(name, "_")
|
|
471
|
+
var out strings.Builder
|
|
472
|
+
for idx, part := range parts {
|
|
473
|
+
if part == "" {
|
|
474
|
+
continue
|
|
475
|
+
}
|
|
476
|
+
part = strings.ToLower(part)
|
|
477
|
+
if idx == 0 {
|
|
478
|
+
out.WriteString(part)
|
|
479
|
+
continue
|
|
480
|
+
}
|
|
481
|
+
out.WriteString(strings.ToUpper(part[:1]))
|
|
482
|
+
out.WriteString(part[1:])
|
|
483
|
+
}
|
|
484
|
+
return out.String()
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
func protobufTypeScriptBindingFieldCtor(field loweredStructField) string {
|
|
488
|
+
if !strings.Contains(field.runtimeType, "TypeKind.Pointer") {
|
|
489
|
+
return ""
|
|
490
|
+
}
|
|
491
|
+
for _, token := range strings.FieldsFunc(field.typ, func(r rune) bool {
|
|
492
|
+
return !(r == '.' || r == '_' || r == '$' || r >= '0' && r <= '9' || r >= 'A' && r <= 'Z' || r >= 'a' && r <= 'z')
|
|
493
|
+
}) {
|
|
494
|
+
if protobufTypeScriptBindingCtorToken(token) {
|
|
495
|
+
return token
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
return ""
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
func protobufTypeScriptBindingCtorToken(token string) bool {
|
|
502
|
+
if token == "" || strings.HasPrefix(token, "$.") || strings.HasPrefix(token, "globalThis.") {
|
|
503
|
+
return false
|
|
504
|
+
}
|
|
505
|
+
switch token {
|
|
506
|
+
case "any", "bigint", "boolean", "Date", "Map", "null", "number", "Promise", "Set", "Slice", "string", "Uint8Array", "undefined", "unknown", "VarRef", "void":
|
|
507
|
+
return false
|
|
508
|
+
}
|
|
509
|
+
if strings.Contains(token, ".") {
|
|
510
|
+
return true
|
|
511
|
+
}
|
|
512
|
+
first := token[0]
|
|
513
|
+
return first >= 'A' && first <= 'Z'
|
|
514
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"errors"
|
|
6
|
+
"go/ast"
|
|
7
|
+
"os"
|
|
8
|
+
"path/filepath"
|
|
9
|
+
"strings"
|
|
10
|
+
"testing"
|
|
11
|
+
|
|
12
|
+
"golang.org/x/tools/go/packages"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
func TestProtobufTypeScriptBindingSkipsPbGoEmission(t *testing.T) {
|
|
16
|
+
dir := t.TempDir()
|
|
17
|
+
writeTestFile(t, dir, "go.mod", "module example.test/protobufbinding\n\ngo 1.25\n")
|
|
18
|
+
writeTestFile(t, dir, "foo.pb.go", `package protobufbinding
|
|
19
|
+
|
|
20
|
+
type Foo struct {
|
|
21
|
+
Name string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type Object struct {
|
|
25
|
+
Name string
|
|
26
|
+
}
|
|
27
|
+
`)
|
|
28
|
+
writeTestFile(t, dir, "foo.pb.ts", `export interface Foo {
|
|
29
|
+
name?: string
|
|
30
|
+
}
|
|
31
|
+
export const Foo = {} as any
|
|
32
|
+
export interface Object$ {
|
|
33
|
+
name?: string
|
|
34
|
+
}
|
|
35
|
+
export const Object$ = {} as any
|
|
36
|
+
`)
|
|
37
|
+
writeTestFile(t, dir, "use.go", `package protobufbinding
|
|
38
|
+
|
|
39
|
+
func NewFoo() Foo {
|
|
40
|
+
return Foo{Name: "bound"}
|
|
41
|
+
}
|
|
42
|
+
`)
|
|
43
|
+
|
|
44
|
+
out := filepath.Join(dir, "out")
|
|
45
|
+
comp, err := NewCompiler(&Config{
|
|
46
|
+
Dir: dir,
|
|
47
|
+
OutputPath: out,
|
|
48
|
+
ProtobufTypeScriptBinding: true,
|
|
49
|
+
}, nil, nil)
|
|
50
|
+
if err != nil {
|
|
51
|
+
t.Fatal(err)
|
|
52
|
+
}
|
|
53
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
54
|
+
t.Fatalf("compile with protobuf TypeScript binding: %v", err)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
pkgDir := filepath.Join(out, "@goscript", "example.test", "protobufbinding")
|
|
58
|
+
if _, err := os.Stat(filepath.Join(pkgDir, "foo.pb.gs.ts")); !errors.Is(err, os.ErrNotExist) {
|
|
59
|
+
t.Fatalf("bound protobuf file should not emit foo.pb.gs.ts, stat err=%v", err)
|
|
60
|
+
}
|
|
61
|
+
binding := readTestFile(t, filepath.Join(pkgDir, "foo.pb.ts"))
|
|
62
|
+
if !strings.Contains(binding, `import * as __protobuf_ts`) || !strings.Contains(binding, `foo.pb.js`) ||
|
|
63
|
+
!strings.Contains(binding, `class Foo`) || !strings.Contains(binding, `__protobufTypeScriptMessage = __protobuf_ts.Foo`) {
|
|
64
|
+
t.Fatalf("binding file should adapt sibling foo.pb.js, got:\n%s", binding)
|
|
65
|
+
}
|
|
66
|
+
if !strings.Contains(binding, `class Object`) || !strings.Contains(binding, `__protobufTypeScriptMessage = __protobuf_ts.Object$`) {
|
|
67
|
+
t.Fatalf("binding file should use protobuf-es-lite safe identifier for Object, got:\n%s", binding)
|
|
68
|
+
}
|
|
69
|
+
if !strings.Contains(binding, `__protobufTypeScriptMessage = __protobuf_ts.Foo;`) ||
|
|
70
|
+
!strings.Contains(binding, `__protobufTypeScriptFields = {};`) {
|
|
71
|
+
t.Fatalf("binding metadata assignments should be semicolon-terminated to avoid ASI calls, got:\n%s", binding)
|
|
72
|
+
}
|
|
73
|
+
index := readTestFile(t, filepath.Join(pkgDir, "index.ts"))
|
|
74
|
+
if !strings.Contains(index, `export { Foo, Object } from "./foo.pb.ts"`) {
|
|
75
|
+
t.Fatalf("package index should re-export binding file, got:\n%s", index)
|
|
76
|
+
}
|
|
77
|
+
use := readTestFile(t, filepath.Join(pkgDir, "use.gs.ts"))
|
|
78
|
+
if !strings.Contains(use, `from "./foo.pb.ts"`) {
|
|
79
|
+
t.Fatalf("non-protobuf file should import bound protobuf declarations, got:\n%s", use)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
func TestProtobufTypeScriptBindingReportsMissingSibling(t *testing.T) {
|
|
84
|
+
dir := t.TempDir()
|
|
85
|
+
writeTestFile(t, dir, "go.mod", "module example.test/missingpbts\n\ngo 1.25\n")
|
|
86
|
+
writeTestFile(t, dir, "foo.pb.go", `package missingpbts
|
|
87
|
+
|
|
88
|
+
type Foo struct{}
|
|
89
|
+
`)
|
|
90
|
+
|
|
91
|
+
comp, err := NewCompiler(&Config{
|
|
92
|
+
Dir: dir,
|
|
93
|
+
OutputPath: filepath.Join(dir, "out"),
|
|
94
|
+
ProtobufTypeScriptBinding: true,
|
|
95
|
+
}, nil, nil)
|
|
96
|
+
if err != nil {
|
|
97
|
+
t.Fatal(err)
|
|
98
|
+
}
|
|
99
|
+
result, err := comp.CompilePackages(context.Background(), ".")
|
|
100
|
+
if err == nil {
|
|
101
|
+
t.Fatal("expected missing sibling .pb.ts to fail")
|
|
102
|
+
}
|
|
103
|
+
if result == nil {
|
|
104
|
+
t.Fatal("expected diagnostics result")
|
|
105
|
+
}
|
|
106
|
+
for _, diag := range result.Diagnostics {
|
|
107
|
+
if diag.Code == "goscript/protobuf-ts-binding:missing" {
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
t.Fatalf("missing protobuf binding diagnostic not found: %#v", result.Diagnostics)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
func TestProtobufTypeScriptBindingSkipsFilesOutsideSourceRoot(t *testing.T) {
|
|
115
|
+
dir := t.TempDir()
|
|
116
|
+
outside := filepath.Join(t.TempDir(), "outside.pb.go")
|
|
117
|
+
writeTestFile(t, dir, "go.mod", "module example.test/outsidepb\n\ngo 1.25\n")
|
|
118
|
+
writeTestFile(t, dir, "use.go", `package outsidepb
|
|
119
|
+
`)
|
|
120
|
+
|
|
121
|
+
semPkg := &semanticPackage{
|
|
122
|
+
pkgPath: "example.test/outsidepb",
|
|
123
|
+
source: &packages.Package{
|
|
124
|
+
CompiledGoFiles: []string{outside},
|
|
125
|
+
GoFiles: []string{outside},
|
|
126
|
+
Syntax: make([]*ast.File, 1),
|
|
127
|
+
},
|
|
128
|
+
}
|
|
129
|
+
bindings, diagnostics := protobufTypeScriptBindings(semPkg, LoweringOptions{
|
|
130
|
+
SourceRoot: dir,
|
|
131
|
+
OutputPath: filepath.Join(dir, "out"),
|
|
132
|
+
ProtobufTypeScriptBinding: true,
|
|
133
|
+
})
|
|
134
|
+
if len(diagnostics) != 0 {
|
|
135
|
+
t.Fatalf("outside source root diagnostics = %#v", diagnostics)
|
|
136
|
+
}
|
|
137
|
+
if len(bindings) != 0 {
|
|
138
|
+
t.Fatalf("outside source root bindings = %#v", bindings)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
func TestProtobufTypeScriptBindingRootFindsParentModule(t *testing.T) {
|
|
143
|
+
dir := t.TempDir()
|
|
144
|
+
writeTestFile(t, dir, "go.mod", "module example.test/root\n\ngo 1.25\n")
|
|
145
|
+
nested := filepath.Join(dir, ".bldr", "build", "plugin")
|
|
146
|
+
if err := os.MkdirAll(nested, 0o755); err != nil {
|
|
147
|
+
t.Fatal(err)
|
|
148
|
+
}
|
|
149
|
+
if got := protobufTypeScriptBindingRoot(nested); got != dir {
|
|
150
|
+
t.Fatalf("binding root = %q, want %q", got, dir)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
func writeTestFile(t *testing.T, root, rel, data string) {
|
|
155
|
+
t.Helper()
|
|
156
|
+
path := filepath.Join(root, rel)
|
|
157
|
+
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
|
158
|
+
t.Fatal(err)
|
|
159
|
+
}
|
|
160
|
+
if err := os.WriteFile(path, []byte(data), 0o644); err != nil {
|
|
161
|
+
t.Fatal(err)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
func readTestFile(t *testing.T, path string) string {
|
|
166
|
+
t.Helper()
|
|
167
|
+
data, err := os.ReadFile(path)
|
|
168
|
+
if err != nil {
|
|
169
|
+
t.Fatal(err)
|
|
170
|
+
}
|
|
171
|
+
return string(data)
|
|
172
|
+
}
|