goscript 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (330) hide show
  1. package/README.md +5 -2
  2. package/cmd/go_js_wasm_exec/main.go +201 -0
  3. package/cmd/go_js_wasm_exec/main_test.go +83 -0
  4. package/cmd/goscript/{cmd_compile.go → cmd-compile.go} +35 -8
  5. package/cmd/goscript/cmd-test.go +14 -0
  6. package/cmd/goscript/cmd-test_test.go +1 -1
  7. package/cmd/goscript/cmd_compile_test.go +105 -6
  8. package/compiler/build-flags.go +9 -10
  9. package/compiler/compile-request.go +12 -9
  10. package/compiler/compliance_test.go +0 -1
  11. package/compiler/config.go +2 -0
  12. package/compiler/gotest/request.go +28 -0
  13. package/compiler/gotest/runner.go +353 -27
  14. package/compiler/gotest/runner_test.go +400 -1
  15. package/compiler/gotest/testdata/browserapi/browserapi_test.go +20 -0
  16. package/compiler/gotest/testdata/browserapi/go.mod +3 -0
  17. package/compiler/lowered-program.go +24 -17
  18. package/compiler/lowering.go +988 -263
  19. package/compiler/lowering_bench_test.go +364 -0
  20. package/compiler/override-facts.go +15 -0
  21. package/compiler/override-parity-verifier.go +450 -0
  22. package/compiler/override-parity.go +122 -0
  23. package/compiler/override-registry_test.go +559 -0
  24. package/compiler/package-graph.go +61 -4
  25. package/compiler/package-graph_test.go +30 -0
  26. package/compiler/protobuf-ts-binding.go +514 -0
  27. package/compiler/protobuf-ts-binding_test.go +172 -0
  28. package/compiler/semantic-model-types.go +17 -4
  29. package/compiler/semantic-model.go +709 -72
  30. package/compiler/semantic-model_test.go +219 -0
  31. package/compiler/service.go +20 -1
  32. package/compiler/skeleton_test.go +1008 -20
  33. package/compiler/typescript-emitter.go +147 -15
  34. package/dist/gs/builtin/builtin.d.ts +2 -2
  35. package/dist/gs/builtin/builtin.js +20 -0
  36. package/dist/gs/builtin/builtin.js.map +1 -1
  37. package/dist/gs/builtin/slice.d.ts +2 -1
  38. package/dist/gs/builtin/slice.js +34 -4
  39. package/dist/gs/builtin/slice.js.map +1 -1
  40. package/dist/gs/builtin/type.d.ts +14 -6
  41. package/dist/gs/builtin/type.js +224 -64
  42. package/dist/gs/builtin/type.js.map +1 -1
  43. package/dist/gs/builtin/varRef.d.ts +11 -0
  44. package/dist/gs/builtin/varRef.js +57 -2
  45. package/dist/gs/builtin/varRef.js.map +1 -1
  46. package/dist/gs/bytes/buffer.gs.js +1 -1
  47. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  48. package/dist/gs/bytes/reader.gs.js +1 -1
  49. package/dist/gs/bytes/reader.gs.js.map +1 -1
  50. package/dist/gs/compress/zlib/index.d.ts +13 -6
  51. package/dist/gs/compress/zlib/index.js +131 -35
  52. package/dist/gs/compress/zlib/index.js.map +1 -1
  53. package/dist/gs/crypto/sha1/index.js +2 -5
  54. package/dist/gs/crypto/sha1/index.js.map +1 -1
  55. package/dist/gs/crypto/sha256/index.js +2 -5
  56. package/dist/gs/crypto/sha256/index.js.map +1 -1
  57. package/dist/gs/crypto/sha512/index.js +2 -5
  58. package/dist/gs/crypto/sha512/index.js.map +1 -1
  59. package/dist/gs/embed/index.d.ts +6 -0
  60. package/dist/gs/embed/index.js +210 -5
  61. package/dist/gs/embed/index.js.map +1 -1
  62. package/dist/gs/encoding/json/index.d.ts +114 -0
  63. package/dist/gs/encoding/json/index.js +544 -36
  64. package/dist/gs/encoding/json/index.js.map +1 -1
  65. package/dist/gs/fmt/fmt.d.ts +3 -3
  66. package/dist/gs/fmt/fmt.js +29 -16
  67. package/dist/gs/fmt/fmt.js.map +1 -1
  68. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +100 -0
  69. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +564 -0
  70. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  71. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.d.ts +45 -0
  72. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js +229 -0
  73. package/dist/gs/github.com/go-git/go-billy/v6/osfs/index.js.map +1 -0
  74. package/dist/gs/github.com/pkg/errors/errors.js +54 -30
  75. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  76. package/dist/gs/go/scanner/index.d.ts +2 -0
  77. package/dist/gs/go/scanner/index.js +29 -5
  78. package/dist/gs/go/scanner/index.js.map +1 -1
  79. package/dist/gs/go/token/index.js +22 -6
  80. package/dist/gs/go/token/index.js.map +1 -1
  81. package/dist/gs/hash/index.d.ts +6 -0
  82. package/dist/gs/hash/index.js +20 -0
  83. package/dist/gs/hash/index.js.map +1 -1
  84. package/dist/gs/internal/goarch/index.d.ts +43 -3
  85. package/dist/gs/internal/goarch/index.js +42 -10
  86. package/dist/gs/internal/goarch/index.js.map +1 -1
  87. package/dist/gs/io/fs/fs.js +26 -14
  88. package/dist/gs/io/fs/fs.js.map +1 -1
  89. package/dist/gs/io/fs/readdir.js +8 -4
  90. package/dist/gs/io/fs/readdir.js.map +1 -1
  91. package/dist/gs/io/fs/sub.js +8 -1
  92. package/dist/gs/io/fs/sub.js.map +1 -1
  93. package/dist/gs/io/io.d.ts +12 -6
  94. package/dist/gs/io/io.js +87 -42
  95. package/dist/gs/io/io.js.map +1 -1
  96. package/dist/gs/math/bits/index.d.ts +31 -5
  97. package/dist/gs/math/bits/index.js +29 -28
  98. package/dist/gs/math/bits/index.js.map +1 -1
  99. package/dist/gs/mime/index.d.ts +16 -0
  100. package/dist/gs/mime/index.js +315 -6
  101. package/dist/gs/mime/index.js.map +1 -1
  102. package/dist/gs/net/http/httptest/index.d.ts +12 -0
  103. package/dist/gs/net/http/httptest/index.js +85 -6
  104. package/dist/gs/net/http/httptest/index.js.map +1 -1
  105. package/dist/gs/net/http/index.d.ts +303 -6
  106. package/dist/gs/net/http/index.js +1615 -58
  107. package/dist/gs/net/http/index.js.map +1 -1
  108. package/dist/gs/os/dir_unix.gs.js +1 -1
  109. package/dist/gs/os/dir_unix.gs.js.map +1 -1
  110. package/dist/gs/os/error.gs.js +1 -1
  111. package/dist/gs/os/error.gs.js.map +1 -1
  112. package/dist/gs/os/exec.gs.d.ts +1 -0
  113. package/dist/gs/os/exec.gs.js +4 -8
  114. package/dist/gs/os/exec.gs.js.map +1 -1
  115. package/dist/gs/os/exec_posix.gs.js +1 -1
  116. package/dist/gs/os/exec_posix.gs.js.map +1 -1
  117. package/dist/gs/os/index.d.ts +1 -1
  118. package/dist/gs/os/index.js +1 -1
  119. package/dist/gs/os/index.js.map +1 -1
  120. package/dist/gs/os/proc.gs.d.ts +4 -0
  121. package/dist/gs/os/proc.gs.js +12 -6
  122. package/dist/gs/os/proc.gs.js.map +1 -1
  123. package/dist/gs/os/root_js.gs.js +1 -1
  124. package/dist/gs/os/root_js.gs.js.map +1 -1
  125. package/dist/gs/os/types.gs.js +1 -1
  126. package/dist/gs/os/types.gs.js.map +1 -1
  127. package/dist/gs/os/types_js.gs.d.ts +6 -2
  128. package/dist/gs/os/types_js.gs.js +170 -9
  129. package/dist/gs/os/types_js.gs.js.map +1 -1
  130. package/dist/gs/os/types_unix.gs.js +1 -1
  131. package/dist/gs/os/types_unix.gs.js.map +1 -1
  132. package/dist/gs/path/path.js +11 -7
  133. package/dist/gs/path/path.js.map +1 -1
  134. package/dist/gs/reflect/index.d.ts +5 -4
  135. package/dist/gs/reflect/index.js +4 -3
  136. package/dist/gs/reflect/index.js.map +1 -1
  137. package/dist/gs/reflect/map.js +15 -0
  138. package/dist/gs/reflect/map.js.map +1 -1
  139. package/dist/gs/reflect/type.d.ts +26 -6
  140. package/dist/gs/reflect/type.js +1498 -279
  141. package/dist/gs/reflect/type.js.map +1 -1
  142. package/dist/gs/reflect/types.d.ts +14 -6
  143. package/dist/gs/reflect/types.js +35 -1
  144. package/dist/gs/reflect/types.js.map +1 -1
  145. package/dist/gs/reflect/value.d.ts +1 -0
  146. package/dist/gs/reflect/value.js +83 -41
  147. package/dist/gs/reflect/value.js.map +1 -1
  148. package/dist/gs/reflect/visiblefields.js +4 -140
  149. package/dist/gs/reflect/visiblefields.js.map +1 -1
  150. package/dist/gs/runtime/pprof/index.d.ts +8 -2
  151. package/dist/gs/runtime/pprof/index.js +50 -30
  152. package/dist/gs/runtime/pprof/index.js.map +1 -1
  153. package/dist/gs/runtime/runtime.js +5 -4
  154. package/dist/gs/runtime/runtime.js.map +1 -1
  155. package/dist/gs/runtime/trace/index.js +5 -19
  156. package/dist/gs/runtime/trace/index.js.map +1 -1
  157. package/dist/gs/strconv/atoi.gs.js +1 -1
  158. package/dist/gs/strconv/atoi.gs.js.map +1 -1
  159. package/dist/gs/strconv/complex.gs.d.ts +3 -0
  160. package/dist/gs/strconv/complex.gs.js +148 -0
  161. package/dist/gs/strconv/complex.gs.js.map +1 -0
  162. package/dist/gs/strconv/index.d.ts +1 -0
  163. package/dist/gs/strconv/index.js +1 -0
  164. package/dist/gs/strconv/index.js.map +1 -1
  165. package/dist/gs/strings/builder.js +1 -1
  166. package/dist/gs/strings/reader.d.ts +1 -1
  167. package/dist/gs/strings/reader.js +11 -7
  168. package/dist/gs/strings/reader.js.map +1 -1
  169. package/dist/gs/strings/replace.js +15 -7
  170. package/dist/gs/strings/replace.js.map +1 -1
  171. package/dist/gs/strings/strings.d.ts +5 -0
  172. package/dist/gs/strings/strings.js +57 -5
  173. package/dist/gs/strings/strings.js.map +1 -1
  174. package/dist/gs/sync/atomic/type.gs.js +9 -9
  175. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  176. package/dist/gs/sync/atomic/value.gs.js +2 -2
  177. package/dist/gs/sync/atomic/value.gs.js.map +1 -1
  178. package/dist/gs/sync/sync.d.ts +2 -1
  179. package/dist/gs/sync/sync.js +37 -16
  180. package/dist/gs/sync/sync.js.map +1 -1
  181. package/dist/gs/syscall/env.js +22 -14
  182. package/dist/gs/syscall/env.js.map +1 -1
  183. package/dist/gs/syscall/js/index.js +9 -0
  184. package/dist/gs/syscall/js/index.js.map +1 -1
  185. package/dist/gs/testing/testing.js +59 -15
  186. package/dist/gs/testing/testing.js.map +1 -1
  187. package/dist/gs/time/time.d.ts +24 -1
  188. package/dist/gs/time/time.js +43 -3
  189. package/dist/gs/time/time.js.map +1 -1
  190. package/dist/gs/unique/index.js +7 -1
  191. package/dist/gs/unique/index.js.map +1 -1
  192. package/go.mod +3 -3
  193. package/go.sum +16 -0
  194. package/gs/builtin/builtin.ts +25 -2
  195. package/gs/builtin/runtime-contract.test.ts +260 -18
  196. package/gs/builtin/slice.ts +51 -4
  197. package/gs/builtin/type.ts +310 -63
  198. package/gs/builtin/varRef.ts +85 -2
  199. package/gs/bytes/buffer.gs.ts +1 -1
  200. package/gs/bytes/reader.gs.ts +1 -1
  201. package/gs/compress/zlib/index.test.ts +159 -1
  202. package/gs/compress/zlib/index.ts +164 -37
  203. package/gs/compress/zlib/meta.json +4 -1
  204. package/gs/compress/zlib/parity.json +51 -0
  205. package/gs/crypto/sha1/index.test.ts +19 -2
  206. package/gs/crypto/sha1/index.ts +3 -6
  207. package/gs/crypto/sha256/index.test.ts +14 -2
  208. package/gs/crypto/sha256/index.ts +3 -6
  209. package/gs/crypto/sha512/index.test.ts +17 -2
  210. package/gs/crypto/sha512/index.ts +3 -6
  211. package/gs/embed/index.test.ts +87 -0
  212. package/gs/embed/index.ts +229 -5
  213. package/gs/encoding/json/index.test.ts +360 -6
  214. package/gs/encoding/json/index.ts +679 -38
  215. package/gs/encoding/json/parity.json +81 -0
  216. package/gs/fmt/fmt.test.ts +41 -3
  217. package/gs/fmt/fmt.ts +40 -17
  218. package/gs/fmt/meta.json +6 -1
  219. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +211 -3
  220. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +857 -1
  221. package/gs/github.com/go-git/go-billy/v6/osfs/index.test.ts +110 -0
  222. package/gs/github.com/go-git/go-billy/v6/osfs/index.ts +280 -0
  223. package/gs/github.com/go-git/go-billy/v6/osfs/meta.json +8 -0
  224. package/gs/github.com/pkg/errors/errors.ts +54 -30
  225. package/gs/go/scanner/index.test.ts +39 -56
  226. package/gs/go/scanner/index.ts +33 -5
  227. package/gs/go/scanner/parity.json +27 -0
  228. package/gs/go/token/index.ts +22 -6
  229. package/gs/hash/index.test.ts +20 -33
  230. package/gs/hash/index.ts +28 -0
  231. package/gs/hash/parity.json +21 -0
  232. package/gs/internal/goarch/index.test.ts +32 -0
  233. package/gs/internal/goarch/index.ts +45 -13
  234. package/gs/internal/goarch/parity.json +144 -0
  235. package/gs/io/fs/fs.ts +26 -14
  236. package/gs/io/fs/readdir.test.ts +38 -0
  237. package/gs/io/fs/readdir.ts +8 -4
  238. package/gs/io/fs/sub.ts +8 -1
  239. package/gs/io/io.test.ts +77 -6
  240. package/gs/io/io.ts +115 -52
  241. package/gs/io/meta.json +7 -1
  242. package/gs/io/parity.json +162 -0
  243. package/gs/math/bits/index.test.ts +14 -1
  244. package/gs/math/bits/index.ts +75 -32
  245. package/gs/math/bits/parity.json +156 -0
  246. package/gs/mime/index.test.ts +90 -0
  247. package/gs/mime/index.ts +369 -6
  248. package/gs/mime/parity.json +36 -0
  249. package/gs/net/http/httptest/index.test.ts +98 -2
  250. package/gs/net/http/httptest/index.ts +101 -6
  251. package/gs/net/http/httptest/parity.json +15 -0
  252. package/gs/net/http/index.test.ts +797 -12
  253. package/gs/net/http/index.ts +1874 -136
  254. package/gs/net/http/meta.json +16 -1
  255. package/gs/net/http/parity.json +193 -0
  256. package/gs/os/dir_unix.gs.ts +1 -1
  257. package/gs/os/error.gs.ts +1 -1
  258. package/gs/os/exec.gs.ts +4 -8
  259. package/gs/os/exec_posix.gs.ts +1 -1
  260. package/gs/os/file_unix_js.test.ts +52 -0
  261. package/gs/os/index.test.ts +9 -0
  262. package/gs/os/index.ts +1 -0
  263. package/gs/os/meta.json +4 -0
  264. package/gs/os/parity.json +9 -0
  265. package/gs/os/proc.gs.ts +18 -5
  266. package/gs/os/proc.test.ts +26 -0
  267. package/gs/os/readdir.test.ts +56 -0
  268. package/gs/os/root_js.gs.ts +1 -1
  269. package/gs/os/types.gs.ts +1 -1
  270. package/gs/os/types_js.gs.ts +170 -9
  271. package/gs/os/types_unix.gs.ts +1 -1
  272. package/gs/path/path.ts +11 -7
  273. package/gs/reflect/deepequal.test.ts +10 -1
  274. package/gs/reflect/field.test.ts +37 -15
  275. package/gs/reflect/function-types.test.ts +518 -22
  276. package/gs/reflect/index.ts +8 -6
  277. package/gs/reflect/map.ts +20 -0
  278. package/gs/reflect/meta.json +6 -4
  279. package/gs/reflect/parity.json +234 -0
  280. package/gs/reflect/sliceat.test.ts +156 -0
  281. package/gs/reflect/structof.test.ts +401 -0
  282. package/gs/reflect/type.ts +1980 -365
  283. package/gs/reflect/typefor.test.ts +540 -10
  284. package/gs/reflect/types.ts +43 -18
  285. package/gs/reflect/value.ts +105 -45
  286. package/gs/reflect/visiblefields.ts +5 -168
  287. package/gs/runtime/parity.json +24 -0
  288. package/gs/runtime/pprof/index.test.ts +29 -7
  289. package/gs/runtime/pprof/index.ts +56 -30
  290. package/gs/runtime/pprof/parity.json +27 -0
  291. package/gs/runtime/runtime.test.ts +3 -1
  292. package/gs/runtime/runtime.ts +4 -3
  293. package/gs/runtime/trace/index.test.ts +5 -3
  294. package/gs/runtime/trace/index.ts +8 -20
  295. package/gs/runtime/trace/parity.json +36 -0
  296. package/gs/strconv/atoi.gs.ts +1 -1
  297. package/gs/strconv/complex.gs.ts +174 -0
  298. package/gs/strconv/complex.test.ts +65 -0
  299. package/gs/strconv/index.ts +1 -0
  300. package/gs/strconv/parity.json +120 -0
  301. package/gs/strings/builder.ts +1 -1
  302. package/gs/strings/meta.json +5 -2
  303. package/gs/strings/parity.json +186 -0
  304. package/gs/strings/reader.test.ts +2 -2
  305. package/gs/strings/reader.ts +11 -7
  306. package/gs/strings/replace.ts +15 -7
  307. package/gs/strings/strings.test.ts +22 -2
  308. package/gs/strings/strings.ts +64 -6
  309. package/gs/sync/atomic/type.gs.ts +9 -9
  310. package/gs/sync/atomic/value.gs.ts +2 -2
  311. package/gs/sync/meta.json +1 -0
  312. package/gs/sync/sync.test.ts +41 -1
  313. package/gs/sync/sync.ts +41 -16
  314. package/gs/syscall/env.ts +29 -14
  315. package/gs/syscall/js/index.test.ts +18 -0
  316. package/gs/syscall/js/index.ts +12 -0
  317. package/gs/testing/testing.test.ts +99 -3
  318. package/gs/testing/testing.ts +95 -24
  319. package/gs/time/parity.json +225 -0
  320. package/gs/time/time.test.ts +20 -2
  321. package/gs/time/time.ts +49 -7
  322. package/gs/unique/index.ts +7 -1
  323. package/package.json +4 -2
  324. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +0 -217
  325. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +0 -814
  326. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +0 -1
  327. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +0 -31
  328. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +0 -1233
  329. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +0 -46
  330. /package/compiler/{wasm_api.go → wasm-api.go} +0 -0
