goscript 0.2.1 → 0.2.3
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/compiler/gotest/runner.go +98 -0
- package/compiler/gotest/runner_test.go +45 -0
- package/compiler/gotest/testdata/browserapi/browserapi_test.go +36 -0
- package/compiler/lowering.go +227 -11
- package/compiler/override-registry_test.go +50 -0
- package/compiler/protobuf-ts-binding.go +155 -7
- package/compiler/protobuf-ts-binding_test.go +116 -2
- package/compiler/runtime-contract.go +2 -0
- package/compiler/runtime-contract_test.go +1 -0
- package/compiler/semantic-model.go +16 -0
- package/compiler/semantic-model_test.go +38 -0
- package/compiler/skeleton_test.go +477 -16
- package/compiler/typescript-emitter.go +4 -0
- package/dist/gs/builtin/builtin.js +7 -9
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/defer.js +2 -2
- package/dist/gs/builtin/hostio.js +5 -5
- package/dist/gs/builtin/hostio.js.map +1 -1
- package/dist/gs/builtin/map.js +2 -1
- package/dist/gs/builtin/map.js.map +1 -1
- package/dist/gs/builtin/slice.d.ts +3 -0
- package/dist/gs/builtin/slice.js +39 -0
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.js +49 -0
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/compress/zlib/index.js +5 -2
- package/dist/gs/compress/zlib/index.js.map +1 -1
- package/dist/gs/crypto/aes/index.d.ts +15 -0
- package/dist/gs/crypto/aes/index.js +57 -0
- package/dist/gs/crypto/aes/index.js.map +1 -0
- package/dist/gs/crypto/cipher/index.d.ts +41 -0
- package/dist/gs/crypto/cipher/index.js +255 -0
- package/dist/gs/crypto/cipher/index.js.map +1 -0
- package/dist/gs/crypto/ecdh/index.js +27 -8
- package/dist/gs/crypto/ecdh/index.js.map +1 -1
- package/dist/gs/crypto/ed25519/index.js +3 -3
- package/dist/gs/crypto/ed25519/index.js.map +1 -1
- package/dist/gs/crypto/rand/index.js +6 -3
- package/dist/gs/crypto/rand/index.js.map +1 -1
- package/dist/gs/embed/index.js +9 -3
- package/dist/gs/embed/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -0
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +33 -0
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
- package/dist/gs/github.com/mr-tron/base58/base58/index.js +4 -1
- package/dist/gs/github.com/mr-tron/base58/base58/index.js.map +1 -1
- package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.d.ts +31 -0
- package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.js +117 -0
- package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.js.map +1 -0
- package/dist/gs/golang.org/x/crypto/scrypt/index.d.ts +2 -0
- package/dist/gs/golang.org/x/crypto/scrypt/index.js +39 -0
- package/dist/gs/golang.org/x/crypto/scrypt/index.js.map +1 -0
- package/dist/gs/hash/fnv/index.js +13 -5
- package/dist/gs/hash/fnv/index.js.map +1 -1
- package/dist/gs/io/fs/glob.d.ts +3 -3
- package/dist/gs/io/fs/glob.js +8 -8
- package/dist/gs/io/fs/glob.js.map +1 -1
- package/dist/gs/io/fs/readdir.d.ts +2 -2
- package/dist/gs/io/fs/readdir.js +13 -74
- package/dist/gs/io/fs/readdir.js.map +1 -1
- package/dist/gs/io/fs/sub.js +4 -4
- package/dist/gs/io/fs/sub.js.map +1 -1
- package/dist/gs/io/fs/walk.js +1 -1
- package/dist/gs/io/fs/walk.js.map +1 -1
- package/dist/gs/io/io.js +18 -2
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/maps/iter.js.map +1 -1
- package/dist/gs/maps/maps.js.map +1 -1
- package/dist/gs/mime/index.js +5 -2
- package/dist/gs/mime/index.js.map +1 -1
- package/dist/gs/net/http/httptest/index.js +6 -3
- package/dist/gs/net/http/httptest/index.js.map +1 -1
- package/dist/gs/net/http/index.d.ts +16 -4
- package/dist/gs/net/http/index.js +236 -40
- package/dist/gs/net/http/index.js.map +1 -1
- package/dist/gs/net/http/pprof/index.js.map +1 -1
- package/dist/gs/reflect/iter.js +1 -1
- package/dist/gs/reflect/iter.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +2 -0
- package/dist/gs/reflect/type.js +53 -21
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/runtime/debug/index.js +2 -1
- package/dist/gs/runtime/debug/index.js.map +1 -1
- package/dist/gs/runtime/pprof/index.js.map +1 -1
- package/dist/gs/runtime/runtime.js +2 -2
- package/dist/gs/runtime/runtime.js.map +1 -1
- package/dist/gs/runtime/trace/index.js.map +1 -1
- package/dist/gs/slices/slices.d.ts +1 -1
- package/dist/gs/slices/slices.js +37 -4
- package/dist/gs/slices/slices.js.map +1 -1
- package/go.mod +2 -2
- package/go.sum +2 -0
- package/gs/builtin/builtin.ts +11 -14
- package/gs/builtin/defer.ts +2 -2
- package/gs/builtin/hostio.test.ts +8 -3
- package/gs/builtin/hostio.ts +5 -7
- package/gs/builtin/map.ts +4 -1
- package/gs/builtin/slice.test.ts +14 -0
- package/gs/builtin/slice.ts +64 -0
- package/gs/builtin/type.ts +72 -0
- package/gs/bytes/bytes.test.ts +14 -13
- package/gs/compress/zlib/index.test.ts +19 -5
- package/gs/compress/zlib/index.ts +16 -7
- package/gs/context/context.test.ts +3 -1
- package/gs/crypto/aes/index.test.ts +120 -0
- package/gs/crypto/aes/index.ts +76 -0
- package/gs/crypto/cipher/index.ts +345 -0
- package/gs/crypto/cipher/meta.json +6 -0
- package/gs/crypto/ecdh/index.test.ts +6 -2
- package/gs/crypto/ecdh/index.ts +49 -12
- package/gs/crypto/ed25519/index.ts +20 -7
- package/gs/crypto/rand/index.ts +6 -3
- package/gs/embed/index.test.ts +3 -3
- package/gs/embed/index.ts +9 -3
- package/gs/fmt/fmt.test.ts +29 -4
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +126 -0
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +46 -0
- package/gs/github.com/mr-tron/base58/base58/index.ts +9 -3
- package/gs/github.com/zeebo/blake3/internal/consts/index.test.ts +2 -8
- package/gs/golang.org/x/crypto/chacha20poly1305/index.test.ts +91 -0
- package/gs/golang.org/x/crypto/chacha20poly1305/index.ts +245 -0
- package/gs/golang.org/x/crypto/scrypt/index.test.ts +81 -0
- package/gs/golang.org/x/crypto/scrypt/index.ts +54 -0
- package/gs/golang.org/x/crypto/scrypt/meta.json +5 -0
- package/gs/hash/fnv/index.test.ts +1 -8
- package/gs/hash/fnv/index.ts +27 -10
- package/gs/io/fs/glob.ts +13 -10
- package/gs/io/fs/meta.json +2 -0
- package/gs/io/fs/readdir.test.ts +63 -2
- package/gs/io/fs/readdir.ts +33 -30
- package/gs/io/fs/sub.ts +4 -4
- package/gs/io/fs/walk.ts +1 -1
- package/gs/io/io.test.ts +56 -1
- package/gs/io/io.ts +19 -2
- package/gs/maps/iter.ts +9 -9
- package/gs/maps/maps.ts +4 -4
- package/gs/math/bits/index.test.ts +10 -1
- package/gs/mime/index.test.ts +33 -15
- package/gs/mime/index.ts +9 -2
- package/gs/net/http/httptest/index.test.ts +17 -3
- package/gs/net/http/httptest/index.ts +8 -3
- package/gs/net/http/index.test.ts +645 -123
- package/gs/net/http/index.ts +548 -113
- package/gs/net/http/pprof/index.ts +24 -6
- package/gs/os/file_unix_js.test.ts +22 -0
- package/gs/reflect/iter.ts +4 -2
- package/gs/reflect/map.test.ts +56 -1
- package/gs/reflect/type.ts +76 -37
- package/gs/runtime/debug/index.test.ts +32 -4
- package/gs/runtime/debug/index.ts +5 -2
- package/gs/runtime/pprof/index.test.ts +7 -1
- package/gs/runtime/pprof/index.ts +5 -1
- package/gs/runtime/runtime.test.ts +7 -0
- package/gs/runtime/runtime.ts +2 -4
- package/gs/runtime/trace/index.test.ts +9 -1
- package/gs/runtime/trace/index.ts +5 -1
- package/gs/slices/meta.json +3 -0
- package/gs/slices/slices.test.ts +59 -21
- package/gs/slices/slices.ts +61 -20
- package/gs/strconv/complex.test.ts +17 -3
- package/gs/sync/atomic/doc_64.test.ts +2 -9
- package/gs/sync/sync.test.ts +18 -8
- package/gs/syscall/js/index.test.ts +9 -4
- package/package.json +13 -5
|
@@ -5,6 +5,7 @@ import (
|
|
|
5
5
|
"go/ast"
|
|
6
6
|
"os"
|
|
7
7
|
"path/filepath"
|
|
8
|
+
"slices"
|
|
8
9
|
"strings"
|
|
9
10
|
)
|
|
10
11
|
|
|
@@ -16,6 +17,13 @@ type protobufTypeScriptBinding struct {
|
|
|
16
17
|
hasOneof bool
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
type protobufTypeScriptBindingOneofCase struct {
|
|
21
|
+
groupLocalName string
|
|
22
|
+
caseLocalName string
|
|
23
|
+
branchCtor string
|
|
24
|
+
valueCtor string
|
|
25
|
+
}
|
|
26
|
+
|
|
19
27
|
func protobufTypeScriptBindings(semPkg *semanticPackage, options LoweringOptions) (map[string]protobufTypeScriptBinding, []Diagnostic) {
|
|
20
28
|
if semPkg == nil || semPkg.source == nil || !options.ProtobufTypeScriptBinding {
|
|
21
29
|
return nil, nil
|
|
@@ -194,7 +202,7 @@ func protobufTypeScriptBindingExportedConsts(tsPath string) map[string]bool {
|
|
|
194
202
|
return nil
|
|
195
203
|
}
|
|
196
204
|
exports := make(map[string]bool)
|
|
197
|
-
for
|
|
205
|
+
for line := range strings.SplitSeq(string(data), "\n") {
|
|
198
206
|
line = strings.TrimSpace(line)
|
|
199
207
|
if !strings.HasPrefix(line, "export const ") {
|
|
200
208
|
continue
|
|
@@ -291,6 +299,7 @@ func rewriteProtobufTypeScriptBindingFile(file *loweredFile, binding protobufTyp
|
|
|
291
299
|
source: binding.importSource,
|
|
292
300
|
sideEffect: true,
|
|
293
301
|
})
|
|
302
|
+
oneofCases := protobufTypeScriptBindingOneofCases(file)
|
|
294
303
|
var setupDecls []loweredDecl
|
|
295
304
|
for _, decl := range file.decls {
|
|
296
305
|
if decl.structType == nil {
|
|
@@ -306,7 +315,7 @@ func rewriteProtobufTypeScriptBindingFile(file *loweredFile, binding protobufTyp
|
|
|
306
315
|
if !ok {
|
|
307
316
|
continue
|
|
308
317
|
}
|
|
309
|
-
setup := protobufTypeScriptBindingStructSetupDecl(decl.structType, importAlias, messageName)
|
|
318
|
+
setup := protobufTypeScriptBindingStructSetupDecl(decl.structType, importAlias, messageName, oneofCases[decl.structType.name])
|
|
310
319
|
if setup.code != "" {
|
|
311
320
|
setupDecls = append(setupDecls, setup)
|
|
312
321
|
}
|
|
@@ -314,6 +323,102 @@ func rewriteProtobufTypeScriptBindingFile(file *loweredFile, binding protobufTyp
|
|
|
314
323
|
file.decls = append(file.decls, setupDecls...)
|
|
315
324
|
}
|
|
316
325
|
|
|
326
|
+
func protobufTypeScriptBindingOneofCases(file *loweredFile) map[string][]protobufTypeScriptBindingOneofCase {
|
|
327
|
+
parentByName := make(map[string]*loweredStruct)
|
|
328
|
+
for _, decl := range file.decls {
|
|
329
|
+
if decl.structType != nil {
|
|
330
|
+
parentByName[decl.structType.name] = decl.structType
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
out := make(map[string][]protobufTypeScriptBindingOneofCase)
|
|
334
|
+
for _, decl := range file.decls {
|
|
335
|
+
branch := decl.structType
|
|
336
|
+
if branch == nil || !strings.Contains(branch.name, "_") {
|
|
337
|
+
continue
|
|
338
|
+
}
|
|
339
|
+
parent := protobufTypeScriptBindingOneofParent(branch.name, parentByName)
|
|
340
|
+
if parent == nil {
|
|
341
|
+
continue
|
|
342
|
+
}
|
|
343
|
+
groups := protobufTypeScriptBindingOneofGroups(parent)
|
|
344
|
+
if len(groups) == 0 {
|
|
345
|
+
continue
|
|
346
|
+
}
|
|
347
|
+
groupLocalName := protobufTypeScriptBindingOneofCaseGroup(branch, parent, groups)
|
|
348
|
+
if groupLocalName == "" {
|
|
349
|
+
continue
|
|
350
|
+
}
|
|
351
|
+
for _, field := range branch.fields {
|
|
352
|
+
if !strings.Contains(field.tag, "oneof") {
|
|
353
|
+
continue
|
|
354
|
+
}
|
|
355
|
+
out[parent.name] = append(out[parent.name], protobufTypeScriptBindingOneofCase{
|
|
356
|
+
groupLocalName: groupLocalName,
|
|
357
|
+
caseLocalName: protobufTypeScriptBindingFieldLocalName(field),
|
|
358
|
+
branchCtor: branch.name,
|
|
359
|
+
valueCtor: protobufTypeScriptBindingFieldCtor(field),
|
|
360
|
+
})
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
for parentName := range out {
|
|
364
|
+
slices.SortFunc(out[parentName], func(left, right protobufTypeScriptBindingOneofCase) int {
|
|
365
|
+
if left.groupLocalName != right.groupLocalName {
|
|
366
|
+
return strings.Compare(left.groupLocalName, right.groupLocalName)
|
|
367
|
+
}
|
|
368
|
+
return strings.Compare(left.caseLocalName, right.caseLocalName)
|
|
369
|
+
})
|
|
370
|
+
}
|
|
371
|
+
return out
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
func protobufTypeScriptBindingOneofParent(branchName string, parents map[string]*loweredStruct) *loweredStruct {
|
|
375
|
+
var parent *loweredStruct
|
|
376
|
+
for name, candidate := range parents {
|
|
377
|
+
if name == branchName || !strings.HasPrefix(branchName, name+"_") {
|
|
378
|
+
continue
|
|
379
|
+
}
|
|
380
|
+
if parent == nil || len(name) > len(parent.name) {
|
|
381
|
+
parent = candidate
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return parent
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
func protobufTypeScriptBindingOneofGroups(parent *loweredStruct) map[string]string {
|
|
388
|
+
groups := make(map[string]string)
|
|
389
|
+
for _, field := range parent.fields {
|
|
390
|
+
if !strings.Contains(field.tag, "protobuf_oneof") {
|
|
391
|
+
continue
|
|
392
|
+
}
|
|
393
|
+
localName := protobufTypeScriptBindingTagValue(field.tag, "protobuf_oneof:\"")
|
|
394
|
+
if localName == "" {
|
|
395
|
+
groups[field.name] = protobufTypeScriptBindingFieldLocalName(field)
|
|
396
|
+
continue
|
|
397
|
+
}
|
|
398
|
+
groups[field.name] = protobufTypeScriptBindingProtoCamel(localName)
|
|
399
|
+
}
|
|
400
|
+
return groups
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
func protobufTypeScriptBindingOneofCaseGroup(branch, parent *loweredStruct, groups map[string]string) string {
|
|
404
|
+
if len(groups) == 1 {
|
|
405
|
+
for _, localName := range groups {
|
|
406
|
+
return localName
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
prefix := "is" + parent.name + "_"
|
|
410
|
+
for _, method := range branch.methods {
|
|
411
|
+
groupName, ok := strings.CutPrefix(method.name, prefix)
|
|
412
|
+
if !ok {
|
|
413
|
+
continue
|
|
414
|
+
}
|
|
415
|
+
if localName := groups[groupName]; localName != "" {
|
|
416
|
+
return localName
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return ""
|
|
420
|
+
}
|
|
421
|
+
|
|
317
422
|
func protobufTypeScriptBindingSyntheticMapEntry(name string) bool {
|
|
318
423
|
return strings.Contains(name, "_") && strings.HasSuffix(name, "Entry")
|
|
319
424
|
}
|
|
@@ -466,23 +571,66 @@ func protobufBindingParam(method *loweredFunction, idx int, fallback string) str
|
|
|
466
571
|
return method.params[idx].name
|
|
467
572
|
}
|
|
468
573
|
|
|
469
|
-
func protobufTypeScriptBindingStructSetupDecl(structType *loweredStruct, importAlias, messageName string) loweredDecl {
|
|
574
|
+
func protobufTypeScriptBindingStructSetupDecl(structType *loweredStruct, importAlias, messageName string, oneofCases []protobufTypeScriptBindingOneofCase) loweredDecl {
|
|
470
575
|
if structType == nil {
|
|
471
576
|
return loweredDecl{}
|
|
472
577
|
}
|
|
473
578
|
if messageName == "" {
|
|
474
579
|
messageName = structType.name
|
|
475
580
|
}
|
|
476
|
-
|
|
581
|
+
fieldEntries := make(map[string]string)
|
|
477
582
|
for _, field := range structType.fields {
|
|
478
583
|
ctor := protobufTypeScriptBindingFieldCtor(field)
|
|
479
584
|
if ctor == "" {
|
|
480
585
|
continue
|
|
481
586
|
}
|
|
482
|
-
|
|
587
|
+
fieldEntries[protobufTypeScriptBindingFieldLocalName(field)] = ctor
|
|
588
|
+
}
|
|
589
|
+
for _, oneofCase := range oneofCases {
|
|
590
|
+
if oneofCase.valueCtor != "" {
|
|
591
|
+
fieldEntries[oneofCase.caseLocalName] = oneofCase.valueCtor
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
fieldNames := make([]string, 0, len(fieldEntries))
|
|
595
|
+
for name := range fieldEntries {
|
|
596
|
+
fieldNames = append(fieldNames, name)
|
|
597
|
+
}
|
|
598
|
+
slices.Sort(fieldNames)
|
|
599
|
+
entries := make([]string, 0, len(fieldNames))
|
|
600
|
+
for _, name := range fieldNames {
|
|
601
|
+
entries = append(entries, strconvQuote(name)+": "+fieldEntries[name])
|
|
602
|
+
}
|
|
603
|
+
code := "(" + structType.name + " as any).__protobufTypeScriptMessage = " + importAlias + "." + messageName + ";\n" +
|
|
604
|
+
"(" + structType.name + " as any).__protobufTypeScriptFields = {" + strings.Join(entries, ", ") + "};"
|
|
605
|
+
if len(oneofCases) != 0 {
|
|
606
|
+
code += "\n(" + structType.name + " as any).__protobufTypeScriptOneofFields = " + protobufTypeScriptBindingOneofFieldsLiteral(oneofCases) + ";"
|
|
607
|
+
}
|
|
608
|
+
return loweredDecl{code: code}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
func protobufTypeScriptBindingOneofFieldsLiteral(oneofCases []protobufTypeScriptBindingOneofCase) string {
|
|
612
|
+
groups := make(map[string][]protobufTypeScriptBindingOneofCase)
|
|
613
|
+
for _, oneofCase := range oneofCases {
|
|
614
|
+
groups[oneofCase.groupLocalName] = append(groups[oneofCase.groupLocalName], oneofCase)
|
|
615
|
+
}
|
|
616
|
+
groupNames := make([]string, 0, len(groups))
|
|
617
|
+
for name := range groups {
|
|
618
|
+
groupNames = append(groupNames, name)
|
|
619
|
+
}
|
|
620
|
+
slices.Sort(groupNames)
|
|
621
|
+
entries := make([]string, 0, len(groupNames))
|
|
622
|
+
for _, groupName := range groupNames {
|
|
623
|
+
cases := groups[groupName]
|
|
624
|
+
slices.SortFunc(cases, func(left, right protobufTypeScriptBindingOneofCase) int {
|
|
625
|
+
return strings.Compare(left.caseLocalName, right.caseLocalName)
|
|
626
|
+
})
|
|
627
|
+
caseEntries := make([]string, 0, len(cases))
|
|
628
|
+
for _, oneofCase := range cases {
|
|
629
|
+
caseEntries = append(caseEntries, strconvQuote(oneofCase.caseLocalName)+": "+oneofCase.branchCtor)
|
|
630
|
+
}
|
|
631
|
+
entries = append(entries, strconvQuote(groupName)+": {"+strings.Join(caseEntries, ", ")+"}")
|
|
483
632
|
}
|
|
484
|
-
return
|
|
485
|
-
"(" + structType.name + " as any).__protobufTypeScriptFields = {" + strings.Join(entries, ", ") + "};"}
|
|
633
|
+
return "{" + strings.Join(entries, ", ") + "}"
|
|
486
634
|
}
|
|
487
635
|
|
|
488
636
|
func protobufTypeScriptBindingFieldLocalName(field loweredStructField) string {
|
|
@@ -80,6 +80,115 @@ func NewFoo() Foo {
|
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
func TestProtobufTypeScriptBindingRewritesGeneratedMethodsToBoundHelpers(t *testing.T) {
|
|
84
|
+
dir := t.TempDir()
|
|
85
|
+
writeTestFile(t, dir, "go.mod", `module example.test/protobufbindingmethods
|
|
86
|
+
|
|
87
|
+
go 1.25
|
|
88
|
+
|
|
89
|
+
require github.com/aperturerobotics/protobuf-go-lite v0.0.0
|
|
90
|
+
|
|
91
|
+
replace github.com/aperturerobotics/protobuf-go-lite => ./protobuf-go-lite
|
|
92
|
+
`)
|
|
93
|
+
writeTestFile(t, dir, "protobuf-go-lite/go.mod", `module github.com/aperturerobotics/protobuf-go-lite
|
|
94
|
+
|
|
95
|
+
go 1.25
|
|
96
|
+
`)
|
|
97
|
+
writeTestFile(t, dir, "protobuf-go-lite/protobuf-go-lite.go", `package protobuf_go_lite
|
|
98
|
+
|
|
99
|
+
type CloneMessage interface {
|
|
100
|
+
CloneMessageVT() CloneMessage
|
|
101
|
+
}
|
|
102
|
+
`)
|
|
103
|
+
writeTestFile(t, dir, "foo.pb.go", `package protobufbindingmethods
|
|
104
|
+
|
|
105
|
+
import protobuf_go_lite "github.com/aperturerobotics/protobuf-go-lite"
|
|
106
|
+
|
|
107
|
+
type Foo struct {
|
|
108
|
+
Name string
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
func (x *Foo) CloneMessageVT() protobuf_go_lite.CloneMessage {
|
|
112
|
+
println("inline CloneMessageVT marker")
|
|
113
|
+
return x.CloneVT()
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
func (x *Foo) CloneVT() *Foo {
|
|
117
|
+
println("inline CloneVT marker")
|
|
118
|
+
return &Foo{Name: x.Name}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
func (x *Foo) EqualVT(other *Foo) bool {
|
|
122
|
+
println("inline EqualVT marker")
|
|
123
|
+
return other != nil && x.Name == other.Name
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
func (x *Foo) MarshalVT() ([]byte, error) {
|
|
127
|
+
println("inline MarshalVT marker")
|
|
128
|
+
return []byte(x.Name), nil
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
func (x *Foo) MarshalToSizedBufferVT(data []byte) (int, error) {
|
|
132
|
+
println("inline MarshalToSizedBufferVT marker")
|
|
133
|
+
return copy(data, x.Name), nil
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
func (x *Foo) SizeVT() int {
|
|
137
|
+
println("inline SizeVT marker")
|
|
138
|
+
return len(x.Name)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
func (x *Foo) UnmarshalVT(data []byte) error {
|
|
142
|
+
println("inline UnmarshalVT marker")
|
|
143
|
+
x.Name = string(data)
|
|
144
|
+
return nil
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
func (x *Foo) Reset() {
|
|
148
|
+
println("inline Reset marker")
|
|
149
|
+
*x = Foo{}
|
|
150
|
+
}
|
|
151
|
+
`)
|
|
152
|
+
writeTestFile(t, dir, "foo.pb.ts", `export interface Foo {
|
|
153
|
+
name?: string
|
|
154
|
+
}
|
|
155
|
+
export const Foo = {} as any
|
|
156
|
+
`)
|
|
157
|
+
|
|
158
|
+
out := filepath.Join(dir, "out")
|
|
159
|
+
comp, err := NewCompiler(&Config{
|
|
160
|
+
Dir: dir,
|
|
161
|
+
OutputPath: out,
|
|
162
|
+
ProtobufTypeScriptBinding: true,
|
|
163
|
+
}, nil, nil)
|
|
164
|
+
if err != nil {
|
|
165
|
+
t.Fatal(err)
|
|
166
|
+
}
|
|
167
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
168
|
+
t.Fatalf("compile with protobuf TypeScript binding: %v", err)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
binding := readTestFile(t, filepath.Join(out, "@goscript", "example.test", "protobufbindingmethods", "foo.pb.ts"))
|
|
172
|
+
wantSnippets := []string{
|
|
173
|
+
`$.interfaceValue<protobuf_go_lite.CloneMessage | null>(protobuf_go_lite.CloneBoundMessage(Foo, this) as any, "*protobufbindingmethods.Foo")`,
|
|
174
|
+
`return protobuf_go_lite.CloneBoundMessage(Foo, this) as any`,
|
|
175
|
+
`protobuf_go_lite.EqualBoundMessage(Foo, this, other)`,
|
|
176
|
+
`protobuf_go_lite.MarshalBoundMessageVT(Foo, this)`,
|
|
177
|
+
`protobuf_go_lite.MarshalBoundMessageToSizedBufferVT(Foo, this, data)`,
|
|
178
|
+
`protobuf_go_lite.SizeBoundMessageVT(Foo, this)`,
|
|
179
|
+
`protobuf_go_lite.UnmarshalBoundMessageVT(Foo, this, data)`,
|
|
180
|
+
`$.assignStruct($.pointerValue<Foo>(this), $.markAsStructValue(new Foo()))`,
|
|
181
|
+
}
|
|
182
|
+
for _, snippet := range wantSnippets {
|
|
183
|
+
if !strings.Contains(binding, snippet) {
|
|
184
|
+
t.Fatalf("binding file should rewrite generated methods through %q, got:\n%s", snippet, binding)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if strings.Contains(binding, "inline ") {
|
|
188
|
+
t.Fatalf("binding file should not preserve inline generated method bodies, got:\n%s", binding)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
83
192
|
func TestProtobufTypeScriptBindingEmitsMetadataForPreservedOneofFiles(t *testing.T) {
|
|
84
193
|
dir := t.TempDir()
|
|
85
194
|
writeTestFile(t, dir, "go.mod", "module example.test/oneofpb\n\ngo 1.25\n")
|
|
@@ -95,7 +204,11 @@ func TestProtobufTypeScriptBindingEmitsMetadataForPreservedOneofFiles(t *testing
|
|
|
95
204
|
"type Wrapper_StringValue struct {\n"+
|
|
96
205
|
"\tStringValue string `protobuf:\"bytes,2,opt,name=string_value,json=stringValue,proto3,oneof\"`\n"+
|
|
97
206
|
"}\n\n"+
|
|
98
|
-
"func (*Wrapper_StringValue) isWrapper_Choice() {}\n"
|
|
207
|
+
"func (*Wrapper_StringValue) isWrapper_Choice() {}\n\n"+
|
|
208
|
+
"type Wrapper_InnerValue struct {\n"+
|
|
209
|
+
"\tInnerValue *Inner `protobuf:\"bytes,3,opt,name=inner_value,json=innerValue,proto3,oneof\"`\n"+
|
|
210
|
+
"}\n\n"+
|
|
211
|
+
"func (*Wrapper_InnerValue) isWrapper_Choice() {}\n")
|
|
99
212
|
writeTestFile(t, dir, "foo.pb.ts", `export interface Inner {
|
|
100
213
|
name?: string
|
|
101
214
|
}
|
|
@@ -122,7 +235,8 @@ export const Wrapper = {} as any
|
|
|
122
235
|
binding := readTestFile(t, filepath.Join(out, "@goscript", "example.test", "oneofpb", "foo.pb.ts"))
|
|
123
236
|
if !strings.Contains(binding, `import * as __protobuf_ts`) ||
|
|
124
237
|
!strings.Contains(binding, `(Wrapper as any).__protobufTypeScriptMessage = __protobuf_ts.Wrapper;`) ||
|
|
125
|
-
!strings.Contains(binding, `(Wrapper as any).__protobufTypeScriptFields = {"inner": Inner};`)
|
|
238
|
+
!strings.Contains(binding, `(Wrapper as any).__protobufTypeScriptFields = {"inner": Inner, "innerValue": Inner};`) ||
|
|
239
|
+
!strings.Contains(binding, `(Wrapper as any).__protobufTypeScriptOneofFields = {"choice": {"innerValue": Wrapper_InnerValue, "stringValue": Wrapper_StringValue}};`) {
|
|
126
240
|
t.Fatalf("oneof-preserved protobuf file should still expose TypeScript metadata, got:\n%s", binding)
|
|
127
241
|
}
|
|
128
242
|
if strings.Contains(binding, `__protobuf_ts.Wrapper_StringValue`) {
|
|
@@ -88,6 +88,7 @@ const (
|
|
|
88
88
|
RuntimeHelperSliceToArray RuntimeHelper = "slice.sliceToArray"
|
|
89
89
|
RuntimeHelperSliceToArrayPointer RuntimeHelper = "slice.sliceToArrayPointer"
|
|
90
90
|
RuntimeHelperAppend RuntimeHelper = "slice.append"
|
|
91
|
+
RuntimeHelperAppendSlice RuntimeHelper = "slice.appendSlice"
|
|
91
92
|
RuntimeHelperCopy RuntimeHelper = "slice.copy"
|
|
92
93
|
RuntimeHelperAsArray RuntimeHelper = "slice.asArray"
|
|
93
94
|
RuntimeHelperStringToRunes RuntimeHelper = "slice.stringToRunes"
|
|
@@ -318,6 +319,7 @@ func runtimeHelperContracts() []RuntimeHelperContract {
|
|
|
318
319
|
runtimeHelper(RuntimeHelperSliceToArray, "sliceToArray", RuntimeHelperCategorySlice),
|
|
319
320
|
runtimeHelper(RuntimeHelperSliceToArrayPointer, "sliceToArrayPointer", RuntimeHelperCategorySlice),
|
|
320
321
|
runtimeHelper(RuntimeHelperAppend, "append", RuntimeHelperCategorySlice),
|
|
322
|
+
runtimeHelper(RuntimeHelperAppendSlice, "appendSlice", RuntimeHelperCategorySlice),
|
|
321
323
|
runtimeHelper(RuntimeHelperCopy, "copy", RuntimeHelperCategorySlice),
|
|
322
324
|
runtimeHelper(RuntimeHelperAsArray, "asArray", RuntimeHelperCategorySlice),
|
|
323
325
|
runtimeHelper(RuntimeHelperStringToRunes, "stringToRunes", RuntimeHelperCategorySlice),
|
|
@@ -24,6 +24,7 @@ func TestRuntimeContractOwnsBuiltinImportAndHelpers(t *testing.T) {
|
|
|
24
24
|
RuntimeHelperPointerValue: RuntimeHelperCategoryValue,
|
|
25
25
|
RuntimeHelperMakeSlice: RuntimeHelperCategorySlice,
|
|
26
26
|
RuntimeHelperAppend: RuntimeHelperCategorySlice,
|
|
27
|
+
RuntimeHelperAppendSlice: RuntimeHelperCategorySlice,
|
|
27
28
|
RuntimeHelperIndexAddress: RuntimeHelperCategorySlice,
|
|
28
29
|
RuntimeHelperIndexByteAddress: RuntimeHelperCategorySlice,
|
|
29
30
|
RuntimeHelperUnsafePointerRef: RuntimeHelperCategorySlice,
|
|
@@ -769,6 +769,9 @@ func (o *SemanticModelOwner) collectFunctionFacts(
|
|
|
769
769
|
if callUsesFunctionIdentifier(pkg, typed.Fun) {
|
|
770
770
|
markFunctionAsync(semFn, "function-identifier-call")
|
|
771
771
|
}
|
|
772
|
+
if callUsesInterfaceMethod(pkg, typed.Fun) {
|
|
773
|
+
markFunctionAsync(semFn, "interface-method-call")
|
|
774
|
+
}
|
|
772
775
|
if overrideFacts.IsMethodAsync(overrideCallPackage(pkg, typed.Fun), overrideCallMethod(pkg, typed.Fun)) {
|
|
773
776
|
markFunctionAsync(semFn, "override")
|
|
774
777
|
}
|
|
@@ -815,6 +818,9 @@ func recordImmediateFuncLitAsyncFacts(
|
|
|
815
818
|
if callUsesFunctionIdentifier(pkg, typed.Fun) {
|
|
816
819
|
markFunctionAsync(semFn, "async-function-literal-call")
|
|
817
820
|
}
|
|
821
|
+
if callUsesInterfaceMethod(pkg, typed.Fun) {
|
|
822
|
+
markFunctionAsync(semFn, "async-function-literal-call")
|
|
823
|
+
}
|
|
818
824
|
if called != nil {
|
|
819
825
|
calledFn := semanticFunctionFor(model, called)
|
|
820
826
|
if calledFn != nil && calledFn.async {
|
|
@@ -1156,6 +1162,10 @@ func exprMayNeedAwait(model *SemanticModel, pkg *packages.Package, expr ast.Expr
|
|
|
1156
1162
|
needsAwait = true
|
|
1157
1163
|
return false
|
|
1158
1164
|
}
|
|
1165
|
+
if callUsesInterfaceMethod(pkg, typed.Fun) {
|
|
1166
|
+
needsAwait = true
|
|
1167
|
+
return false
|
|
1168
|
+
}
|
|
1159
1169
|
if called := calledFunction(pkg, typed.Fun); called != nil {
|
|
1160
1170
|
semFn := semanticFunctionFor(model, called)
|
|
1161
1171
|
if semFn != nil && semFn.async {
|
|
@@ -1672,6 +1682,9 @@ func (o *SemanticModelOwner) applyInterfaceAsyncMethods(
|
|
|
1672
1682
|
}
|
|
1673
1683
|
for methodName, ifaceMethod := range graphEntry.ifaceMethods {
|
|
1674
1684
|
implMethod := graphEntry.implMethods[methodName]
|
|
1685
|
+
if isSyncErrorMethodFunc(ifaceMethod) || isSyncErrorMethodFunc(implMethod) {
|
|
1686
|
+
continue
|
|
1687
|
+
}
|
|
1675
1688
|
implFn := semanticFunctionFor(model, implMethod)
|
|
1676
1689
|
if implFn != nil && implFn.async {
|
|
1677
1690
|
model.markInterfaceMethodAsync(ifaceMethod)
|
|
@@ -1697,6 +1710,9 @@ func (o *SemanticModelOwner) applyAnonymousInterfaceAsyncMethods(
|
|
|
1697
1710
|
}
|
|
1698
1711
|
for methodName, ifaceMethod := range graphEntry.ifaceMethods {
|
|
1699
1712
|
implMethod := graphEntry.implMethods[methodName]
|
|
1713
|
+
if isSyncErrorMethodFunc(ifaceMethod) || isSyncErrorMethodFunc(implMethod) {
|
|
1714
|
+
continue
|
|
1715
|
+
}
|
|
1700
1716
|
if model.functionAsync(implMethod) {
|
|
1701
1717
|
model.markInterfaceMethodAsync(ifaceMethod)
|
|
1702
1718
|
}
|
|
@@ -604,6 +604,44 @@ func TestSemanticModelMarksFunctionIdentifierCallAsync(t *testing.T) {
|
|
|
604
604
|
}
|
|
605
605
|
}
|
|
606
606
|
|
|
607
|
+
func TestSemanticModelMarksInterfaceMethodCallAsync(t *testing.T) {
|
|
608
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
609
|
+
"go.mod": "module example.test/interfacecall\n\ngo 1.25.3\n",
|
|
610
|
+
"iface/controller.go": strings.Join([]string{
|
|
611
|
+
"package iface",
|
|
612
|
+
"import \"context\"",
|
|
613
|
+
"type Controller interface {",
|
|
614
|
+
" Execute(context.Context) error",
|
|
615
|
+
"}",
|
|
616
|
+
"",
|
|
617
|
+
}, "\n"),
|
|
618
|
+
"controller.go": strings.Join([]string{
|
|
619
|
+
"package interfacecall",
|
|
620
|
+
"import (",
|
|
621
|
+
" \"context\"",
|
|
622
|
+
" \"example.test/interfacecall/iface\"",
|
|
623
|
+
")",
|
|
624
|
+
"func Run(ctx context.Context, c iface.Controller) error {",
|
|
625
|
+
" return c.Execute(ctx)",
|
|
626
|
+
"}",
|
|
627
|
+
"",
|
|
628
|
+
}, "\n"),
|
|
629
|
+
})
|
|
630
|
+
graph := loadPackageGraph(t, &CompileRequest{
|
|
631
|
+
Patterns: []string{".", "./iface"},
|
|
632
|
+
Dir: moduleDir,
|
|
633
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
634
|
+
DependencyMode: DependencyModeAll,
|
|
635
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
636
|
+
})
|
|
637
|
+
model := buildSemanticModel(t, graph)
|
|
638
|
+
run := requireDefinedFunc(t, graph, "example.test/interfacecall", "Run")
|
|
639
|
+
semFn := model.functions[run]
|
|
640
|
+
if semFn == nil || !semFn.async {
|
|
641
|
+
t.Fatalf("expected Run to be async after calling interface method, got %#v", semFn)
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
607
645
|
func buildSemanticModel(t *testing.T, graph *PackageGraph) *SemanticModel {
|
|
608
646
|
t.Helper()
|
|
609
647
|
|