goscript 0.0.23 → 0.0.25
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 +2 -2
- package/cmd/goscript/cmd_compile.go +18 -2
- package/compiler/analysis.go +74 -132
- package/compiler/analysis_test.go +220 -0
- package/compiler/assignment.go +37 -43
- package/compiler/builtin_test.go +90 -0
- package/compiler/compiler.go +307 -22
- package/compiler/composite-lit.go +108 -43
- package/compiler/config.go +7 -3
- package/compiler/config_test.go +6 -33
- package/compiler/decl.go +7 -1
- package/compiler/expr-call.go +212 -2
- package/compiler/expr-selector.go +66 -41
- package/compiler/expr-star.go +57 -65
- package/compiler/expr-type.go +1 -1
- package/compiler/expr-value.go +1 -1
- package/compiler/expr.go +125 -20
- package/compiler/field.go +4 -4
- package/compiler/primitive.go +11 -10
- package/compiler/spec-struct.go +3 -3
- package/compiler/spec-value.go +75 -29
- package/compiler/spec.go +9 -3
- package/compiler/stmt-assign.go +36 -2
- package/compiler/stmt-for.go +11 -0
- package/compiler/stmt-range.go +314 -1
- package/compiler/stmt.go +52 -0
- package/compiler/type.go +83 -15
- package/dist/gs/builtin/builtin.d.ts +9 -0
- package/dist/gs/builtin/builtin.js +46 -0
- package/dist/gs/builtin/builtin.js.map +1 -0
- package/dist/gs/builtin/channel.d.ts +193 -0
- package/dist/gs/builtin/channel.js +471 -0
- package/dist/gs/builtin/channel.js.map +1 -0
- package/dist/gs/builtin/defer.d.ts +38 -0
- package/dist/gs/builtin/defer.js +54 -0
- package/dist/gs/builtin/defer.js.map +1 -0
- package/dist/gs/builtin/index.d.ts +1 -0
- package/dist/gs/builtin/index.js +2 -0
- package/dist/gs/builtin/index.js.map +1 -0
- package/dist/gs/builtin/io.d.ts +16 -0
- package/dist/gs/builtin/io.js +15 -0
- package/dist/gs/builtin/io.js.map +1 -0
- package/dist/gs/builtin/map.d.ts +33 -0
- package/dist/gs/builtin/map.js +44 -0
- package/dist/gs/builtin/map.js.map +1 -0
- package/dist/gs/builtin/slice.d.ts +173 -0
- package/dist/gs/builtin/slice.js +799 -0
- package/dist/gs/builtin/slice.js.map +1 -0
- package/dist/gs/builtin/type.d.ts +203 -0
- package/dist/gs/builtin/type.js +744 -0
- package/dist/gs/builtin/type.js.map +1 -0
- package/dist/gs/builtin/varRef.d.ts +14 -0
- package/dist/gs/builtin/varRef.js +14 -0
- package/dist/gs/builtin/varRef.js.map +1 -0
- package/dist/gs/cmp/index.d.ts +4 -0
- package/dist/gs/cmp/index.js +27 -0
- package/dist/gs/cmp/index.js.map +1 -0
- package/dist/gs/context/context.d.ts +26 -0
- package/dist/gs/context/context.js +305 -0
- package/dist/gs/context/context.js.map +1 -0
- package/dist/gs/context/index.d.ts +1 -0
- package/dist/gs/context/index.js +2 -0
- package/dist/gs/context/index.js.map +1 -0
- package/dist/gs/internal/goarch/index.d.ts +6 -0
- package/dist/gs/internal/goarch/index.js +14 -0
- package/dist/gs/internal/goarch/index.js.map +1 -0
- package/dist/gs/iter/index.d.ts +1 -0
- package/dist/gs/iter/index.js +2 -0
- package/dist/gs/iter/index.js.map +1 -0
- package/dist/gs/iter/iter.d.ts +4 -0
- package/dist/gs/iter/iter.js +91 -0
- package/dist/gs/iter/iter.js.map +1 -0
- package/dist/gs/math/bits/index.d.ts +47 -0
- package/dist/gs/math/bits/index.js +298 -0
- package/dist/gs/math/bits/index.js.map +1 -0
- package/dist/gs/runtime/index.d.ts +1 -0
- package/dist/gs/runtime/index.js +2 -0
- package/dist/gs/runtime/index.js.map +1 -0
- package/dist/gs/runtime/runtime.d.ts +41 -0
- package/dist/gs/runtime/runtime.js +158 -0
- package/dist/gs/runtime/runtime.js.map +1 -0
- package/dist/gs/slices/index.d.ts +1 -0
- package/dist/gs/slices/index.js +2 -0
- package/dist/gs/slices/index.js.map +1 -0
- package/dist/gs/slices/slices.d.ts +8 -0
- package/dist/gs/slices/slices.js +20 -0
- package/dist/gs/slices/slices.js.map +1 -0
- package/dist/gs/time/index.d.ts +1 -0
- package/dist/gs/time/index.js +2 -0
- package/dist/gs/time/index.js.map +1 -0
- package/dist/gs/time/time.d.ts +57 -0
- package/dist/gs/time/time.js +208 -0
- package/dist/gs/time/time.js.map +1 -0
- package/package.json +3 -2
package/compiler/compiler.go
CHANGED
|
@@ -11,6 +11,8 @@ import (
|
|
|
11
11
|
"slices"
|
|
12
12
|
"strings"
|
|
13
13
|
|
|
14
|
+
"go/constant"
|
|
15
|
+
|
|
14
16
|
gs "github.com/aperturerobotics/goscript"
|
|
15
17
|
"github.com/sirupsen/logrus"
|
|
16
18
|
"golang.org/x/tools/go/packages"
|
|
@@ -72,6 +74,16 @@ func NewCompiler(conf *Config, le *logrus.Entry, opts *packages.Config) (*Compil
|
|
|
72
74
|
return &Compiler{config: *conf, le: le, opts: *opts}, nil
|
|
73
75
|
}
|
|
74
76
|
|
|
77
|
+
// CompilationResult contains information about what was compiled
|
|
78
|
+
type CompilationResult struct {
|
|
79
|
+
// CompiledPackages contains the package paths of all packages that were actually compiled to TypeScript
|
|
80
|
+
CompiledPackages []string
|
|
81
|
+
// CopiedPackages contains the package paths of all packages that were copied from handwritten sources
|
|
82
|
+
CopiedPackages []string
|
|
83
|
+
// OriginalPackages contains the package paths that were explicitly requested for compilation
|
|
84
|
+
OriginalPackages []string
|
|
85
|
+
}
|
|
86
|
+
|
|
75
87
|
// CompilePackages loads Go packages based on the provided patterns and
|
|
76
88
|
// then compiles each loaded package into TypeScript. It uses the context for
|
|
77
89
|
// cancellation and applies the compiler's configured options during package loading.
|
|
@@ -79,7 +91,8 @@ func NewCompiler(conf *Config, le *logrus.Entry, opts *packages.Config) (*Compil
|
|
|
79
91
|
// invokes its `Compile` method.
|
|
80
92
|
// If c.config.AllDependencies is true, it will also compile all dependencies
|
|
81
93
|
// of the requested packages, including standard library dependencies.
|
|
82
|
-
|
|
94
|
+
// Returns a CompilationResult with information about what was compiled.
|
|
95
|
+
func (c *Compiler) CompilePackages(ctx context.Context, patterns ...string) (*CompilationResult, error) {
|
|
83
96
|
opts := c.opts
|
|
84
97
|
opts.Context = ctx
|
|
85
98
|
|
|
@@ -87,7 +100,7 @@ func (c *Compiler) CompilePackages(ctx context.Context, patterns ...string) erro
|
|
|
87
100
|
opts.Mode |= packages.NeedImports
|
|
88
101
|
pkgs, err := packages.Load(&opts, patterns...)
|
|
89
102
|
if err != nil {
|
|
90
|
-
return fmt.Errorf("failed to load packages: %w", err)
|
|
103
|
+
return nil, fmt.Errorf("failed to load packages: %w", err)
|
|
91
104
|
}
|
|
92
105
|
|
|
93
106
|
// build a list of packages that patterns matched
|
|
@@ -96,12 +109,23 @@ func (c *Compiler) CompilePackages(ctx context.Context, patterns ...string) erro
|
|
|
96
109
|
patternPkgPaths = append(patternPkgPaths, pkg.PkgPath)
|
|
97
110
|
}
|
|
98
111
|
|
|
112
|
+
result := &CompilationResult{
|
|
113
|
+
OriginalPackages: patternPkgPaths,
|
|
114
|
+
}
|
|
115
|
+
|
|
99
116
|
// If AllDependencies is true, we need to collect all dependencies
|
|
100
117
|
if c.config.AllDependencies {
|
|
101
118
|
// Create a set to track processed packages by their ID
|
|
102
119
|
processed := make(map[string]bool)
|
|
103
120
|
var allPkgs []*packages.Package
|
|
104
121
|
|
|
122
|
+
// Helper function to check if a package has a handwritten equivalent
|
|
123
|
+
hasHandwrittenEquivalent := func(pkgPath string) bool {
|
|
124
|
+
gsSourcePath := "gs/" + pkgPath
|
|
125
|
+
_, gsErr := gs.GsOverrides.ReadDir(gsSourcePath)
|
|
126
|
+
return gsErr == nil
|
|
127
|
+
}
|
|
128
|
+
|
|
105
129
|
// Visit all packages and their dependencies
|
|
106
130
|
var visit func(pkg *packages.Package)
|
|
107
131
|
visit = func(pkg *packages.Package) {
|
|
@@ -109,8 +133,17 @@ func (c *Compiler) CompilePackages(ctx context.Context, patterns ...string) erro
|
|
|
109
133
|
return
|
|
110
134
|
}
|
|
111
135
|
processed[pkg.ID] = true
|
|
136
|
+
|
|
137
|
+
// Add this package to the list of all packages
|
|
112
138
|
allPkgs = append(allPkgs, pkg)
|
|
113
139
|
|
|
140
|
+
// Check if this package has a handwritten equivalent
|
|
141
|
+
if hasHandwrittenEquivalent(pkg.PkgPath) {
|
|
142
|
+
// Add this package but don't visit its dependencies
|
|
143
|
+
c.le.Debugf("Skipping dependencies of handwritten package: %s", pkg.PkgPath)
|
|
144
|
+
return
|
|
145
|
+
}
|
|
146
|
+
|
|
114
147
|
// Visit all imports, including standard library packages
|
|
115
148
|
for _, imp := range pkg.Imports {
|
|
116
149
|
visit(imp)
|
|
@@ -146,17 +179,57 @@ func (c *Compiler) CompilePackages(ctx context.Context, patterns ...string) erro
|
|
|
146
179
|
*/
|
|
147
180
|
}
|
|
148
181
|
|
|
182
|
+
// If DisableEmitBuiltin is false, we need to copy the builtin package to the output directory
|
|
183
|
+
if !c.config.DisableEmitBuiltin {
|
|
184
|
+
c.le.Infof("Copying builtin package to output directory")
|
|
185
|
+
builtinPath := "gs/builtin"
|
|
186
|
+
outputPath := ComputeModulePath(c.config.OutputPath, "builtin")
|
|
187
|
+
if err := c.copyEmbeddedPackage(builtinPath, outputPath); err != nil {
|
|
188
|
+
return nil, fmt.Errorf("failed to copy builtin package to output directory: %w", err)
|
|
189
|
+
}
|
|
190
|
+
result.CopiedPackages = append(result.CopiedPackages, "builtin")
|
|
191
|
+
}
|
|
192
|
+
|
|
149
193
|
// Compile all packages
|
|
150
194
|
for _, pkg := range pkgs {
|
|
151
195
|
// Check if the package has a handwritten equivalent
|
|
196
|
+
// If the package was explicitly requested, skip this logic
|
|
152
197
|
if !slices.Contains(patternPkgPaths, pkg.PkgPath) {
|
|
153
|
-
|
|
198
|
+
gsSourcePath := "gs/" + pkg.PkgPath
|
|
199
|
+
_, gsErr := gs.GsOverrides.ReadDir(gsSourcePath)
|
|
154
200
|
if gsErr != nil && !os.IsNotExist(gsErr) {
|
|
155
|
-
return gsErr
|
|
201
|
+
return nil, gsErr
|
|
156
202
|
}
|
|
157
203
|
if gsErr == nil {
|
|
158
|
-
c.
|
|
159
|
-
|
|
204
|
+
if c.config.DisableEmitBuiltin {
|
|
205
|
+
c.le.Infof("Skipping compilation for overridden package %s", pkg.PkgPath)
|
|
206
|
+
result.CopiedPackages = append(result.CopiedPackages, pkg.PkgPath)
|
|
207
|
+
continue
|
|
208
|
+
} else {
|
|
209
|
+
// If DisableEmitBuiltin is false, we need to copy the handwritten package to the output directory
|
|
210
|
+
c.le.Infof("Copying handwritten package %s to output directory", pkg.PkgPath)
|
|
211
|
+
|
|
212
|
+
// Compute output path for this package
|
|
213
|
+
outputPath := ComputeModulePath(c.config.OutputPath, pkg.PkgPath)
|
|
214
|
+
|
|
215
|
+
// Remove existing directory if it exists
|
|
216
|
+
if err := os.RemoveAll(outputPath); err != nil {
|
|
217
|
+
return nil, fmt.Errorf("failed to remove existing output directory for %s: %w", pkg.PkgPath, err)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Create the output directory
|
|
221
|
+
if err := os.MkdirAll(outputPath, 0o755); err != nil {
|
|
222
|
+
return nil, fmt.Errorf("failed to create output directory for %s: %w", pkg.PkgPath, err)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Copy files from embedded FS to output directory
|
|
226
|
+
if err := c.copyEmbeddedPackage(gsSourcePath, outputPath); err != nil {
|
|
227
|
+
return nil, fmt.Errorf("failed to copy embedded package %s: %w", pkg.PkgPath, err)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
result.CopiedPackages = append(result.CopiedPackages, pkg.PkgPath)
|
|
231
|
+
continue
|
|
232
|
+
}
|
|
160
233
|
}
|
|
161
234
|
}
|
|
162
235
|
|
|
@@ -166,17 +239,42 @@ func (c *Compiler) CompilePackages(ctx context.Context, patterns ...string) erro
|
|
|
166
239
|
continue
|
|
167
240
|
}
|
|
168
241
|
|
|
242
|
+
// Check if this is the unsafe package, which is not supported in GoScript
|
|
243
|
+
if pkg.PkgPath == "unsafe" {
|
|
244
|
+
// Find which package depends on unsafe by looking at the import graph
|
|
245
|
+
var dependentPackages []string
|
|
246
|
+
for _, otherPkg := range pkgs {
|
|
247
|
+
if otherPkg.PkgPath != "unsafe" {
|
|
248
|
+
for importPath := range otherPkg.Imports {
|
|
249
|
+
if importPath == "unsafe" {
|
|
250
|
+
dependentPackages = append(dependentPackages, otherPkg.PkgPath)
|
|
251
|
+
break
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
dependentList := "unknown package"
|
|
258
|
+
if len(dependentPackages) > 0 {
|
|
259
|
+
dependentList = strings.Join(dependentPackages, ", ")
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
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)
|
|
263
|
+
}
|
|
264
|
+
|
|
169
265
|
pkgCompiler, err := NewPackageCompiler(c.le, &c.config, pkg)
|
|
170
266
|
if err != nil {
|
|
171
|
-
return fmt.Errorf("failed to create package compiler for %s: %w", pkg.PkgPath, err)
|
|
267
|
+
return nil, fmt.Errorf("failed to create package compiler for %s: %w", pkg.PkgPath, err)
|
|
172
268
|
}
|
|
173
269
|
|
|
174
270
|
if err := pkgCompiler.Compile(ctx); err != nil {
|
|
175
|
-
return fmt.Errorf("failed to compile package %s: %w", pkg.PkgPath, err)
|
|
271
|
+
return nil, fmt.Errorf("failed to compile package %s: %w", pkg.PkgPath, err)
|
|
176
272
|
}
|
|
273
|
+
|
|
274
|
+
result.CompiledPackages = append(result.CompiledPackages, pkg.PkgPath)
|
|
177
275
|
}
|
|
178
276
|
|
|
179
|
-
return nil
|
|
277
|
+
return result, nil
|
|
180
278
|
}
|
|
181
279
|
|
|
182
280
|
// PackageCompiler is responsible for compiling an entire Go package into
|
|
@@ -202,7 +300,7 @@ func NewPackageCompiler(
|
|
|
202
300
|
le: le,
|
|
203
301
|
pkg: pkg,
|
|
204
302
|
compilerConf: compilerConf,
|
|
205
|
-
outputPath: ComputeModulePath(compilerConf.
|
|
303
|
+
outputPath: ComputeModulePath(compilerConf.OutputPath, pkg.PkgPath),
|
|
206
304
|
}
|
|
207
305
|
|
|
208
306
|
return res, nil
|
|
@@ -287,7 +385,7 @@ func (c *PackageCompiler) generateIndexFile(compiledFiles []string) error {
|
|
|
287
385
|
// CompileFile handles the compilation of a single Go source file to TypeScript.
|
|
288
386
|
// It first performs a pre-compilation analysis of the file using `AnalyzeFile`
|
|
289
387
|
// to gather information necessary for accurate TypeScript generation (e.g.,
|
|
290
|
-
// about
|
|
388
|
+
// about varRefing, async functions, defer statements).
|
|
291
389
|
// Then, it creates a `FileCompiler` instance for the file and invokes its
|
|
292
390
|
// `Compile` method to generate the TypeScript code.
|
|
293
391
|
func (p *PackageCompiler) CompileFile(ctx context.Context, name string, syntax *ast.File) error {
|
|
@@ -351,7 +449,7 @@ func (c *FileCompiler) Compile(ctx context.Context) error {
|
|
|
351
449
|
pkgPath := c.pkg.PkgPath
|
|
352
450
|
|
|
353
451
|
outputFilePath := TranslateGoFilePathToTypescriptFilePath(pkgPath, filepath.Base(c.fullPath))
|
|
354
|
-
outputFilePathAbs := filepath.Join(c.compilerConfig.
|
|
452
|
+
outputFilePathAbs := filepath.Join(c.compilerConfig.OutputPath, outputFilePath)
|
|
355
453
|
|
|
356
454
|
if err := os.MkdirAll(filepath.Dir(outputFilePathAbs), 0o755); err != nil {
|
|
357
455
|
return err
|
|
@@ -382,7 +480,7 @@ func (c *FileCompiler) Compile(ctx context.Context) error {
|
|
|
382
480
|
// GoToTSCompiler is the core component responsible for translating Go AST nodes
|
|
383
481
|
// and type information into TypeScript code. It uses a `TSCodeWriter` to output
|
|
384
482
|
// the generated TypeScript and relies on `Analysis` data to make informed
|
|
385
|
-
// decisions about code generation (e.g.,
|
|
483
|
+
// decisions about code generation (e.g., varRefing, async behavior).
|
|
386
484
|
type GoToTSCompiler struct {
|
|
387
485
|
tsw *TSCodeWriter
|
|
388
486
|
|
|
@@ -407,15 +505,14 @@ func NewGoToTSCompiler(tsw *TSCodeWriter, pkg *packages.Package, analysis *Analy
|
|
|
407
505
|
// WriteIdent translates a Go identifier (`ast.Ident`) used as a value (e.g.,
|
|
408
506
|
// variable, function name) into its TypeScript equivalent.
|
|
409
507
|
// - If the identifier is `nil`, it writes `null`.
|
|
508
|
+
// - If the identifier refers to a constant, it writes the constant's evaluated value.
|
|
410
509
|
// - Otherwise, it writes the identifier's name.
|
|
411
|
-
// - If `
|
|
412
|
-
// indicates
|
|
413
|
-
// in a box (due to its address being taken or other boxing requirements),
|
|
414
|
-
// it appends `.value` to access the actual value from the box.
|
|
510
|
+
// - If `accessVarRefedValue` is true and the analysis (`c.analysis.NeedsVarRefAccess`)
|
|
511
|
+
// indicates the variable is variable referenced, `.value` is appended to access the contained value.
|
|
415
512
|
//
|
|
416
513
|
// This function relies on `go/types` (`TypesInfo.Uses` or `Defs`) to resolve
|
|
417
|
-
// the identifier and the `Analysis` data to determine
|
|
418
|
-
func (c *GoToTSCompiler) WriteIdent(exp *ast.Ident,
|
|
514
|
+
// the identifier and the `Analysis` data to determine varRefing needs.
|
|
515
|
+
func (c *GoToTSCompiler) WriteIdent(exp *ast.Ident, accessVarRefedValue bool) {
|
|
419
516
|
if exp.Name == "nil" {
|
|
420
517
|
c.tsw.WriteLiterally("null")
|
|
421
518
|
return
|
|
@@ -428,11 +525,25 @@ func (c *GoToTSCompiler) WriteIdent(exp *ast.Ident, accessBoxedValue bool) {
|
|
|
428
525
|
obj = c.pkg.TypesInfo.Defs[exp]
|
|
429
526
|
}
|
|
430
527
|
|
|
431
|
-
//
|
|
432
|
-
|
|
528
|
+
// Check if this identifier refers to a constant
|
|
529
|
+
if obj != nil {
|
|
530
|
+
if constObj, isConst := obj.(*types.Const); isConst {
|
|
531
|
+
// Only evaluate constants from the current package being compiled
|
|
532
|
+
// Don't evaluate constants from imported packages (they should use their exported names)
|
|
533
|
+
// Special case: predeclared constants like iota have a nil package, so we should evaluate them
|
|
534
|
+
if constObj.Pkg() == c.pkg.Types || constObj.Pkg() == nil {
|
|
535
|
+
// Write the constant's evaluated value instead of the identifier name
|
|
536
|
+
c.writeConstantValue(constObj)
|
|
537
|
+
return
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// Write the identifier name first, sanitizing if it's a reserved word
|
|
543
|
+
c.tsw.WriteLiterally(c.sanitizeIdentifier(exp.Name))
|
|
433
544
|
|
|
434
545
|
// Determine if we need to access .value based on analysis data
|
|
435
|
-
if obj != nil &&
|
|
546
|
+
if obj != nil && accessVarRefedValue && c.analysis.NeedsVarRefAccess(obj) {
|
|
436
547
|
c.tsw.WriteLiterally("!.value")
|
|
437
548
|
}
|
|
438
549
|
}
|
|
@@ -627,3 +738,177 @@ func (c *GoToTSCompiler) WriteDoc(doc *ast.CommentGroup) {
|
|
|
627
738
|
}
|
|
628
739
|
}
|
|
629
740
|
}
|
|
741
|
+
|
|
742
|
+
// sanitizeIdentifier checks if an identifier is a JavaScript/TypeScript reserved word
|
|
743
|
+
// and prefixes it with an underscore if it is. This prevents compilation errors
|
|
744
|
+
// when Go identifiers conflict with JS/TS keywords.
|
|
745
|
+
func (c *GoToTSCompiler) sanitizeIdentifier(name string) string {
|
|
746
|
+
// Don't sanitize boolean literals - they are valid in both Go and JS/TS
|
|
747
|
+
if name == "true" || name == "false" {
|
|
748
|
+
return name
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// List of JavaScript/TypeScript reserved words that could conflict
|
|
752
|
+
reservedWords := map[string]bool{
|
|
753
|
+
"abstract": true,
|
|
754
|
+
"any": true,
|
|
755
|
+
"as": true,
|
|
756
|
+
"asserts": true,
|
|
757
|
+
"async": true,
|
|
758
|
+
"await": true,
|
|
759
|
+
"boolean": true,
|
|
760
|
+
"break": true,
|
|
761
|
+
"case": true,
|
|
762
|
+
"catch": true,
|
|
763
|
+
"class": true,
|
|
764
|
+
"const": true,
|
|
765
|
+
"constructor": true,
|
|
766
|
+
"continue": true,
|
|
767
|
+
"debugger": true,
|
|
768
|
+
"declare": true,
|
|
769
|
+
"default": true,
|
|
770
|
+
"delete": true,
|
|
771
|
+
"do": true,
|
|
772
|
+
"else": true,
|
|
773
|
+
"enum": true,
|
|
774
|
+
"export": true,
|
|
775
|
+
"extends": true,
|
|
776
|
+
"finally": true,
|
|
777
|
+
"for": true,
|
|
778
|
+
"from": true,
|
|
779
|
+
"function": true,
|
|
780
|
+
"get": true,
|
|
781
|
+
"if": true,
|
|
782
|
+
"implements": true,
|
|
783
|
+
"import": true,
|
|
784
|
+
"in": true,
|
|
785
|
+
"instanceof": true,
|
|
786
|
+
"interface": true,
|
|
787
|
+
"is": true,
|
|
788
|
+
"keyof": true,
|
|
789
|
+
"let": true,
|
|
790
|
+
"module": true,
|
|
791
|
+
"namespace": true,
|
|
792
|
+
"never": true,
|
|
793
|
+
"new": true,
|
|
794
|
+
"null": true,
|
|
795
|
+
"number": true,
|
|
796
|
+
"object": true,
|
|
797
|
+
"of": true,
|
|
798
|
+
"package": true,
|
|
799
|
+
"private": true,
|
|
800
|
+
"protected": true,
|
|
801
|
+
"public": true,
|
|
802
|
+
"readonly": true,
|
|
803
|
+
"require": true,
|
|
804
|
+
"return": true,
|
|
805
|
+
"set": true,
|
|
806
|
+
"static": true,
|
|
807
|
+
"string": true,
|
|
808
|
+
"super": true,
|
|
809
|
+
"switch": true,
|
|
810
|
+
"symbol": true,
|
|
811
|
+
"this": true,
|
|
812
|
+
"throw": true,
|
|
813
|
+
"try": true,
|
|
814
|
+
"type": true,
|
|
815
|
+
"typeof": true,
|
|
816
|
+
"undefined": true,
|
|
817
|
+
"unique": true,
|
|
818
|
+
"unknown": true,
|
|
819
|
+
"var": true,
|
|
820
|
+
"void": true,
|
|
821
|
+
"while": true,
|
|
822
|
+
"with": true,
|
|
823
|
+
"yield": true,
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
if reservedWords[name] {
|
|
827
|
+
return "_" + name
|
|
828
|
+
}
|
|
829
|
+
return name
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// writeConstantValue writes the evaluated value of a Go constant to TypeScript.
|
|
833
|
+
// It handles different constant types (integer, float, string, boolean, complex)
|
|
834
|
+
// and writes the appropriate TypeScript literal.
|
|
835
|
+
func (c *GoToTSCompiler) writeConstantValue(constObj *types.Const) {
|
|
836
|
+
val := constObj.Val()
|
|
837
|
+
|
|
838
|
+
switch val.Kind() {
|
|
839
|
+
case constant.Int:
|
|
840
|
+
// For integer constants, write the string representation
|
|
841
|
+
c.tsw.WriteLiterally(val.String())
|
|
842
|
+
case constant.Float:
|
|
843
|
+
// For float constants, write the string representation
|
|
844
|
+
c.tsw.WriteLiterally(val.String())
|
|
845
|
+
case constant.String:
|
|
846
|
+
// For string constants, write as a quoted string literal
|
|
847
|
+
c.tsw.WriteLiterally(val.String()) // val.String() already includes quotes
|
|
848
|
+
case constant.Bool:
|
|
849
|
+
// For boolean constants, write true/false
|
|
850
|
+
if constant.BoolVal(val) {
|
|
851
|
+
c.tsw.WriteLiterally("true")
|
|
852
|
+
} else {
|
|
853
|
+
c.tsw.WriteLiterally("false")
|
|
854
|
+
}
|
|
855
|
+
case constant.Complex:
|
|
856
|
+
// For complex constants, we need to handle them specially
|
|
857
|
+
// For now, write as a comment indicating unsupported
|
|
858
|
+
c.tsw.WriteLiterally("/* complex constant: " + val.String() + " */")
|
|
859
|
+
default:
|
|
860
|
+
// For unknown constant types, write as a comment
|
|
861
|
+
c.tsw.WriteLiterally("/* unknown constant: " + val.String() + " */")
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
// copyEmbeddedPackage recursively copies files from an embedded FS path to a filesystem directory.
|
|
866
|
+
// It handles both regular files and directories.
|
|
867
|
+
func (c *Compiler) copyEmbeddedPackage(embeddedPath string, outputPath string) error {
|
|
868
|
+
// Remove the output path if it exists
|
|
869
|
+
if err := os.RemoveAll(outputPath); err != nil {
|
|
870
|
+
return fmt.Errorf("failed to remove output directory %s: %w", outputPath, err)
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
// Create the output path
|
|
874
|
+
if err := os.MkdirAll(outputPath, 0o755); err != nil {
|
|
875
|
+
return fmt.Errorf("failed to create output directory %s: %w", outputPath, err)
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
// List the entries in the embedded path
|
|
879
|
+
entries, err := gs.GsOverrides.ReadDir(embeddedPath)
|
|
880
|
+
if err != nil {
|
|
881
|
+
return fmt.Errorf("failed to read embedded directory %s: %w", embeddedPath, err)
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
// Process each entry
|
|
885
|
+
for _, entry := range entries {
|
|
886
|
+
entryPath := filepath.Join(embeddedPath, entry.Name())
|
|
887
|
+
outputEntryPath := filepath.Join(outputPath, entry.Name())
|
|
888
|
+
|
|
889
|
+
if entry.IsDir() {
|
|
890
|
+
// Create the output directory
|
|
891
|
+
if err := os.MkdirAll(outputEntryPath, 0o755); err != nil {
|
|
892
|
+
return fmt.Errorf("failed to create output directory %s: %w", outputEntryPath, err)
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
// Recursively copy the directory contents
|
|
896
|
+
if err := c.copyEmbeddedPackage(entryPath, outputEntryPath); err != nil {
|
|
897
|
+
return err
|
|
898
|
+
}
|
|
899
|
+
} else {
|
|
900
|
+
// Read the file content from the embedded FS
|
|
901
|
+
content, err := gs.GsOverrides.ReadFile(entryPath)
|
|
902
|
+
if err != nil {
|
|
903
|
+
return fmt.Errorf("failed to read embedded file %s: %w", entryPath, err)
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
// Write the content to the output file
|
|
907
|
+
if err := os.WriteFile(outputEntryPath, content, 0o644); err != nil {
|
|
908
|
+
return fmt.Errorf("failed to write file %s: %w", outputEntryPath, err)
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
return nil
|
|
914
|
+
}
|