@@ -45,8 +45,14 @@ export interface MethodSignature {
45
45
  */
46
46
  export interface StructFieldInfo {
47
47
  type: TypeInfo | string // The field's type
48
- name?: string // The Go field name when it differs from the TypeScript key.
48
+ name: string // The Go field name.
49
+ key?: string // The runtime storage key on generated or dynamic values.
49
50
  tag?: string // The struct field tag (e.g., `json:"name,omitempty"`)
51
+ pkgPath?: string // Non-empty for unexported fields.
52
+ anonymous?: boolean
53
+ index?: number[]
54
+ offset?: number
55
+ exported?: boolean
50
56
  }
51
57
 
52
58
  /**
@@ -56,7 +62,7 @@ export interface StructTypeInfo extends BaseTypeInfo {
56
62
  kind: TypeKind.Struct
57
63
  methods: MethodSignature[] // Array of method signatures
58
64
  ctor?: new (...args: any[]) => any
59
- fields: Record<string, TypeInfo | string | StructFieldInfo> // Field names and types for struct fields
65
+ fields: StructFieldInfo[] // Ordered field descriptors.
60
66
  }
61
67
 
62
68
  /**
@@ -185,12 +191,13 @@ export function isChannelTypeInfo(info: TypeInfo): info is ChannelTypeInfo {
185
191
  * vs a direct TypeInfo or string
186
192
  */
187
193
  export function isStructFieldInfo(
188
- fieldValue: TypeInfo | string | StructFieldInfo,
194
+ fieldValue: unknown,
189
195
  ): fieldValue is StructFieldInfo {
190
196
  return (
191
197
  typeof fieldValue === 'object' &&
192
198
  fieldValue !== null &&
193
199
  'type' in fieldValue &&
200
+ 'name' in fieldValue &&
194
201
  !('kind' in fieldValue)
195
202
  )
196
203
  }
@@ -234,7 +241,7 @@ export const registerStructType = (
234
241
  zeroValue: any,
235
242
  methods: MethodSignature[],
236
243
  ctor: new (...args: any[]) => any,
237
- fields: Record<string, TypeInfo | string | StructFieldInfo> = {},
244
+ fields: StructFieldInfo[] = [],
238
245
  ): StructTypeInfo => {
239
246
  const typeInfo: StructTypeInfo = {
240
247
  name,
@@ -320,29 +327,69 @@ function typeInfoRuntimeName(info: TypeInfo): string | undefined {
320
327
  }
321
328
 
322
329
  function goTypeMatchesTypeInfo(goType: string, info: TypeInfo): boolean {
323
- return goType === typeInfoRuntimeName(info)
330
+ const runtimeName = typeInfoRuntimeName(info)
331
+ return (
332
+ (runtimeName !== undefined && goType === runtimeName) ||
333
+ compareTypeStringWithTypeInfo(goType, info)
334
+ )
335
+ }
336
+
337
+ interface TypeInfoComparisonState {
338
+ seenPairs: Set<string>
339
+ objectIDs: WeakMap<object, number>
340
+ nextObjectID: number
341
+ }
342
+
343
+ function newTypeInfoComparisonState(): TypeInfoComparisonState {
344
+ return {
345
+ seenPairs: new Set(),
346
+ objectIDs: new WeakMap(),
347
+ nextObjectID: 0,
348
+ }
349
+ }
350
+
351
+ function typeInfoComparisonID(
352
+ raw: string | TypeInfo,
353
+ normalized: TypeInfo,
354
+ state: TypeInfoComparisonState,
355
+ ): string {
356
+ const runtimeName = typeInfoRuntimeName(normalized)
357
+ if (runtimeName !== undefined) {
358
+ return `${normalized.kind}:${runtimeName}`
359
+ }
360
+ if (typeof raw === 'string') {
361
+ return `string:${raw}`
362
+ }
363
+ const existing = state.objectIDs.get(raw)
364
+ if (existing !== undefined) {
365
+ return `object:${existing}`
366
+ }
367
+ const id = state.nextObjectID
368
+ state.nextObjectID += 1
369
+ state.objectIDs.set(raw, id)
370
+ return `object:${id}`
324
371
  }
325
372
 
326
373
  function compareOptionalTypeInfo(
327
- type1?: string | TypeInfo,
328
- type2?: string | TypeInfo,
374
+ type1: string | TypeInfo | undefined,
375
+ type2: string | TypeInfo | undefined,
376
+ state: TypeInfoComparisonState,
329
377
  ): boolean {
330
378
  if (type1 === undefined && type2 === undefined) return true
331
379
  if (type1 === undefined || type2 === undefined) return false
332
- // Assuming areTypeInfosIdentical will handle normalization if needed,
333
- // but type1 and type2 here are expected to be direct fields from TypeInfo objects.
334
- return areTypeInfosIdentical(type1, type2)
380
+ return areTypeInfosIdenticalWithSeen(type1, type2, state)
335
381
  }
336
382
 
337
383
  function areFuncParamOrResultArraysIdentical(
338
384
  arr1?: (string | TypeInfo)[],
339
385
  arr2?: (string | TypeInfo)[],
386
+ state = newTypeInfoComparisonState(),
340
387
  ): boolean {
341
388
  if (arr1 === undefined && arr2 === undefined) return true
342
389
  if (arr1 === undefined || arr2 === undefined) return false
343
390
  if (arr1.length !== arr2.length) return false
344
- for (let i = 0; i < arr1.length; i++) {
345
- if (!areTypeInfosIdentical(arr1[i], arr2[i])) {
391
+ for (const [index, typeInfo] of arr1.entries()) {
392
+ if (!areTypeInfosIdenticalWithSeen(typeInfo, arr2[index], state)) {
346
393
  return false
347
394
  }
348
395
  }
@@ -352,58 +399,75 @@ function areFuncParamOrResultArraysIdentical(
352
399
  function areFuncSignaturesIdentical(
353
400
  func1: FunctionTypeInfo,
354
401
  func2: FunctionTypeInfo,
402
+ state = newTypeInfoComparisonState(),
355
403
  ): boolean {
356
404
  if ((func1.isVariadic || false) !== (func2.isVariadic || false)) {
357
405
  return false
358
406
  }
359
407
  return (
360
- areFuncParamOrResultArraysIdentical(func1.params, func2.params) &&
361
- areFuncParamOrResultArraysIdentical(func1.results, func2.results)
408
+ areFuncParamOrResultArraysIdentical(func1.params, func2.params, state) &&
409
+ areFuncParamOrResultArraysIdentical(func1.results, func2.results, state)
362
410
  )
363
411
  }
364
412
 
365
413
  export function areTypeInfosIdentical(
366
414
  type1InfoOrName: string | TypeInfo,
367
415
  type2InfoOrName: string | TypeInfo,
416
+ ): boolean {
417
+ return areTypeInfosIdenticalWithSeen(
418
+ type1InfoOrName,
419
+ type2InfoOrName,
420
+ newTypeInfoComparisonState(),
421
+ )
422
+ }
423
+
424
+ function areTypeInfosIdenticalWithSeen(
425
+ type1InfoOrName: string | TypeInfo,
426
+ type2InfoOrName: string | TypeInfo,
427
+ state: TypeInfoComparisonState,
368
428
  ): boolean {
369
429
  const t1Norm = normalizeTypeInfo(type1InfoOrName)
370
430
  const t2Norm = normalizeTypeInfo(type2InfoOrName)
371
431
 
372
- if (t1Norm === t2Norm) return true // Object identity
432
+ if (t1Norm === t2Norm) return true
373
433
  if (t1Norm.kind !== t2Norm.kind) return false
374
434
 
375
- // If types have names, the names must match for identity.
376
- // If one has a name and the other doesn't, they are not identical.
435
+ if ((t1Norm.typeName ?? '') !== (t2Norm.typeName ?? '')) return false
377
436
  if (t1Norm.name !== t2Norm.name) return false
378
437
 
379
- // If both are named and names match, for Basic, Struct, Interface, this is sufficient for identity.
380
438
  if (
381
- t1Norm.name !== undefined /* && t2Norm.name is also defined and equal */
382
- ) {
383
- if (
384
- t1Norm.kind === TypeKind.Basic ||
439
+ t1Norm.name !== undefined &&
440
+ (t1Norm.kind === TypeKind.Basic ||
385
441
  t1Norm.kind === TypeKind.Struct ||
386
- t1Norm.kind === TypeKind.Interface
387
- ) {
388
- return true
389
- }
442
+ t1Norm.kind === TypeKind.Interface)
443
+ ) {
444
+ return true
445
+ }
446
+
447
+ const pairKey = `${typeInfoComparisonID(
448
+ type1InfoOrName,
449
+ t1Norm,
450
+ state,
451
+ )}|${typeInfoComparisonID(type2InfoOrName, t2Norm, state)}`
452
+ if (state.seenPairs.has(pairKey)) {
453
+ return true
390
454
  }
391
- // For other types (Pointer, Slice, etc.), or if both are anonymous (name is undefined),
392
- // structural comparison is needed.
455
+ state.seenPairs.add(pairKey)
393
456
 
394
457
  switch (t1Norm.kind) {
395
458
  case TypeKind.Basic:
396
- // Names matched if they were defined, or both undefined (which means true by t1Norm.name !== t2Norm.name being false)
397
459
  return true
398
460
  case TypeKind.Pointer:
399
461
  return compareOptionalTypeInfo(
400
462
  (t1Norm as PointerTypeInfo).elemType,
401
463
  (t2Norm as PointerTypeInfo).elemType,
464
+ state,
402
465
  )
403
466
  case TypeKind.Slice:
404
467
  return compareOptionalTypeInfo(
405
468
  (t1Norm as SliceTypeInfo).elemType,
406
469
  (t2Norm as SliceTypeInfo).elemType,
470
+ state,
407
471
  )
408
472
  case TypeKind.Array:
409
473
  return (
@@ -411,6 +475,7 @@ export function areTypeInfosIdentical(
411
475
  compareOptionalTypeInfo(
412
476
  (t1Norm as ArrayTypeInfo).elemType,
413
477
  (t2Norm as ArrayTypeInfo).elemType,
478
+ state,
414
479
  )
415
480
  )
416
481
  case TypeKind.Map:
@@ -418,39 +483,119 @@ export function areTypeInfosIdentical(
418
483
  compareOptionalTypeInfo(
419
484
  (t1Norm as MapTypeInfo).keyType,
420
485
  (t2Norm as MapTypeInfo).keyType,
486
+ state,
421
487
  ) &&
422
488
  compareOptionalTypeInfo(
423
489
  (t1Norm as MapTypeInfo).elemType,
424
490
  (t2Norm as MapTypeInfo).elemType,
491
+ state,
425
492
  )
426
493
  )
427
494
  case TypeKind.Channel:
428
495
  return (
429
- // Ensure direction property exists before comparing, or handle undefined if it can be
430
496
  ((t1Norm as ChannelTypeInfo).direction || 'both') ===
431
497
  ((t2Norm as ChannelTypeInfo).direction || 'both') &&
432
498
  compareOptionalTypeInfo(
433
499
  (t1Norm as ChannelTypeInfo).elemType,
434
500
  (t2Norm as ChannelTypeInfo).elemType,
501
+ state,
435
502
  )
436
503
  )
437
504
  case TypeKind.Function:
438
505
  return areFuncSignaturesIdentical(
439
506
  t1Norm as FunctionTypeInfo,
440
507
  t2Norm as FunctionTypeInfo,
508
+ state,
441
509
  )
442
510
  case TypeKind.Struct:
511
+ if (t2Norm.kind !== TypeKind.Struct) {
512
+ return false
513
+ }
514
+ return areStructTypeInfosIdentical(t1Norm, t2Norm, state)
443
515
  case TypeKind.Interface:
444
- // If we reach here, names were undefined (both anonymous) or names matched but was not Basic/Struct/Interface.
445
- // For anonymous Struct/Interface, strict identity means full structural comparison.
446
- // For now, we consider anonymous types not identical unless they are the same object (caught above).
447
- // If they were named and matched, 'return true' was hit earlier for these kinds.
448
- return false
516
+ if (t2Norm.kind !== TypeKind.Interface) {
517
+ return false
518
+ }
519
+ return areInterfaceTypeInfosIdentical(t1Norm, t2Norm, state)
449
520
  default:
450
521
  return false
451
522
  }
452
523
  }
453
524
 
525
+ function areStructTypeInfosIdentical(
526
+ struct1: StructTypeInfo,
527
+ struct2: StructTypeInfo,
528
+ state: TypeInfoComparisonState,
529
+ ): boolean {
530
+ if (struct1.fields.length !== struct2.fields.length) {
531
+ return false
532
+ }
533
+ for (const [index, field1] of struct1.fields.entries()) {
534
+ const field2 = struct2.fields[index]
535
+ if (
536
+ field2 === undefined ||
537
+ field1.name !== field2.name ||
538
+ (field1.pkgPath ?? '') !== (field2.pkgPath ?? '') ||
539
+ (field1.tag ?? '') !== (field2.tag ?? '') ||
540
+ (field1.anonymous ?? false) !== (field2.anonymous ?? false) ||
541
+ !areTypeInfosIdenticalWithSeen(field1.type, field2.type, state)
542
+ ) {
543
+ return false
544
+ }
545
+ }
546
+ return true
547
+ }
548
+
549
+ function areInterfaceTypeInfosIdentical(
550
+ interface1: InterfaceTypeInfo,
551
+ interface2: InterfaceTypeInfo,
552
+ state: TypeInfoComparisonState,
553
+ ): boolean {
554
+ const methods1 = sortedMethodSignatures(interface1.methods)
555
+ const methods2 = sortedMethodSignatures(interface2.methods)
556
+ if (methods1.length !== methods2.length) {
557
+ return false
558
+ }
559
+ for (const [index, method1] of methods1.entries()) {
560
+ const method2 = methods2[index]
561
+ if (
562
+ method2 === undefined ||
563
+ method1.name !== method2.name ||
564
+ !areMethodArgArraysIdentical(method1.args, method2.args, state) ||
565
+ !areMethodArgArraysIdentical(method1.returns, method2.returns, state)
566
+ ) {
567
+ return false
568
+ }
569
+ }
570
+ return true
571
+ }
572
+
573
+ function sortedMethodSignatures(
574
+ methods: MethodSignature[] = [],
575
+ ): MethodSignature[] {
576
+ return [...methods].sort((left, right) => left.name.localeCompare(right.name))
577
+ }
578
+
579
+ function areMethodArgArraysIdentical(
580
+ args1: MethodArg[],
581
+ args2: MethodArg[],
582
+ state: TypeInfoComparisonState,
583
+ ): boolean {
584
+ if (args1.length !== args2.length) {
585
+ return false
586
+ }
587
+ for (const [index, arg1] of args1.entries()) {
588
+ const arg2 = args2[index]
589
+ if (
590
+ arg2 === undefined ||
591
+ !areTypeInfosIdenticalWithSeen(arg1.type, arg2.type, state)
592
+ ) {
593
+ return false
594
+ }
595
+ }
596
+ return true
597
+ }
598
+
454
599
  /**
455
600
  * Validates that a map key matches the expected type info.
456
601
  *
@@ -487,7 +632,23 @@ function validateMapKey(key: any, keyTypeInfo: TypeInfo): boolean {
487
632
  */
488
633
  function matchesBasicType(value: any, info: TypeInfo): boolean {
489
634
  if (info.name === 'string') return typeof value === 'string'
490
- if (info.name === 'number' || info.name === 'int' || info.name === 'float64')
635
+ if (
636
+ info.name === 'number' ||
637
+ info.name === 'int' ||
638
+ info.name === 'int8' ||
639
+ info.name === 'int16' ||
640
+ info.name === 'int32' ||
641
+ info.name === 'int64' ||
642
+ info.name === 'uint' ||
643
+ info.name === 'uint8' ||
644
+ info.name === 'byte' ||
645
+ info.name === 'uint16' ||
646
+ info.name === 'uint32' ||
647
+ info.name === 'uint64' ||
648
+ info.name === 'uintptr' ||
649
+ info.name === 'float32' ||
650
+ info.name === 'float64'
651
+ )
491
652
  return typeof value === 'number'
492
653
  if (info.name === 'boolean' || info.name === 'bool')
493
654
  return typeof value === 'boolean'
@@ -519,7 +680,8 @@ function matchesStructType(value: any, info: TypeInfo): boolean {
519
680
 
520
681
  // For anonymous struct types (no constructor), use structural matching
521
682
  if (typeof value === 'object' && value !== null && info.fields) {
522
- const fieldNames = Object.keys(info.fields || {})
683
+ const fields = info.fields || []
684
+ const fieldNames = fields.map((field) => structFieldRuntimeKey(field))
523
685
  const valueFields = Object.keys(value)
524
686
 
525
687
  const fieldsExist = fieldNames.every((field) => field in value)
@@ -529,10 +691,9 @@ function matchesStructType(value: any, info: TypeInfo): boolean {
529
691
  )
530
692
 
531
693
  if (fieldsExist && sameFieldCount && allFieldsInStruct) {
532
- return Object.entries(info.fields).every(([fieldName, fieldType]) => {
533
- const fieldTypeInfo =
534
- isStructFieldInfo(fieldType) ? fieldType.type : fieldType
535
- return matchesType(value[fieldName], normalizeTypeInfo(fieldTypeInfo))
694
+ return fields.every((field) => {
695
+ const key = structFieldRuntimeKey(field)
696
+ return matchesType(value[key], normalizeTypeInfo(field.type))
536
697
  })
537
698
  }
538
699
 
@@ -542,6 +703,10 @@ function matchesStructType(value: any, info: TypeInfo): boolean {
542
703
  return false
543
704
  }
544
705
 
706
+ export function structFieldRuntimeKey(field: StructFieldInfo): string {
707
+ return field.key || field.name
708
+ }
709
+
545
710
  /**
546
711
  * Checks if a value matches an interface type info by verifying it implements
547
712
  * all required methods with compatible signatures.
@@ -859,17 +1024,30 @@ function matchesPointerType(value: any, info: TypeInfo): boolean {
859
1024
  * @returns True if the value matches the function type, false otherwise.
860
1025
  */
861
1026
  function matchesFunctionType(value: any, info: FunctionTypeInfo): boolean {
862
- // First check if the value is a function
863
1027
  if (typeof value !== 'function') {
864
1028
  return false
865
1029
  }
866
-
867
- // This is important for named function types
868
- if (info.name && value.__goTypeName) {
869
- return info.name === value.__goTypeName
1030
+ const valueInfo = functionValueTypeInfo(value)
1031
+ if (!valueInfo) {
1032
+ return false
870
1033
  }
1034
+ return areTypeInfosIdentical(valueInfo, info)
1035
+ }
871
1036
 
872
- return true
1037
+ function functionValueTypeInfo(value: any): FunctionTypeInfo | null {
1038
+ const typeInfo = value.__typeInfo
1039
+ if (!typeInfo || typeInfo.kind !== TypeKind.Function) {
1040
+ return null
1041
+ }
1042
+ const goTypeName =
1043
+ typeof value.__goTypeName === 'string' ? value.__goTypeName : undefined
1044
+ if (goTypeName && typeInfo.name && goTypeName !== typeInfo.name) {
1045
+ return null
1046
+ }
1047
+ if (goTypeName && !typeInfo.name) {
1048
+ return { ...typeInfo, name: goTypeName }
1049
+ }
1050
+ return typeInfo
873
1051
  }
874
1052
 
875
1053
  /**
@@ -994,15 +1172,21 @@ function matchesType(value: any, info: TypeInfo): boolean {
994
1172
  */
995
1173
  function compareTypeStringWithTypeInfo(
996
1174
  typeStr: string,
997
- typeInfo: TypeInfo,
1175
+ typeInfo: string | TypeInfo,
998
1176
  ): boolean {
1177
+ const normalized = normalizeTypeInfo(typeInfo)
1178
+ const runtimeName = typeInfoRuntimeName(normalized)
1179
+ if (runtimeName !== undefined && typeStr === runtimeName) {
1180
+ return true
1181
+ }
1182
+
999
1183
  // For pointer types, strip the leading * and compare element types
1000
- if (isPointerTypeInfo(typeInfo)) {
1184
+ if (isPointerTypeInfo(normalized)) {
1001
1185
  if (!typeStr.startsWith('*')) {
1002
1186
  return false
1003
1187
  }
1004
1188
  const elemStr = typeStr.slice(1)
1005
- const elemType = typeInfo.elemType
1189
+ const elemType = normalized.elemType
1006
1190
  if (!elemType) {
1007
1191
  return false
1008
1192
  }
@@ -1036,8 +1220,8 @@ function compareTypeStringWithTypeInfo(
1036
1220
  }
1037
1221
 
1038
1222
  // Compare fields
1039
- const typeInfoFields = elemTypeInfo.fields || {}
1040
- const typeInfoFieldNames = Object.keys(typeInfoFields)
1223
+ const typeInfoFields = elemTypeInfo.fields || []
1224
+ const typeInfoFieldNames = typeInfoFields.map((field) => field.name)
1041
1225
  const parsedFieldNames = Object.keys(parsedFields)
1042
1226
 
1043
1227
  if (typeInfoFieldNames.length !== parsedFieldNames.length) {
@@ -1045,16 +1229,13 @@ function compareTypeStringWithTypeInfo(
1045
1229
  }
1046
1230
 
1047
1231
  // Check if all field names match and types are compatible
1048
- for (const fieldName of typeInfoFieldNames) {
1232
+ for (const field of typeInfoFields) {
1233
+ const fieldName = field.name
1049
1234
  if (!(fieldName in parsedFields)) {
1050
1235
  return false
1051
1236
  }
1052
1237
 
1053
- const fieldValue = typeInfoFields[fieldName]
1054
- // Handle StructFieldInfo (which has 'type' and optional 'tag' properties)
1055
- const fieldTypeInfo: TypeInfo | string =
1056
- isStructFieldInfo(fieldValue) ? fieldValue.type : fieldValue
1057
- const typeInfoFieldType = normalizeTypeInfo(fieldTypeInfo)
1238
+ const typeInfoFieldType = normalizeTypeInfo(field.type)
1058
1239
  const parsedFieldType = parsedFields[fieldName]
1059
1240
 
1060
1241
  // Compare basic types
@@ -1081,9 +1262,58 @@ function compareTypeStringWithTypeInfo(
1081
1262
  if (typeof elemType === 'string') {
1082
1263
  return elemStr === elemType
1083
1264
  }
1084
- if (elemType.name) {
1085
- return elemStr === elemType.name
1265
+ return compareTypeStringWithTypeInfo(elemStr, elemType)
1266
+ }
1267
+
1268
+ if (isSliceTypeInfo(normalized)) {
1269
+ if (!typeStr.startsWith('[]') || !normalized.elemType) {
1270
+ return false
1271
+ }
1272
+ return compareTypeStringWithTypeInfo(typeStr.slice(2), normalized.elemType)
1273
+ }
1274
+
1275
+ if (isArrayTypeInfo(normalized)) {
1276
+ const match = typeStr.match(/^\[(\d+)\](.+)$/)
1277
+ if (!match || !normalized.elemType) {
1278
+ return false
1086
1279
  }
1280
+ return (
1281
+ Number(match[1]) === normalized.length &&
1282
+ compareTypeStringWithTypeInfo(match[2], normalized.elemType)
1283
+ )
1284
+ }
1285
+
1286
+ if (isBasicTypeInfo(normalized)) {
1287
+ const name = typeInfoRuntimeName(normalized)
1288
+ if (name === undefined) {
1289
+ return false
1290
+ }
1291
+ if (typeStr === name) {
1292
+ return true
1293
+ }
1294
+ if (name === 'uint8' && typeStr === 'byte') {
1295
+ return true
1296
+ }
1297
+ if (name === 'int32' && typeStr === 'rune') {
1298
+ return true
1299
+ }
1300
+ return (
1301
+ name === 'int' &&
1302
+ [
1303
+ 'byte',
1304
+ 'rune',
1305
+ 'int8',
1306
+ 'int16',
1307
+ 'int32',
1308
+ 'int64',
1309
+ 'uint',
1310
+ 'uint8',
1311
+ 'uint16',
1312
+ 'uint32',
1313
+ 'uint64',
1314
+ 'uintptr',
1315
+ ].includes(typeStr)
1316
+ )
1087
1317
  }
1088
1318
 
1089
1319
  return false
@@ -1369,10 +1599,12 @@ export function namedValueInterfaceValue<T>(
1369
1599
  value: unknown,
1370
1600
  typeName: string,
1371
1601
  methods: Record<string, (receiver: any, ...args: any[]) => any>,
1602
+ typeInfo?: TypeInfo | string,
1372
1603
  ): T {
1373
1604
  const boxed: any = {
1374
1605
  __goType: typeName,
1375
1606
  __goValue: value,
1607
+ __goTypeInfo: typeInfo,
1376
1608
  valueOf: () => value,
1377
1609
  toString: () => String(value),
1378
1610
  [Symbol.toPrimitive]: () => value as any,
@@ -1383,24 +1615,39 @@ export function namedValueInterfaceValue<T>(
1383
1615
  return boxed as T
1384
1616
  }
1385
1617
 
1386
- export function namedFunction<T>(fn: T, typeName: string): T {
1618
+ export function namedFunction<T>(
1619
+ fn: T,
1620
+ typeName: string,
1621
+ typeInfo?: FunctionTypeInfo,
1622
+ ): T {
1387
1623
  if (typeof fn !== 'function') {
1388
1624
  return fn
1389
1625
  }
1390
- return Object.assign(fn, { __goTypeName: typeName })
1626
+ return Object.assign(
1627
+ fn,
1628
+ typeInfo ?
1629
+ { __goTypeName: typeName, __typeInfo: typeInfo }
1630
+ : { __goTypeName: typeName },
1631
+ )
1391
1632
  }
1392
1633
 
1393
1634
  export function functionValue<T extends (...args: any[]) => any>(
1394
1635
  fn: T,
1395
1636
  typeInfo: FunctionTypeInfo,
1396
1637
  ): T {
1397
- return Object.assign(fn, { __typeInfo: typeInfo })
1638
+ return Object.assign(
1639
+ fn,
1640
+ typeInfo.name ?
1641
+ { __typeInfo: typeInfo, __goTypeName: typeInfo.name }
1642
+ : { __typeInfo: typeInfo },
1643
+ )
1398
1644
  }
1399
1645
 
1400
1646
  export interface GenericTypeDescriptor<T = any> {
1401
1647
  type?: TypeInfo | string
1402
1648
  zero?: () => T
1403
1649
  methods?: Record<string, (receiver: T, ...args: any[]) => any>
1650
+ methodSignatures?: MethodSignature[]
1404
1651
  }
1405
1652
 
1406
1653
  export type GenericTypeArgs = Record<string, GenericTypeDescriptor>