goscript 0.0.54 → 0.0.56

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 CHANGED
@@ -64,6 +64,108 @@ npm install -g goscript
64
64
  goscript compile --package . --output ./dist
65
65
  ```
66
66
 
67
+ ## 📦 Using Generated Code in Your Project
68
+
69
+ After compiling your Go code to TypeScript, you'll need to set up your project appropriately.
70
+
71
+ ### TypeScript Configuration
72
+
73
+ Create or update your `tsconfig.json` with these settings:
74
+
75
+ ```json
76
+ {
77
+ "compilerOptions": {
78
+ "target": "ES2022",
79
+ "module": "ESNext",
80
+ "moduleResolution": "bundler",
81
+ "lib": ["ES2022", "esnext.disposable", "dom"],
82
+ "baseUrl": "./",
83
+ "paths": {
84
+ "@goscript/*": ["./path/to/generated/output/@goscript/*"]
85
+ },
86
+ "allowSyntheticDefaultImports": true,
87
+ "esModuleInterop": true,
88
+ "skipLibCheck": true,
89
+ "strict": true
90
+ }
91
+ }
92
+ ```
93
+
94
+ **Important requirements:**
95
+ - **`target: "ES2022"` or newer** - Required for `Disposable` and other features
96
+ - **`lib: ["esnext.disposable"]`** - Enables TypeScript's disposable types for resource management
97
+ - **`baseUrl` and `paths`** - Allows TypeScript to resolve `@goscript/*` imports
98
+ - **`moduleResolution: "bundler"`** - Recommended for modern bundlers
99
+
100
+ You should be able to use any TypeScript bundler to compile the generated TypeScript.
101
+
102
+ ## 🛠️ Integration & Usage
103
+
104
+ ### Command Line
105
+
106
+ ```bash
107
+ goscript compile --package ./my-go-code --output ./dist
108
+ ```
109
+
110
+ **Options:**
111
+ - `--package <path>` - Go package to compile (default: ".")
112
+ - `--output <dir>` - Output directory for TypeScript files
113
+
114
+ ### Programmatic API
115
+
116
+ **Go:**
117
+ ```go
118
+ import "github.com/aperturerobotics/goscript/compiler"
119
+
120
+ conf := &compiler.Config{OutputPath: "./dist"}
121
+ comp, err := compiler.NewCompiler(conf, logger, nil)
122
+ _, err = comp.CompilePackages(ctx, "your/package/path")
123
+ ```
124
+
125
+ **Node.js:**
126
+ ```typescript
127
+ import { compile } from 'goscript'
128
+
129
+ await compile({
130
+ pkg: './my-go-package',
131
+ output: './dist'
132
+ })
133
+ ```
134
+
135
+ ### Frontend Frameworks
136
+
137
+ **React + GoScript:**
138
+ ```typescript
139
+ import { NewCalculator } from '@goscript/myapp/calculator'
140
+
141
+ function CalculatorApp() {
142
+ const [calc] = useState(() => NewCalculator())
143
+
144
+ const handleAdd = () => {
145
+ const result = calc.Add(5, 3)
146
+ setResult(result)
147
+ }
148
+
149
+ return <button onClick={handleAdd}>Add 5 + 3</button>
150
+ }
151
+ ```
152
+
153
+ **Vue + GoScript:**
154
+ ```vue
155
+ <script setup lang="ts">
156
+ import { NewUser, FindUserByEmail } from '@goscript/myapp/user'
157
+
158
+ const users = ref([
159
+ NewUser(1, "Alice", "alice@example.com")
160
+ ])
161
+
162
+ const searchUser = (email: string) => {
163
+ return FindUserByEmail(users.value, email)
164
+ }
165
+ </script>
166
+ ```
167
+
168
+
67
169
  ## 💡 See It In Action
68
170
 
69
171
  ### Example: User Management
@@ -196,72 +298,6 @@ async function handleMessages() {
196
298
  }
197
299
  ```
198
300
 
199
- ## 🛠️ Integration & Usage
200
-
201
- ### Command Line
202
-
203
- ```bash
204
- goscript compile --package ./my-go-code --output ./dist
205
- ```
206
-
207
- **Options:**
208
- - `--package <path>` - Go package to compile (default: ".")
209
- - `--output <dir>` - Output directory for TypeScript files
210
-
211
- ### Programmatic API
212
-
213
- **Go:**
214
- ```go
215
- import "github.com/aperturerobotics/goscript/compiler"
216
-
217
- conf := &compiler.Config{OutputPath: "./dist"}
218
- comp, err := compiler.NewCompiler(conf, logger, nil)
219
- _, err = comp.CompilePackages(ctx, "your/package/path")
220
- ```
221
-
222
- **Node.js:**
223
- ```typescript
224
- import { compile } from 'goscript'
225
-
226
- await compile({
227
- pkg: './my-go-package',
228
- output: './dist'
229
- })
230
- ```
231
-
232
- ### Frontend Frameworks
233
-
234
- **React + GoScript:**
235
- ```typescript
236
- import { NewCalculator } from '@goscript/myapp/calculator'
237
-
238
- function CalculatorApp() {
239
- const [calc] = useState(() => NewCalculator())
240
-
241
- const handleAdd = () => {
242
- const result = calc.Add(5, 3)
243
- setResult(result)
244
- }
245
-
246
- return <button onClick={handleAdd}>Add 5 + 3</button>
247
- }
248
- ```
249
-
250
- **Vue + GoScript:**
251
- ```vue
252
- <script setup lang="ts">
253
- import { NewUser, FindUserByEmail } from '@goscript/myapp/user'
254
-
255
- const users = ref([
256
- NewUser(1, "Alice", "alice@example.com")
257
- ])
258
-
259
- const searchUser = (email: string) => {
260
- return FindUserByEmail(users.value, email)
261
- }
262
- </script>
263
- ```
264
-
265
301
  ## 🚀 What's Next?
266
302
 
267
303
  **Current Status:**
@@ -276,19 +312,7 @@ const searchUser = (email: string) => {
276
312
  - ⚡ Performance optimizations
277
313
  - 🔧 Better tooling integration
278
314
 
279
- Check our [compliance tests](./compliance/COMPLIANCE.md) for detailed progress.
280
-
281
- ## 🤝 Real-World Use Cases
282
-
283
- **Fintech:** Share complex financial calculations between Go services and trading dashboards
284
-
285
- **Gaming:** Run the same game logic on servers and in browser clients
286
-
287
- **Data Processing:** Use identical algorithms for backend ETL and frontend analytics
288
-
289
- **Validation:** Keep business rules consistent across your entire stack
290
-
291
- Ready to eliminate code duplication? [Get started now](#-get-started-in-2-minutes) 🚀
315
+ Check the [compliance tests](./compliance/COMPLIANCE.md) for detailed progress.
292
316
 
293
317
  ## License
294
318
 
@@ -434,6 +434,24 @@ func (c *PackageCompiler) generateIndexFile(compiledFiles []string) error {
434
434
  case *ast.FuncDecl:
435
435
  if d.Recv == nil && d.Name.IsExported() {
436
436
  valueSymbols = append(valueSymbols, sanitizeIdentifier(d.Name.Name))
437
+ } else if d.Recv != nil && len(d.Recv.List) == 1 && d.Name.IsExported() {
438
+ recvField := d.Recv.List[0]
439
+ recvTypeExpr := recvField.Type
440
+ if star, ok := recvTypeExpr.(*ast.StarExpr); ok {
441
+ recvTypeExpr = star.X
442
+ }
443
+ if ident, ok := recvTypeExpr.(*ast.Ident); ok {
444
+ typeObj := c.pkg.TypesInfo.ObjectOf(ident)
445
+ if typeObj != nil && typeObj.Exported() {
446
+ if typeName, ok := typeObj.(*types.TypeName); ok {
447
+ underlying := typeName.Type().Underlying()
448
+ if _, isStruct := underlying.(*types.Struct); !isStruct {
449
+ methodName := sanitizeIdentifier(ident.Name + "_" + d.Name.Name)
450
+ valueSymbols = append(valueSymbols, methodName)
451
+ }
452
+ }
453
+ }
454
+ }
437
455
  }
438
456
  case *ast.GenDecl:
439
457
  for _, spec := range d.Specs {
@@ -1,6 +1,7 @@
1
1
  package compiler_test
2
2
 
3
3
  import (
4
+ "fmt"
4
5
  "os"
5
6
  "os/exec"
6
7
  "path/filepath"
@@ -135,5 +136,14 @@ func getParentGoModulePath() (string, error) {
135
136
  if err != nil {
136
137
  return "", err
137
138
  }
138
- return strings.TrimSpace(string(output)), nil
139
+ // note: in a go work configuration, go list -m can report multiple modules
140
+ // only one of which is the goscript case, so we need to filter:
141
+ pf := strings.Fields(strings.TrimSpace(string(output)))
142
+ pf = slices.DeleteFunc(pf, func(n string) bool {
143
+ return !strings.HasSuffix(n, "goscript")
144
+ })
145
+ if len(pf) != 1 {
146
+ return "", fmt.Errorf("'go list -m' did not have exactly 1 goscript package -- run in root of goscript package")
147
+ }
148
+ return pf[0], nil
139
149
  }
@@ -349,9 +349,47 @@ func (c *GoToTSCompiler) writeWrapperTypeMethodCall(exp *ast.CallExpr, selectorE
349
349
  c.tsw.WriteLiterally(selectorExpr.Sel.Name)
350
350
  c.tsw.WriteLiterally("(")
351
351
 
352
- // First argument is the receiver
353
- if err := c.WriteValueExpr(selectorExpr.X); err != nil {
354
- return true, fmt.Errorf("failed to write wrapper type method receiver: %w", err)
352
+ // Write the receiver (the object the method is called on)
353
+ // For pointer receiver methods, we need to pass the VarRef instead of the value
354
+ receiverNeedsVarRef := false
355
+
356
+ // Check if the method has a pointer receiver by looking at the method signature
357
+ if selection := c.pkg.TypesInfo.Selections[selectorExpr]; selection != nil {
358
+ if methodObj := selection.Obj(); methodObj != nil {
359
+ if methodFunc, ok := methodObj.(*types.Func); ok {
360
+ if sig, ok := methodFunc.Type().(*types.Signature); ok && sig != nil {
361
+ if recv := sig.Recv(); recv != nil {
362
+ if _, isPointer := recv.Type().(*types.Pointer); isPointer {
363
+ receiverNeedsVarRef = true
364
+ }
365
+ }
366
+ }
367
+ }
368
+ }
369
+ }
370
+
371
+ if receiverNeedsVarRef {
372
+ // For pointer receivers, we need to pass the VarRef
373
+ // Convert p.field to p._fields.field
374
+ if selExpr, ok := selectorExpr.X.(*ast.SelectorExpr); ok {
375
+ if baseIdent, ok := selExpr.X.(*ast.Ident); ok {
376
+ c.tsw.WriteLiterally(baseIdent.Name)
377
+ c.tsw.WriteLiterally("._fields.")
378
+ c.tsw.WriteLiterally(selExpr.Sel.Name)
379
+ } else {
380
+ if err := c.WriteValueExpr(selectorExpr.X); err != nil {
381
+ return true, fmt.Errorf("failed to write wrapper type method receiver: %w", err)
382
+ }
383
+ }
384
+ } else {
385
+ if err := c.WriteValueExpr(selectorExpr.X); err != nil {
386
+ return true, fmt.Errorf("failed to write wrapper type method receiver: %w", err)
387
+ }
388
+ }
389
+ } else {
390
+ if err := c.WriteValueExpr(selectorExpr.X); err != nil {
391
+ return true, fmt.Errorf("failed to write wrapper type method receiver: %w", err)
392
+ }
355
393
  }
356
394
 
357
395
  // Add other arguments
package/compiler/spec.go CHANGED
@@ -376,8 +376,10 @@ func (c *GoToTSCompiler) WriteNamedTypeWithMethods(a *ast.TypeSpec) error {
376
376
  }
377
377
  recvField := funcDecl.Recv.List[0]
378
378
  recvType := recvField.Type
379
+ isPointerReceiver := false
379
380
  if starExpr, ok := recvType.(*ast.StarExpr); ok {
380
381
  recvType = starExpr.X
382
+ isPointerReceiver = true
381
383
  }
382
384
 
383
385
  // Check for both simple identifiers (FileMode) and generic types (FileMode[T])
@@ -391,12 +393,7 @@ func (c *GoToTSCompiler) WriteNamedTypeWithMethods(a *ast.TypeSpec) error {
391
393
  }
392
394
 
393
395
  if recvTypeName == className {
394
- if !isInsideFunction {
395
- c.tsw.WriteLiterally("export ")
396
- }
397
-
398
- // Generate function signature: export function TypeName_MethodName(receiver: TypeName, ...args): ReturnType
399
- c.tsw.WriteLiterally("function ")
396
+ c.tsw.WriteLiterally("export function ")
400
397
  c.tsw.WriteLiterally(className)
401
398
  c.tsw.WriteLiterally("_")
402
399
  c.tsw.WriteLiterally(funcDecl.Name.Name)
@@ -413,7 +410,15 @@ func (c *GoToTSCompiler) WriteNamedTypeWithMethods(a *ast.TypeSpec) error {
413
410
  }
414
411
  c.tsw.WriteLiterally(receiverParamName)
415
412
  c.tsw.WriteLiterally(": ")
416
- c.tsw.WriteLiterally(className)
413
+
414
+ // For pointer receivers, use VarRef<T>
415
+ if isPointerReceiver {
416
+ c.tsw.WriteLiterally("$.VarRef<")
417
+ c.tsw.WriteLiterally(className)
418
+ c.tsw.WriteLiterally(">")
419
+ } else {
420
+ c.tsw.WriteLiterally(className)
421
+ }
417
422
 
418
423
  // Add other parameters
419
424
  if funcDecl.Type.Params != nil && len(funcDecl.Type.Params.List) > 0 {
@@ -3,11 +3,10 @@ package compiler
3
3
  import (
4
4
  "fmt"
5
5
  "go/ast"
6
+ "go/token"
6
7
  "go/types"
7
8
  "strings"
8
9
 
9
- "go/token"
10
-
11
10
  "github.com/pkg/errors"
12
11
  )
13
12
 
@@ -1 +1 @@
1
- {"version":3,"file":"iter.js","sourceRoot":"","sources":["../../../gs/reflect/iter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,OAAO,EAAE,MAAM,WAAW,CAAA;AAKhD,MAAM,UAAU,QAAQ,CAKtB,GAAM,EAAE,CAAO;IACf,8CAA8C;IAE9C,2CAA2C;IAC3C,wBAAwB;IACxB,OAAO,CAAC,MAAsC,EAAQ,EAAE;QACtD,IAAI,OAAO,GAAG,CAAE,CAAC,OAAQ,EAAE,IAAI,EAAE,CAAA;QACjC,8CAA8C;QAE9C,2CAA2C;QAC3C,wBAAwB;QACxB,KAAK,IAAI,CAAC,GAAG,CAAiB,EAAE,CAAC,GAAI,GAAoB,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/D,IAAI,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAA;YAC5B,2CAA2C;YAC3C,wBAAwB;YACxB,IAAI,OAAO,EAAE,CAAC;gBACZ,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAA;YAC9B,CAAC;YACD,IAAI,CAAC,MAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBAClB,OAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"iter.js","sourceRoot":"","sources":["../../../gs/reflect/iter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,OAAO,EAAE,MAAM,WAAW,CAAA;AAKhD,MAAM,UAAU,QAAQ,CACtB,GAAM,EACN,CAAO;IAEP,8CAA8C;IAE9C,2CAA2C;IAC3C,wBAAwB;IACxB,OAAO,CAAC,MAAsC,EAAQ,EAAE;QACtD,IAAI,OAAO,GAAG,CAAE,CAAC,OAAQ,EAAE,IAAI,EAAE,CAAA;QACjC,8CAA8C;QAE9C,2CAA2C;QAC3C,wBAAwB;QACxB,KAAK,IAAI,CAAC,GAAG,CAAiB,EAAE,CAAC,GAAI,GAAoB,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/D,IAAI,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAA;YAC5B,2CAA2C;YAC3C,wBAAwB;YACxB,IAAI,OAAO,EAAE,CAAC;gBACZ,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAA;YAC9B,CAAC;YACD,IAAI,CAAC,MAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBAClB,OAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC,CAAA;AACH,CAAC"}
@@ -3,12 +3,10 @@ import { uintptr } from './types.js'
3
3
 
4
4
  import * as iter from '@goscript/iter/index.js'
5
5
 
6
- export function rangeNum<
7
- T extends
8
- | number
9
- | uintptr,
10
- N extends number | number,
11
- >(num: N, t: Type): iter.Seq<Value> {
6
+ export function rangeNum<T extends number | uintptr, N extends number | number>(
7
+ num: N,
8
+ t: Type,
9
+ ): iter.Seq<Value> {
12
10
  // cannot use range T(v) because no core type.
13
11
 
14
12
  // if the iteration value type is define by
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "goscript",
3
3
  "description": "Go to TypeScript transpiler",
4
- "version": "0.0.54",
4
+ "version": "0.0.56",
5
5
  "author": {
6
6
  "name": "Aperture Robotics LLC.",
7
7
  "email": "support@aperture.us",