goscript 0.0.26 → 0.0.29
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 +4 -4
- package/cmd/goscript/cmd_compile.go +0 -3
- package/cmd/goscript/deps.go +11 -0
- package/compiler/analysis.go +298 -55
- package/compiler/assignment.go +2 -2
- package/compiler/builtin_test.go +1 -1
- package/compiler/compiler.go +200 -68
- package/compiler/compiler_test.go +17 -24
- package/compiler/composite-lit.go +32 -8
- package/compiler/decl.go +6 -6
- package/compiler/expr-call.go +170 -15
- package/compiler/expr-selector.go +100 -0
- package/compiler/expr.go +1 -1
- package/compiler/protobuf.go +557 -0
- package/compiler/spec-struct.go +4 -0
- package/compiler/spec-value.go +89 -10
- package/compiler/spec.go +254 -1
- package/compiler/stmt-assign.go +35 -0
- package/compiler/type-assert.go +87 -0
- package/compiler/type.go +4 -1
- package/dist/gs/builtin/builtin.d.ts +20 -1
- package/dist/gs/builtin/builtin.js +95 -4
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/slice.d.ts +1 -1
- package/dist/gs/builtin/slice.js +21 -2
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/errors/errors.d.ts +5 -6
- package/dist/gs/errors/errors.js.map +1 -1
- package/dist/gs/internal/oserror/errors.d.ts +6 -0
- package/dist/gs/internal/oserror/errors.js +7 -0
- package/dist/gs/internal/oserror/errors.js.map +1 -0
- package/dist/gs/internal/oserror/index.d.ts +1 -0
- package/dist/gs/internal/oserror/index.js +2 -0
- package/dist/gs/internal/oserror/index.js.map +1 -0
- package/dist/gs/io/fs/format.d.ts +3 -0
- package/dist/gs/io/fs/format.js +56 -0
- package/dist/gs/io/fs/format.js.map +1 -0
- package/dist/gs/io/fs/fs.d.ts +79 -0
- package/dist/gs/io/fs/fs.js +200 -0
- package/dist/gs/io/fs/fs.js.map +1 -0
- package/dist/gs/io/fs/glob.d.ts +10 -0
- package/dist/gs/io/fs/glob.js +141 -0
- package/dist/gs/io/fs/glob.js.map +1 -0
- package/dist/gs/io/fs/index.d.ts +8 -0
- package/dist/gs/io/fs/index.js +9 -0
- package/dist/gs/io/fs/index.js.map +1 -0
- package/dist/gs/io/fs/readdir.d.ts +7 -0
- package/dist/gs/io/fs/readdir.js +152 -0
- package/dist/gs/io/fs/readdir.js.map +1 -0
- package/dist/gs/io/fs/readfile.d.ts +6 -0
- package/dist/gs/io/fs/readfile.js +118 -0
- package/dist/gs/io/fs/readfile.js.map +1 -0
- package/dist/gs/io/fs/stat.d.ts +6 -0
- package/dist/gs/io/fs/stat.js +87 -0
- package/dist/gs/io/fs/stat.js.map +1 -0
- package/dist/gs/io/fs/sub.d.ts +6 -0
- package/dist/gs/io/fs/sub.js +172 -0
- package/dist/gs/io/fs/sub.js.map +1 -0
- package/dist/gs/io/fs/walk.d.ts +7 -0
- package/dist/gs/io/fs/walk.js +76 -0
- package/dist/gs/io/fs/walk.js.map +1 -0
- package/dist/gs/io/index.d.ts +1 -0
- package/dist/gs/io/index.js +2 -0
- package/dist/gs/io/index.js.map +1 -0
- package/dist/gs/io/io.d.ts +107 -0
- package/dist/gs/io/io.js +385 -0
- package/dist/gs/io/io.js.map +1 -0
- package/dist/gs/path/index.d.ts +2 -0
- package/dist/gs/path/index.js +3 -0
- package/dist/gs/path/index.js.map +1 -0
- package/dist/gs/path/match.d.ts +6 -0
- package/dist/gs/path/match.js +281 -0
- package/dist/gs/path/match.js.map +1 -0
- package/dist/gs/path/path.d.ts +7 -0
- package/dist/gs/path/path.js +256 -0
- package/dist/gs/path/path.js.map +1 -0
- package/dist/gs/strings/builder.d.ts +18 -0
- package/dist/gs/strings/builder.js +205 -0
- package/dist/gs/strings/builder.js.map +1 -0
- package/dist/gs/strings/clone.d.ts +1 -0
- package/dist/gs/strings/clone.js +16 -0
- package/dist/gs/strings/clone.js.map +1 -0
- package/dist/gs/strings/compare.d.ts +1 -0
- package/dist/gs/strings/compare.js +14 -0
- package/dist/gs/strings/compare.js.map +1 -0
- package/dist/gs/strings/index.d.ts +2 -0
- package/dist/gs/strings/index.js +3 -0
- package/dist/gs/strings/index.js.map +1 -0
- package/dist/gs/strings/iter.d.ts +8 -0
- package/dist/gs/strings/iter.js +160 -0
- package/dist/gs/strings/iter.js.map +1 -0
- package/dist/gs/strings/reader.d.ts +34 -0
- package/dist/gs/strings/reader.js +418 -0
- package/dist/gs/strings/reader.js.map +1 -0
- package/dist/gs/strings/replace.d.ts +106 -0
- package/dist/gs/strings/replace.js +1136 -0
- package/dist/gs/strings/replace.js.map +1 -0
- package/dist/gs/strings/search.d.ts +24 -0
- package/dist/gs/strings/search.js +169 -0
- package/dist/gs/strings/search.js.map +1 -0
- package/dist/gs/strings/strings.d.ts +47 -0
- package/dist/gs/strings/strings.js +418 -0
- package/dist/gs/strings/strings.js.map +1 -0
- package/dist/gs/stringslite/index.d.ts +1 -0
- package/dist/gs/stringslite/index.js +2 -0
- package/dist/gs/stringslite/index.js.map +1 -0
- package/dist/gs/stringslite/strings.d.ts +11 -0
- package/dist/gs/stringslite/strings.js +67 -0
- package/dist/gs/stringslite/strings.js.map +1 -0
- package/dist/gs/sync/index.d.ts +1 -0
- package/dist/gs/sync/index.js +2 -0
- package/dist/gs/sync/index.js.map +1 -0
- package/dist/gs/sync/sync.d.ts +79 -0
- package/dist/gs/sync/sync.js +392 -0
- package/dist/gs/sync/sync.js.map +1 -0
- package/dist/gs/time/time.d.ts +11 -2
- package/dist/gs/time/time.js +337 -12
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unicode/index.d.ts +1 -0
- package/dist/gs/unicode/index.js +2 -0
- package/dist/gs/unicode/index.js.map +1 -0
- package/dist/gs/unicode/unicode.d.ts +105 -0
- package/dist/gs/unicode/unicode.js +332 -0
- package/dist/gs/unicode/unicode.js.map +1 -0
- package/dist/gs/unicode/utf8/index.d.ts +1 -0
- package/dist/gs/unicode/utf8/index.js +3 -0
- package/dist/gs/unicode/utf8/index.js.map +1 -0
- package/dist/gs/unicode/utf8/utf8.d.ts +20 -0
- package/dist/gs/unicode/utf8/utf8.js +196 -0
- package/dist/gs/unicode/utf8/utf8.js.map +1 -0
- package/dist/gs/unsafe/index.d.ts +1 -0
- package/dist/gs/unsafe/index.js +2 -0
- package/dist/gs/unsafe/index.js.map +1 -0
- package/dist/gs/unsafe/unsafe.d.ts +11 -0
- package/dist/gs/unsafe/unsafe.js +44 -0
- package/dist/gs/unsafe/unsafe.js.map +1 -0
- package/go.mod +2 -1
- package/go.sum +6 -2
- package/gs/README.md +6 -0
- package/gs/builtin/builtin.ts +171 -0
- package/gs/builtin/channel.ts +683 -0
- package/gs/builtin/defer.ts +58 -0
- package/gs/builtin/index.ts +1 -0
- package/gs/builtin/io.ts +22 -0
- package/gs/builtin/map.ts +50 -0
- package/gs/builtin/slice.ts +1030 -0
- package/gs/builtin/type.ts +1106 -0
- package/gs/builtin/varRef.ts +25 -0
- package/gs/cmp/godoc.txt +8 -0
- package/gs/cmp/index.ts +29 -0
- package/gs/context/context.ts +401 -0
- package/gs/context/godoc.txt +69 -0
- package/gs/context/index.ts +1 -0
- package/gs/errors/errors.ts +223 -0
- package/gs/errors/godoc.txt +63 -0
- package/gs/errors/index.ts +1 -0
- package/gs/internal/goarch/godoc.txt +39 -0
- package/gs/internal/goarch/index.ts +18 -0
- package/gs/internal/oserror/errors.ts +14 -0
- package/gs/internal/oserror/index.ts +1 -0
- package/gs/io/fs/format.ts +65 -0
- package/gs/io/fs/fs.ts +359 -0
- package/gs/io/fs/glob.ts +167 -0
- package/gs/io/fs/godoc.txt +35 -0
- package/gs/io/fs/index.ts +8 -0
- package/gs/io/fs/readdir.ts +126 -0
- package/gs/io/fs/readfile.ts +77 -0
- package/gs/io/fs/stat.ts +38 -0
- package/gs/io/fs/sub.ts +208 -0
- package/gs/io/fs/walk.ts +89 -0
- package/gs/io/godoc.txt +61 -0
- package/gs/io/index.ts +1 -0
- package/gs/io/io.go +75 -0
- package/gs/io/io.ts +546 -0
- package/gs/iter/godoc.txt +203 -0
- package/gs/iter/index.ts +1 -0
- package/gs/iter/iter.ts +117 -0
- package/gs/math/bits/index.ts +356 -0
- package/gs/math/godoc.txt +76 -0
- package/gs/path/index.ts +2 -0
- package/gs/path/match.ts +307 -0
- package/gs/path/path.ts +301 -0
- package/gs/runtime/godoc.txt +331 -0
- package/gs/runtime/index.ts +1 -0
- package/gs/runtime/runtime.ts +178 -0
- package/gs/slices/godoc.txt +44 -0
- package/gs/slices/index.ts +1 -0
- package/gs/slices/slices.ts +22 -0
- package/gs/strings/builder.test.ts +121 -0
- package/gs/strings/builder.ts +223 -0
- package/gs/strings/clone.test.ts +43 -0
- package/gs/strings/clone.ts +17 -0
- package/gs/strings/compare.test.ts +84 -0
- package/gs/strings/compare.ts +13 -0
- package/gs/strings/godoc.txt +66 -0
- package/gs/strings/index.ts +2 -0
- package/gs/strings/iter.test.ts +343 -0
- package/gs/strings/iter.ts +171 -0
- package/gs/strings/reader.test.ts +242 -0
- package/gs/strings/reader.ts +451 -0
- package/gs/strings/replace.test.ts +181 -0
- package/gs/strings/replace.ts +1310 -0
- package/gs/strings/search.test.ts +214 -0
- package/gs/strings/search.ts +213 -0
- package/gs/strings/strings.test.ts +477 -0
- package/gs/strings/strings.ts +510 -0
- package/gs/stringslite/godoc.txt +17 -0
- package/gs/stringslite/index.ts +1 -0
- package/gs/stringslite/strings.ts +82 -0
- package/gs/sync/godoc.txt +21 -0
- package/gs/sync/index.ts +1 -0
- package/gs/sync/sync.go +64 -0
- package/gs/sync/sync.ts +449 -0
- package/gs/time/godoc.txt +116 -0
- package/gs/time/index.ts +1 -0
- package/gs/time/time.ts +585 -0
- package/gs/unicode/godoc.txt +52 -0
- package/gs/unicode/index.ts +1 -0
- package/gs/unicode/unicode.go +38 -0
- package/gs/unicode/unicode.ts +418 -0
- package/gs/unicode/utf8/godoc.txt +22 -0
- package/gs/unicode/utf8/index.ts +2 -0
- package/gs/unicode/utf8/utf8.ts +227 -0
- package/gs/unsafe/godoc.txt +19 -0
- package/gs/unsafe/index.ts +1 -0
- package/gs/unsafe/unsafe.test.ts +68 -0
- package/gs/unsafe/unsafe.ts +77 -0
- package/package.json +4 -3
package/compiler/compiler.go
CHANGED
|
@@ -10,6 +10,7 @@ import (
|
|
|
10
10
|
"os"
|
|
11
11
|
"path/filepath"
|
|
12
12
|
"slices"
|
|
13
|
+
"sort"
|
|
13
14
|
"strings"
|
|
14
15
|
|
|
15
16
|
gs "github.com/aperturerobotics/goscript"
|
|
@@ -145,6 +146,18 @@ func (c *Compiler) CompilePackages(ctx context.Context, patterns ...string) (*Co
|
|
|
145
146
|
|
|
146
147
|
// Visit all imports, including standard library packages
|
|
147
148
|
for _, imp := range pkg.Imports {
|
|
149
|
+
// Skip protobuf-go-lite packages and their dependencies
|
|
150
|
+
if isProtobufGoLitePackage(imp.PkgPath) {
|
|
151
|
+
c.le.Debugf("Skipping protobuf-go-lite package: %s", imp.PkgPath)
|
|
152
|
+
continue
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Skip packages that are only used by .pb.go files
|
|
156
|
+
if isPackageOnlyUsedByProtobufFiles(pkg, imp.PkgPath) {
|
|
157
|
+
c.le.Debugf("Skipping package only used by .pb.go files: %s", imp.PkgPath)
|
|
158
|
+
continue
|
|
159
|
+
}
|
|
160
|
+
|
|
148
161
|
visit(imp)
|
|
149
162
|
}
|
|
150
163
|
}
|
|
@@ -238,50 +251,6 @@ func (c *Compiler) CompilePackages(ctx context.Context, patterns ...string) (*Co
|
|
|
238
251
|
continue
|
|
239
252
|
}
|
|
240
253
|
|
|
241
|
-
// Check if this is the unsafe package, which is not supported in GoScript
|
|
242
|
-
if pkg.PkgPath == "unsafe" {
|
|
243
|
-
// Find which packages that would actually be compiled depend on unsafe
|
|
244
|
-
var dependentPackages []string
|
|
245
|
-
for _, otherPkg := range pkgs {
|
|
246
|
-
if otherPkg.PkgPath != "unsafe" {
|
|
247
|
-
// Check if this package would actually be compiled (same logic as above)
|
|
248
|
-
wouldBeCompiled := true
|
|
249
|
-
|
|
250
|
-
// If the package was not explicitly requested, check if it has a handwritten equivalent
|
|
251
|
-
if !slices.Contains(patternPkgPaths, otherPkg.PkgPath) {
|
|
252
|
-
gsSourcePath := "gs/" + otherPkg.PkgPath
|
|
253
|
-
_, gsErr := gs.GsOverrides.ReadDir(gsSourcePath)
|
|
254
|
-
if gsErr == nil {
|
|
255
|
-
// Package has handwritten equivalent, so it wouldn't be compiled
|
|
256
|
-
wouldBeCompiled = false
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Skip packages that failed to load
|
|
261
|
-
if len(otherPkg.Errors) > 0 {
|
|
262
|
-
wouldBeCompiled = false
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// Only include packages that would actually be compiled and import unsafe
|
|
266
|
-
if wouldBeCompiled {
|
|
267
|
-
for importPath := range otherPkg.Imports {
|
|
268
|
-
if importPath == "unsafe" {
|
|
269
|
-
dependentPackages = append(dependentPackages, otherPkg.PkgPath)
|
|
270
|
-
break
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
dependentList := "unknown package"
|
|
278
|
-
if len(dependentPackages) > 0 {
|
|
279
|
-
dependentList = strings.Join(dependentPackages, ", ")
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
return nil, fmt.Errorf("cannot compile package 'unsafe': GoScript does not support the unsafe package due to its low-level memory operations that are incompatible with TypeScript/JavaScript. This package is required by: %s. Consider using alternative approaches that don't require unsafe operations", dependentList)
|
|
283
|
-
}
|
|
284
|
-
|
|
285
254
|
pkgCompiler, err := NewPackageCompiler(c.le, &c.config, pkg)
|
|
286
255
|
if err != nil {
|
|
287
256
|
return nil, fmt.Errorf("failed to create package compiler for %s: %w", pkg.PkgPath, err)
|
|
@@ -346,6 +315,9 @@ func (c *PackageCompiler) Compile(ctx context.Context) error {
|
|
|
346
315
|
}
|
|
347
316
|
}
|
|
348
317
|
|
|
318
|
+
// Perform package-level analysis for auto-imports
|
|
319
|
+
packageAnalysis := AnalyzePackage(c.pkg)
|
|
320
|
+
|
|
349
321
|
// Track all compiled files for later generating the index.ts
|
|
350
322
|
compiledFiles := make([]string, 0, len(c.pkg.CompiledGoFiles))
|
|
351
323
|
|
|
@@ -357,13 +329,35 @@ func (c *PackageCompiler) Compile(ctx context.Context) error {
|
|
|
357
329
|
return err
|
|
358
330
|
}
|
|
359
331
|
|
|
332
|
+
// Check if this is a .pb.go file that should be skipped
|
|
333
|
+
baseFileName := filepath.Base(fileName)
|
|
334
|
+
if strings.HasSuffix(baseFileName, ".pb.go") {
|
|
335
|
+
// Check if there's a corresponding .pb.ts file
|
|
336
|
+
pbTsFileName := strings.TrimSuffix(baseFileName, ".pb.go") + ".pb.ts"
|
|
337
|
+
packageDir := filepath.Dir(fileName)
|
|
338
|
+
pbTsPath := filepath.Join(packageDir, pbTsFileName)
|
|
339
|
+
|
|
340
|
+
if _, err := os.Stat(pbTsPath); err == nil {
|
|
341
|
+
// .pb.ts file exists, copy it instead of transpiling .pb.go
|
|
342
|
+
c.le.WithField("file", relWdFileName).Debug("found .pb.ts file, copying instead of transpiling .pb.go")
|
|
343
|
+
|
|
344
|
+
if err := c.copyProtobufTSFile(pbTsPath, pbTsFileName); err != nil {
|
|
345
|
+
return fmt.Errorf("failed to copy protobuf .pb.ts file: %w", err)
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Add the .pb file to our compiled files list for index generation
|
|
349
|
+
pbFileName := strings.TrimSuffix(baseFileName, ".pb.go") + ".pb"
|
|
350
|
+
compiledFiles = append(compiledFiles, pbFileName)
|
|
351
|
+
continue // Skip transpiling this .pb.go file
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
360
355
|
c.le.WithField("file", relWdFileName).Debug("compiling file")
|
|
361
|
-
if err := c.CompileFile(ctx, fileName, f); err != nil {
|
|
356
|
+
if err := c.CompileFile(ctx, fileName, f, packageAnalysis); err != nil {
|
|
362
357
|
return err
|
|
363
358
|
}
|
|
364
359
|
|
|
365
360
|
// Add the base filename to our list for the index.ts generation
|
|
366
|
-
baseFileName := filepath.Base(fileName)
|
|
367
361
|
// Strip .go extension and add .gs
|
|
368
362
|
gsFileName := strings.TrimSuffix(baseFileName, ".go") + ".gs"
|
|
369
363
|
compiledFiles = append(compiledFiles, gsFileName)
|
|
@@ -378,8 +372,9 @@ func (c *PackageCompiler) Compile(ctx context.Context) error {
|
|
|
378
372
|
}
|
|
379
373
|
|
|
380
374
|
// generateIndexFile creates an index.ts file in the package output directory
|
|
381
|
-
// that re-exports
|
|
382
|
-
// This ensures the package can be imported correctly by TypeScript modules
|
|
375
|
+
// that re-exports only Go-exported symbols from the compiled TypeScript files.
|
|
376
|
+
// This ensures the package can be imported correctly by TypeScript modules
|
|
377
|
+
// while maintaining proper Go package boundaries.
|
|
383
378
|
func (c *PackageCompiler) generateIndexFile(compiledFiles []string) error {
|
|
384
379
|
indexFilePath := filepath.Join(c.outputPath, "index.ts")
|
|
385
380
|
|
|
@@ -390,12 +385,128 @@ func (c *PackageCompiler) generateIndexFile(compiledFiles []string) error {
|
|
|
390
385
|
}
|
|
391
386
|
defer indexFile.Close() //nolint:errcheck
|
|
392
387
|
|
|
393
|
-
//
|
|
388
|
+
// Collect exported symbols from all files in the package
|
|
389
|
+
var exportedSymbols []string
|
|
390
|
+
|
|
391
|
+
// Iterate through all syntax files to find exported symbols
|
|
392
|
+
for i, syntax := range c.pkg.Syntax {
|
|
393
|
+
fileName := c.pkg.CompiledGoFiles[i]
|
|
394
|
+
baseFileName := filepath.Base(fileName)
|
|
395
|
+
gsFileName := strings.TrimSuffix(baseFileName, ".go") + ".gs"
|
|
396
|
+
|
|
397
|
+
// Only include this file if it was compiled (in our compiledFiles list)
|
|
398
|
+
fileWasCompiled := false
|
|
399
|
+
for _, compiledFile := range compiledFiles {
|
|
400
|
+
if compiledFile == gsFileName {
|
|
401
|
+
fileWasCompiled = true
|
|
402
|
+
break
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
if !fileWasCompiled {
|
|
406
|
+
continue
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Analyze declarations in this file to find exported symbols
|
|
410
|
+
for _, decl := range syntax.Decls {
|
|
411
|
+
switch d := decl.(type) {
|
|
412
|
+
case *ast.FuncDecl:
|
|
413
|
+
// Only include top-level functions (not methods)
|
|
414
|
+
if d.Recv == nil && d.Name.IsExported() {
|
|
415
|
+
exportedSymbols = append(exportedSymbols, d.Name.Name)
|
|
416
|
+
}
|
|
417
|
+
case *ast.GenDecl:
|
|
418
|
+
for _, spec := range d.Specs {
|
|
419
|
+
switch s := spec.(type) {
|
|
420
|
+
case *ast.TypeSpec:
|
|
421
|
+
if s.Name.IsExported() {
|
|
422
|
+
exportedSymbols = append(exportedSymbols, s.Name.Name)
|
|
423
|
+
}
|
|
424
|
+
case *ast.ValueSpec:
|
|
425
|
+
for _, name := range s.Names {
|
|
426
|
+
if name.IsExported() {
|
|
427
|
+
exportedSymbols = append(exportedSymbols, name.Name)
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Remove duplicates and sort
|
|
437
|
+
symbolMap := make(map[string]bool)
|
|
438
|
+
for _, symbol := range exportedSymbols {
|
|
439
|
+
symbolMap[symbol] = true
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
var uniqueSymbols []string
|
|
443
|
+
for symbol := range symbolMap {
|
|
444
|
+
uniqueSymbols = append(uniqueSymbols, symbol)
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Sort for consistent output
|
|
448
|
+
sort.Strings(uniqueSymbols)
|
|
449
|
+
|
|
450
|
+
// Write selective re-exports for each compiled file
|
|
394
451
|
for _, fileName := range compiledFiles {
|
|
395
|
-
//
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
452
|
+
// Check if this is a protobuf file
|
|
453
|
+
if strings.HasSuffix(fileName, ".pb") {
|
|
454
|
+
// For protobuf files, add a simple re-export
|
|
455
|
+
pbTsFileName := fileName + ".ts"
|
|
456
|
+
if err := c.writeProtobufExports(indexFile, fileName, pbTsFileName); err != nil {
|
|
457
|
+
return err
|
|
458
|
+
}
|
|
459
|
+
continue
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// Find which symbols this file exports
|
|
463
|
+
var fileSymbols []string
|
|
464
|
+
|
|
465
|
+
// Find the corresponding syntax file
|
|
466
|
+
for i, syntax := range c.pkg.Syntax {
|
|
467
|
+
syntaxFileName := c.pkg.CompiledGoFiles[i]
|
|
468
|
+
syntaxBaseFileName := filepath.Base(syntaxFileName)
|
|
469
|
+
syntaxGsFileName := strings.TrimSuffix(syntaxBaseFileName, ".go") + ".gs"
|
|
470
|
+
|
|
471
|
+
if syntaxGsFileName != fileName {
|
|
472
|
+
continue
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Collect exported symbols from this specific file
|
|
476
|
+
for _, decl := range syntax.Decls {
|
|
477
|
+
switch d := decl.(type) {
|
|
478
|
+
case *ast.FuncDecl:
|
|
479
|
+
if d.Recv == nil && d.Name.IsExported() {
|
|
480
|
+
fileSymbols = append(fileSymbols, d.Name.Name)
|
|
481
|
+
}
|
|
482
|
+
case *ast.GenDecl:
|
|
483
|
+
for _, spec := range d.Specs {
|
|
484
|
+
switch s := spec.(type) {
|
|
485
|
+
case *ast.TypeSpec:
|
|
486
|
+
if s.Name.IsExported() {
|
|
487
|
+
fileSymbols = append(fileSymbols, s.Name.Name)
|
|
488
|
+
}
|
|
489
|
+
case *ast.ValueSpec:
|
|
490
|
+
for _, name := range s.Names {
|
|
491
|
+
if name.IsExported() {
|
|
492
|
+
fileSymbols = append(fileSymbols, name.Name)
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
break
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// Write selective export if this file has exported symbols
|
|
503
|
+
if len(fileSymbols) > 0 {
|
|
504
|
+
sort.Strings(fileSymbols)
|
|
505
|
+
exportLine := fmt.Sprintf("export { %s } from \"./%s.js\"\n",
|
|
506
|
+
strings.Join(fileSymbols, ", "), fileName)
|
|
507
|
+
if _, err := indexFile.WriteString(exportLine); err != nil {
|
|
508
|
+
return err
|
|
509
|
+
}
|
|
399
510
|
}
|
|
400
511
|
}
|
|
401
512
|
|
|
@@ -408,7 +519,7 @@ func (c *PackageCompiler) generateIndexFile(compiledFiles []string) error {
|
|
|
408
519
|
// about varRefing, async functions, defer statements).
|
|
409
520
|
// Then, it creates a `FileCompiler` instance for the file and invokes its
|
|
410
521
|
// `Compile` method to generate the TypeScript code.
|
|
411
|
-
func (p *PackageCompiler) CompileFile(ctx context.Context, name string, syntax *ast.File) error {
|
|
522
|
+
func (p *PackageCompiler) CompileFile(ctx context.Context, name string, syntax *ast.File, packageAnalysis *PackageAnalysis) error {
|
|
412
523
|
// Create a new analysis instance for per-file data
|
|
413
524
|
analysis := NewAnalysis()
|
|
414
525
|
|
|
@@ -418,7 +529,7 @@ func (p *PackageCompiler) CompileFile(ctx context.Context, name string, syntax *
|
|
|
418
529
|
// Analyze the file before compiling
|
|
419
530
|
AnalyzeFile(syntax, p.pkg, analysis, cmap)
|
|
420
531
|
|
|
421
|
-
fileCompiler, err := NewFileCompiler(p.compilerConf, p.pkg, syntax, name, analysis)
|
|
532
|
+
fileCompiler, err := NewFileCompiler(p.compilerConf, p.pkg, syntax, name, analysis, packageAnalysis)
|
|
422
533
|
if err != nil {
|
|
423
534
|
return err
|
|
424
535
|
}
|
|
@@ -430,12 +541,13 @@ func (p *PackageCompiler) CompileFile(ctx context.Context, name string, syntax *
|
|
|
430
541
|
// initializes the `TSCodeWriter` for TypeScript code generation, and uses a
|
|
431
542
|
// `GoToTSCompiler` to translate Go declarations and statements.
|
|
432
543
|
type FileCompiler struct {
|
|
433
|
-
compilerConfig
|
|
434
|
-
codeWriter
|
|
435
|
-
pkg
|
|
436
|
-
ast
|
|
437
|
-
fullPath
|
|
438
|
-
Analysis
|
|
544
|
+
compilerConfig *Config
|
|
545
|
+
codeWriter *TSCodeWriter
|
|
546
|
+
pkg *packages.Package
|
|
547
|
+
ast *ast.File
|
|
548
|
+
fullPath string
|
|
549
|
+
Analysis *Analysis
|
|
550
|
+
PackageAnalysis *PackageAnalysis
|
|
439
551
|
}
|
|
440
552
|
|
|
441
553
|
// NewFileCompiler creates a new `FileCompiler` for a specific Go file.
|
|
@@ -448,13 +560,15 @@ func NewFileCompiler(
|
|
|
448
560
|
astFile *ast.File,
|
|
449
561
|
fullPath string,
|
|
450
562
|
analysis *Analysis,
|
|
563
|
+
packageAnalysis *PackageAnalysis,
|
|
451
564
|
) (*FileCompiler, error) {
|
|
452
565
|
return &FileCompiler{
|
|
453
|
-
compilerConfig:
|
|
454
|
-
pkg:
|
|
455
|
-
ast:
|
|
456
|
-
fullPath:
|
|
457
|
-
Analysis:
|
|
566
|
+
compilerConfig: compilerConf,
|
|
567
|
+
pkg: pkg,
|
|
568
|
+
ast: astFile,
|
|
569
|
+
fullPath: fullPath,
|
|
570
|
+
Analysis: analysis,
|
|
571
|
+
PackageAnalysis: packageAnalysis,
|
|
458
572
|
}, nil
|
|
459
573
|
}
|
|
460
574
|
|
|
@@ -488,7 +602,26 @@ func (c *FileCompiler) Compile(ctx context.Context) error {
|
|
|
488
602
|
|
|
489
603
|
// Add import for the goscript runtime using namespace import and alias
|
|
490
604
|
c.codeWriter.WriteLinef("import * as $ from %q;", "@goscript/builtin/builtin.js")
|
|
491
|
-
|
|
605
|
+
|
|
606
|
+
// Check if there are any .pb.go files in this package and add imports for them
|
|
607
|
+
if err := c.addProtobufImports(); err != nil {
|
|
608
|
+
return fmt.Errorf("failed to add protobuf imports: %w", err)
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// Generate auto-imports for functions from other files in the same package
|
|
612
|
+
currentFileName := strings.TrimSuffix(filepath.Base(c.fullPath), ".go")
|
|
613
|
+
if imports := c.PackageAnalysis.FunctionCalls[currentFileName]; imports != nil {
|
|
614
|
+
for sourceFile, functions := range imports {
|
|
615
|
+
if len(functions) > 0 {
|
|
616
|
+
// Sort functions for consistent output
|
|
617
|
+
sort.Strings(functions)
|
|
618
|
+
c.codeWriter.WriteLinef("import { %s } from \"./%s.gs.js\";",
|
|
619
|
+
strings.Join(functions, ", "), sourceFile)
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
c.codeWriter.WriteLine("") // Add a newline after imports
|
|
492
625
|
|
|
493
626
|
if err := goWriter.WriteDecls(f.Decls); err != nil {
|
|
494
627
|
return fmt.Errorf("failed to write declarations: %w", err)
|
|
@@ -503,7 +636,6 @@ func (c *FileCompiler) Compile(ctx context.Context) error {
|
|
|
503
636
|
// decisions about code generation (e.g., varRefing, async behavior).
|
|
504
637
|
type GoToTSCompiler struct {
|
|
505
638
|
tsw *TSCodeWriter
|
|
506
|
-
|
|
507
639
|
pkg *packages.Package
|
|
508
640
|
|
|
509
641
|
analysis *Analysis
|
|
@@ -141,7 +141,7 @@ func getParentGoModulePath() (string, error) {
|
|
|
141
141
|
return strings.TrimSpace(string(output)), nil
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
func
|
|
144
|
+
func TestUnsafePackageCompilation(t *testing.T) {
|
|
145
145
|
// Create a temporary directory for the test output
|
|
146
146
|
tempDir, err := os.MkdirTemp("", "goscript-test-unsafe")
|
|
147
147
|
if err != nil {
|
|
@@ -154,11 +154,11 @@ func TestUnsafePackageErrorMessage(t *testing.T) {
|
|
|
154
154
|
log.SetLevel(logrus.DebugLevel)
|
|
155
155
|
le := logrus.NewEntry(log)
|
|
156
156
|
|
|
157
|
-
// Test with AllDependencies=true to ensure
|
|
157
|
+
// Test with AllDependencies=true and DisableEmitBuiltin=false to ensure handwritten packages are copied
|
|
158
158
|
config := &compiler.Config{
|
|
159
159
|
OutputPath: tempDir,
|
|
160
160
|
AllDependencies: true,
|
|
161
|
-
DisableEmitBuiltin:
|
|
161
|
+
DisableEmitBuiltin: false, // This ensures handwritten packages are copied to output
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
comp, err := compiler.NewCompiler(config, le, nil)
|
|
@@ -168,32 +168,25 @@ func TestUnsafePackageErrorMessage(t *testing.T) {
|
|
|
168
168
|
|
|
169
169
|
// Try to compile a package that has dependencies that import unsafe
|
|
170
170
|
// We'll use "sync/atomic" which imports unsafe but doesn't have a handwritten equivalent
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
t.Fatalf("Expected compilation to fail due to unsafe package, but it succeeded")
|
|
171
|
+
result, err := comp.CompilePackages(context.Background(), "sync/atomic")
|
|
172
|
+
// This should now succeed since we have a handwritten unsafe package
|
|
173
|
+
if err != nil {
|
|
174
|
+
t.Fatalf("Expected compilation to succeed with handwritten unsafe package, but it failed: %v", err)
|
|
176
175
|
}
|
|
177
176
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if !strings.Contains(errorMsg, "cannot compile package 'unsafe'") {
|
|
182
|
-
t.Errorf("Error message should mention unsafe package, got: %s", errorMsg)
|
|
177
|
+
// Verify that the unsafe package was copied (not compiled) since it has a handwritten equivalent
|
|
178
|
+
if !slices.Contains(result.CopiedPackages, "unsafe") {
|
|
179
|
+
t.Errorf("Expected unsafe package to be in CopiedPackages, but it wasn't. CopiedPackages: %v", result.CopiedPackages)
|
|
183
180
|
}
|
|
184
181
|
|
|
185
|
-
// Verify that
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
for _, pkg := range handwrittenPackages {
|
|
190
|
-
if strings.Contains(errorMsg, pkg) {
|
|
191
|
-
t.Errorf("Error message should not mention handwritten package '%s', but it does. Error: %s", pkg, errorMsg)
|
|
192
|
-
}
|
|
182
|
+
// Verify that sync/atomic was compiled
|
|
183
|
+
if !slices.Contains(result.CompiledPackages, "sync/atomic") {
|
|
184
|
+
t.Errorf("Expected sync/atomic package to be in CompiledPackages, but it wasn't. CompiledPackages: %v", result.CompiledPackages)
|
|
193
185
|
}
|
|
194
186
|
|
|
195
|
-
//
|
|
196
|
-
|
|
197
|
-
|
|
187
|
+
// Check that the unsafe package directory exists in the output
|
|
188
|
+
unsafePath := filepath.Join(tempDir, "@goscript/unsafe")
|
|
189
|
+
if _, err := os.Stat(unsafePath); os.IsNotExist(err) {
|
|
190
|
+
t.Errorf("unsafe package directory was not created at %s", unsafePath)
|
|
198
191
|
}
|
|
199
192
|
}
|
|
@@ -199,18 +199,34 @@ func (c *GoToTSCompiler) WriteCompositeLit(exp *ast.CompositeLit) error {
|
|
|
199
199
|
if underlyingStruct, ok := namedType.Underlying().(*types.Struct); ok {
|
|
200
200
|
structType = underlyingStruct
|
|
201
201
|
isStructLiteral = true
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
c.
|
|
202
|
+
|
|
203
|
+
// Check if this is a protobuf type
|
|
204
|
+
if handled, err := c.writeProtobufCompositeLit(exp, litType); handled {
|
|
205
|
+
if err != nil {
|
|
206
|
+
return err
|
|
207
|
+
}
|
|
208
|
+
} else {
|
|
209
|
+
// Named struct, use constructor
|
|
210
|
+
c.tsw.WriteLiterally("new ")
|
|
211
|
+
c.WriteTypeExpr(exp.Type)
|
|
212
|
+
}
|
|
205
213
|
}
|
|
206
214
|
} else if ptrType, ok := litType.(*types.Pointer); ok {
|
|
207
215
|
if namedElem, ok := ptrType.Elem().(*types.Named); ok {
|
|
208
216
|
if underlyingStruct, ok := namedElem.Underlying().(*types.Struct); ok {
|
|
209
217
|
structType = underlyingStruct
|
|
210
218
|
isStructLiteral = true // Treat pointer-to-struct literal similarly
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
c.
|
|
219
|
+
|
|
220
|
+
// Check if this is a protobuf type
|
|
221
|
+
if handled, err := c.writeProtobufCompositeLit(exp, litType); handled {
|
|
222
|
+
if err != nil {
|
|
223
|
+
return err
|
|
224
|
+
}
|
|
225
|
+
} else {
|
|
226
|
+
// Named struct pointer, use constructor
|
|
227
|
+
c.tsw.WriteLiterally("new ")
|
|
228
|
+
c.WriteTypeExpr(exp.Type)
|
|
229
|
+
}
|
|
214
230
|
}
|
|
215
231
|
}
|
|
216
232
|
} else if underlyingStruct, ok := litType.Underlying().(*types.Struct); ok {
|
|
@@ -339,7 +355,11 @@ func (c *GoToTSCompiler) WriteCompositeLit(exp *ast.CompositeLit) error {
|
|
|
339
355
|
if firstFieldWritten {
|
|
340
356
|
c.tsw.WriteLiterally(", ")
|
|
341
357
|
}
|
|
342
|
-
|
|
358
|
+
|
|
359
|
+
// Convert field name for protobuf types
|
|
360
|
+
fieldName := c.convertProtobufFieldNameInLiteral(keyName, litType)
|
|
361
|
+
|
|
362
|
+
c.tsw.WriteLiterally(fieldName)
|
|
343
363
|
c.tsw.WriteLiterally(": ")
|
|
344
364
|
if err := c.WriteVarRefedValue(directFields[keyName]); err != nil {
|
|
345
365
|
return err
|
|
@@ -538,7 +558,11 @@ func (c *GoToTSCompiler) writeUntypedStructLiteral(exp *ast.CompositeLit, struct
|
|
|
538
558
|
if firstFieldWritten {
|
|
539
559
|
c.tsw.WriteLiterally(", ")
|
|
540
560
|
}
|
|
541
|
-
|
|
561
|
+
|
|
562
|
+
// Convert field name for protobuf types
|
|
563
|
+
fieldName := c.convertProtobufFieldNameInLiteral(keyName, structType.Underlying())
|
|
564
|
+
|
|
565
|
+
c.tsw.WriteLiterally(fieldName)
|
|
542
566
|
c.tsw.WriteLiterally(": ")
|
|
543
567
|
if err := c.WriteVarRefedValue(directFields[keyName]); err != nil {
|
|
544
568
|
return err
|
package/compiler/decl.go
CHANGED
|
@@ -68,11 +68,9 @@ func (c *GoToTSCompiler) WriteFuncDeclAsFunction(decl *ast.FuncDecl) error {
|
|
|
68
68
|
c.WriteDoc(decl.Doc)
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
c.tsw.WriteLiterally("export ")
|
|
75
|
-
}
|
|
71
|
+
// Export all functions for intra-package visibility
|
|
72
|
+
// This allows other files in the same package to import functions
|
|
73
|
+
c.tsw.WriteLiterally("export ")
|
|
76
74
|
|
|
77
75
|
// Check if this function is async using the analysis data
|
|
78
76
|
var isAsync bool
|
|
@@ -233,7 +231,9 @@ func (c *GoToTSCompiler) WriteFuncDeclAsMethod(decl *ast.FuncDecl) error {
|
|
|
233
231
|
if recvName != "_" {
|
|
234
232
|
c.tsw.WriteLine("{")
|
|
235
233
|
c.tsw.Indent(1)
|
|
236
|
-
|
|
234
|
+
// Sanitize the receiver name to avoid conflicts with TypeScript reserved words
|
|
235
|
+
sanitizedRecvName := c.sanitizeIdentifier(recvName)
|
|
236
|
+
c.tsw.WriteLinef("const %s = this", sanitizedRecvName)
|
|
237
237
|
|
|
238
238
|
// Add using statement if needed
|
|
239
239
|
if c.analysis.NeedsDefer(decl.Body) {
|