goscript 0.1.0 → 0.1.1

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 (327) hide show
  1. package/README.md +267 -255
  2. package/cmd/goscript/cmd-test.go +193 -0
  3. package/cmd/goscript/cmd-test_test.go +76 -0
  4. package/cmd/goscript/main.go +1 -0
  5. package/compiler/build-flags.go +38 -0
  6. package/compiler/compile-request.go +2 -0
  7. package/compiler/compliance_test.go +0 -8
  8. package/compiler/gotest/owner.go +24 -0
  9. package/compiler/gotest/package-result.go +67 -0
  10. package/compiler/gotest/request.go +145 -0
  11. package/compiler/gotest/result.go +28 -0
  12. package/compiler/gotest/runner.go +588 -0
  13. package/compiler/gotest/runner_test.go +627 -0
  14. package/compiler/gotest/test.go +9 -0
  15. package/compiler/index.test.ts +1 -1
  16. package/compiler/lowered-program.go +71 -19
  17. package/compiler/lowering.go +5065 -569
  18. package/compiler/override-facts.go +307 -0
  19. package/compiler/override-registry.go +50 -189
  20. package/compiler/override-registry_test.go +47 -0
  21. package/compiler/package-graph.go +50 -27
  22. package/compiler/package-graph_test.go +37 -2
  23. package/compiler/package-test-function.go +9 -0
  24. package/compiler/package-test-graph-package.go +40 -0
  25. package/compiler/package-test-graph-variant.go +105 -0
  26. package/compiler/package-test-graph.go +117 -0
  27. package/compiler/package-test-graph_test.go +144 -0
  28. package/compiler/runtime-contract.go +189 -29
  29. package/compiler/runtime-contract_test.go +44 -30
  30. package/compiler/semantic-model-types.go +9 -6
  31. package/compiler/semantic-model.go +538 -38
  32. package/compiler/semantic-model_test.go +55 -0
  33. package/compiler/service.go +1 -1
  34. package/compiler/skeleton_test.go +679 -49
  35. package/compiler/tsworkspace/owner.go +334 -0
  36. package/compiler/tsworkspace/owner_test.go +93 -0
  37. package/compiler/tsworkspace/result.go +17 -0
  38. package/compiler/typescript-emitter.go +459 -82
  39. package/compiler/wasm/compile.go +1 -1
  40. package/compiler/wasm/compile_test.go +61 -11
  41. package/compiler/wasm_api.go +172 -7
  42. package/dist/gs/builtin/builtin.d.ts +20 -2
  43. package/dist/gs/builtin/builtin.js +194 -6
  44. package/dist/gs/builtin/builtin.js.map +1 -1
  45. package/dist/gs/builtin/channel.d.ts +8 -0
  46. package/dist/gs/builtin/channel.js +12 -0
  47. package/dist/gs/builtin/channel.js.map +1 -1
  48. package/dist/gs/builtin/slice.d.ts +22 -2
  49. package/dist/gs/builtin/slice.js +216 -44
  50. package/dist/gs/builtin/slice.js.map +1 -1
  51. package/dist/gs/builtin/type.d.ts +5 -2
  52. package/dist/gs/builtin/type.js +83 -24
  53. package/dist/gs/builtin/type.js.map +1 -1
  54. package/dist/gs/builtin/varRef.d.ts +5 -0
  55. package/dist/gs/builtin/varRef.js +23 -0
  56. package/dist/gs/builtin/varRef.js.map +1 -1
  57. package/dist/gs/bytes/buffer.gs.js +48 -44
  58. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  59. package/dist/gs/bytes/reader.gs.js +20 -18
  60. package/dist/gs/bytes/reader.gs.js.map +1 -1
  61. package/dist/gs/context/context.d.ts +5 -4
  62. package/dist/gs/context/context.js +10 -10
  63. package/dist/gs/context/context.js.map +1 -1
  64. package/dist/gs/crypto/internal/fips140deps/byteorder/index.d.ts +1 -0
  65. package/dist/gs/crypto/internal/fips140deps/byteorder/index.js +2 -0
  66. package/dist/gs/crypto/internal/fips140deps/byteorder/index.js.map +1 -0
  67. package/dist/gs/crypto/internal/fips140deps/godebug/index.d.ts +1 -0
  68. package/dist/gs/crypto/internal/fips140deps/godebug/index.js +2 -0
  69. package/dist/gs/crypto/internal/fips140deps/godebug/index.js.map +1 -0
  70. package/dist/gs/embed/index.d.ts +7 -0
  71. package/dist/gs/embed/index.js +16 -0
  72. package/dist/gs/embed/index.js.map +1 -0
  73. package/dist/gs/encoding/json/index.d.ts +1 -0
  74. package/dist/gs/encoding/json/index.js +18 -0
  75. package/dist/gs/encoding/json/index.js.map +1 -1
  76. package/dist/gs/errors/errors.d.ts +4 -0
  77. package/dist/gs/errors/errors.js +81 -0
  78. package/dist/gs/errors/errors.js.map +1 -1
  79. package/dist/gs/fmt/fmt.d.ts +4 -4
  80. package/dist/gs/fmt/fmt.js +42 -11
  81. package/dist/gs/fmt/fmt.js.map +1 -1
  82. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +35 -0
  83. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +211 -1
  84. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  85. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.d.ts +189 -0
  86. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js +825 -0
  87. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js.map +1 -0
  88. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +163 -0
  89. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +449 -0
  90. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +1 -0
  91. package/dist/gs/github.com/klauspost/compress/internal/le/index.d.ts +9 -0
  92. package/dist/gs/github.com/klauspost/compress/internal/le/index.js +71 -0
  93. package/dist/gs/github.com/klauspost/compress/internal/le/index.js.map +1 -0
  94. package/dist/gs/go/internal/scannerhooks/index.d.ts +3 -0
  95. package/dist/gs/go/internal/scannerhooks/index.js +5 -0
  96. package/dist/gs/go/internal/scannerhooks/index.js.map +1 -0
  97. package/dist/gs/go/scanner/index.d.ts +13 -0
  98. package/dist/gs/go/scanner/index.js +35 -0
  99. package/dist/gs/go/scanner/index.js.map +1 -1
  100. package/dist/gs/go/token/index.d.ts +156 -0
  101. package/dist/gs/go/token/index.js +500 -4
  102. package/dist/gs/go/token/index.js.map +1 -1
  103. package/dist/gs/internal/abi/index.d.ts +4 -0
  104. package/dist/gs/internal/abi/index.js +10 -0
  105. package/dist/gs/internal/abi/index.js.map +1 -1
  106. package/dist/gs/internal/bytealg/index.d.ts +2 -0
  107. package/dist/gs/internal/bytealg/index.js +14 -0
  108. package/dist/gs/internal/bytealg/index.js.map +1 -1
  109. package/dist/gs/internal/byteorder/index.d.ts +8 -2
  110. package/dist/gs/internal/byteorder/index.js +56 -25
  111. package/dist/gs/internal/byteorder/index.js.map +1 -1
  112. package/dist/gs/internal/godebug/index.d.ts +12 -0
  113. package/dist/gs/internal/godebug/index.js +30 -0
  114. package/dist/gs/internal/godebug/index.js.map +1 -0
  115. package/dist/gs/io/fs/index.d.ts +1 -0
  116. package/dist/gs/io/fs/index.js +1 -0
  117. package/dist/gs/io/fs/index.js.map +1 -1
  118. package/dist/gs/io/fs/readlink.d.ts +8 -0
  119. package/dist/gs/io/fs/readlink.js +64 -0
  120. package/dist/gs/io/fs/readlink.js.map +1 -0
  121. package/dist/gs/io/fs/walk.d.ts +3 -3
  122. package/dist/gs/io/fs/walk.js +7 -7
  123. package/dist/gs/io/fs/walk.js.map +1 -1
  124. package/dist/gs/io/io.d.ts +40 -6
  125. package/dist/gs/io/io.js +151 -26
  126. package/dist/gs/io/io.js.map +1 -1
  127. package/dist/gs/maps/iter.d.ts +3 -3
  128. package/dist/gs/maps/iter.js +3 -3
  129. package/dist/gs/maps/iter.js.map +1 -1
  130. package/dist/gs/maps/maps.d.ts +2 -2
  131. package/dist/gs/maps/maps.js +1 -1
  132. package/dist/gs/maps/maps.js.map +1 -1
  133. package/dist/gs/math/bits/index.d.ts +13 -4
  134. package/dist/gs/math/bits/index.js +66 -34
  135. package/dist/gs/math/bits/index.js.map +1 -1
  136. package/dist/gs/math/const.gs.d.ts +5 -5
  137. package/dist/gs/math/const.gs.js +4 -4
  138. package/dist/gs/math/const.gs.js.map +1 -1
  139. package/dist/gs/mime/index.d.ts +1 -0
  140. package/dist/gs/mime/index.js +50 -0
  141. package/dist/gs/mime/index.js.map +1 -0
  142. package/dist/gs/net/http/httptest/index.d.ts +11 -0
  143. package/dist/gs/net/http/httptest/index.js +21 -0
  144. package/dist/gs/net/http/httptest/index.js.map +1 -0
  145. package/dist/gs/net/http/index.d.ts +27 -0
  146. package/dist/gs/net/http/index.js +61 -0
  147. package/dist/gs/net/http/index.js.map +1 -0
  148. package/dist/gs/os/dir_unix.gs.js +2 -2
  149. package/dist/gs/os/dir_unix.gs.js.map +1 -1
  150. package/dist/gs/os/types_js.gs.js.map +1 -1
  151. package/dist/gs/path/filepath/match.js +165 -3
  152. package/dist/gs/path/filepath/match.js.map +1 -1
  153. package/dist/gs/path/filepath/path.d.ts +3 -1
  154. package/dist/gs/path/filepath/path.js +133 -4
  155. package/dist/gs/path/filepath/path.js.map +1 -1
  156. package/dist/gs/path/path.d.ts +4 -1
  157. package/dist/gs/path/path.js +16 -4
  158. package/dist/gs/path/path.js.map +1 -1
  159. package/dist/gs/reflect/index.d.ts +1 -1
  160. package/dist/gs/reflect/index.js +1 -1
  161. package/dist/gs/reflect/index.js.map +1 -1
  162. package/dist/gs/reflect/map.js +3 -0
  163. package/dist/gs/reflect/map.js.map +1 -1
  164. package/dist/gs/reflect/type.d.ts +7 -4
  165. package/dist/gs/reflect/type.js +148 -7
  166. package/dist/gs/reflect/type.js.map +1 -1
  167. package/dist/gs/runtime/debug/index.d.ts +2 -0
  168. package/dist/gs/runtime/debug/index.js +8 -0
  169. package/dist/gs/runtime/debug/index.js.map +1 -0
  170. package/dist/gs/runtime/runtime.d.ts +35 -3
  171. package/dist/gs/runtime/runtime.js +72 -0
  172. package/dist/gs/runtime/runtime.js.map +1 -1
  173. package/dist/gs/slices/slices.d.ts +24 -5
  174. package/dist/gs/slices/slices.js +214 -5
  175. package/dist/gs/slices/slices.js.map +1 -1
  176. package/dist/gs/sort/slice.gs.d.ts +3 -3
  177. package/dist/gs/sort/slice.gs.js +6 -6
  178. package/dist/gs/sort/slice.gs.js.map +1 -1
  179. package/dist/gs/sort/sort.gs.d.ts +4 -4
  180. package/dist/gs/sort/sort.gs.js +11 -8
  181. package/dist/gs/sort/sort.gs.js.map +1 -1
  182. package/dist/gs/strings/builder.d.ts +1 -1
  183. package/dist/gs/strings/builder.js +3 -2
  184. package/dist/gs/strings/builder.js.map +1 -1
  185. package/dist/gs/sync/atomic/type.gs.d.ts +9 -8
  186. package/dist/gs/sync/atomic/type.gs.js +0 -2
  187. package/dist/gs/sync/atomic/type.gs.js.map +1 -1
  188. package/dist/gs/sync/sync.d.ts +2 -0
  189. package/dist/gs/sync/sync.js +27 -0
  190. package/dist/gs/sync/sync.js.map +1 -1
  191. package/dist/gs/syscall/constants.d.ts +36 -24
  192. package/dist/gs/syscall/constants.js +12 -0
  193. package/dist/gs/syscall/constants.js.map +1 -1
  194. package/dist/gs/syscall/errors.d.ts +2 -0
  195. package/dist/gs/syscall/errors.js +8 -0
  196. package/dist/gs/syscall/errors.js.map +1 -1
  197. package/dist/gs/syscall/fs.d.ts +43 -0
  198. package/dist/gs/syscall/fs.js +102 -0
  199. package/dist/gs/syscall/fs.js.map +1 -1
  200. package/dist/gs/syscall/js/index.d.ts +90 -0
  201. package/dist/gs/syscall/js/index.js +375 -0
  202. package/dist/gs/syscall/js/index.js.map +1 -0
  203. package/dist/gs/syscall/types.d.ts +22 -0
  204. package/dist/gs/syscall/types.js +45 -1
  205. package/dist/gs/syscall/types.js.map +1 -1
  206. package/dist/gs/testing/index.d.ts +1 -0
  207. package/dist/gs/testing/index.js +2 -0
  208. package/dist/gs/testing/index.js.map +1 -0
  209. package/dist/gs/testing/testing.d.ts +77 -0
  210. package/dist/gs/testing/testing.js +301 -0
  211. package/dist/gs/testing/testing.js.map +1 -0
  212. package/dist/gs/time/time.d.ts +41 -4
  213. package/dist/gs/time/time.js +205 -36
  214. package/dist/gs/time/time.js.map +1 -1
  215. package/dist/gs/unicode/unicode.d.ts +23 -1
  216. package/dist/gs/unicode/unicode.js +79 -10
  217. package/dist/gs/unicode/unicode.js.map +1 -1
  218. package/dist/gs/unicode/utf8/utf8.d.ts +4 -4
  219. package/dist/gs/unicode/utf8/utf8.js +24 -11
  220. package/dist/gs/unicode/utf8/utf8.js.map +1 -1
  221. package/dist/gs/unique/index.d.ts +11 -0
  222. package/dist/gs/unique/index.js +71 -0
  223. package/dist/gs/unique/index.js.map +1 -0
  224. package/go.sum +9 -0
  225. package/gs/builtin/builtin.ts +239 -8
  226. package/gs/builtin/channel.ts +22 -0
  227. package/gs/builtin/runtime-contract.test.ts +126 -0
  228. package/gs/builtin/slice.ts +259 -50
  229. package/gs/builtin/type.ts +109 -34
  230. package/gs/builtin/varRef.ts +38 -1
  231. package/gs/bytes/buffer.gs.ts +48 -44
  232. package/gs/bytes/meta.json +8 -3
  233. package/gs/bytes/reader.gs.ts +20 -19
  234. package/gs/context/context.test.ts +41 -0
  235. package/gs/context/context.ts +22 -26
  236. package/gs/crypto/internal/fips140deps/byteorder/index.ts +1 -0
  237. package/gs/crypto/internal/fips140deps/godebug/index.ts +1 -0
  238. package/gs/embed/index.ts +20 -0
  239. package/gs/embed/meta.json +5 -0
  240. package/gs/encoding/json/index.test.ts +15 -1
  241. package/gs/encoding/json/index.ts +24 -0
  242. package/gs/errors/errors.test.ts +82 -0
  243. package/gs/errors/errors.ts +104 -0
  244. package/gs/fmt/fmt.ts +56 -16
  245. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +73 -1
  246. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +297 -1
  247. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.test.ts +159 -0
  248. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.ts +1005 -0
  249. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +719 -0
  250. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +40 -0
  251. package/gs/github.com/klauspost/compress/internal/le/index.test.ts +36 -0
  252. package/gs/github.com/klauspost/compress/internal/le/index.ts +114 -0
  253. package/gs/go/internal/scannerhooks/index.test.ts +14 -0
  254. package/gs/go/internal/scannerhooks/index.ts +9 -0
  255. package/gs/go/scanner/index.test.ts +22 -0
  256. package/gs/go/scanner/index.ts +47 -0
  257. package/gs/go/token/index.test.ts +47 -1
  258. package/gs/go/token/index.ts +570 -4
  259. package/gs/internal/abi/index.test.ts +18 -0
  260. package/gs/internal/abi/index.ts +14 -0
  261. package/gs/internal/bytealg/index.test.ts +18 -0
  262. package/gs/internal/bytealg/index.ts +16 -0
  263. package/gs/internal/byteorder/index.test.ts +39 -0
  264. package/gs/internal/byteorder/index.ts +100 -27
  265. package/gs/internal/godebug/index.test.ts +16 -0
  266. package/gs/internal/godebug/index.ts +35 -0
  267. package/gs/io/fs/index.ts +1 -0
  268. package/gs/io/fs/meta.json +5 -0
  269. package/gs/io/fs/readlink.test.ts +43 -0
  270. package/gs/io/fs/readlink.ts +77 -0
  271. package/gs/io/fs/walk.test.ts +61 -0
  272. package/gs/io/fs/walk.ts +9 -9
  273. package/gs/io/io.ts +174 -31
  274. package/gs/io/meta.json +10 -2
  275. package/gs/maps/iter.ts +12 -6
  276. package/gs/maps/maps.ts +8 -6
  277. package/gs/math/bits/index.ts +103 -47
  278. package/gs/math/const.gs.test.ts +11 -5
  279. package/gs/math/const.gs.ts +5 -6
  280. package/gs/mime/index.ts +54 -0
  281. package/gs/net/http/httptest/index.ts +25 -0
  282. package/gs/net/http/index.test.ts +20 -0
  283. package/gs/net/http/index.ts +81 -0
  284. package/gs/os/dir_unix.gs.ts +2 -3
  285. package/gs/os/types_js.gs.ts +2 -2
  286. package/gs/path/filepath/match.test.ts +31 -12
  287. package/gs/path/filepath/match.ts +178 -3
  288. package/gs/path/filepath/path.test.ts +25 -0
  289. package/gs/path/filepath/path.ts +159 -5
  290. package/gs/path/path.ts +20 -5
  291. package/gs/reflect/index.ts +1 -0
  292. package/gs/reflect/map.test.ts +19 -0
  293. package/gs/reflect/map.ts +4 -0
  294. package/gs/reflect/type.ts +197 -17
  295. package/gs/runtime/debug/index.test.ts +24 -0
  296. package/gs/runtime/debug/index.ts +8 -0
  297. package/gs/runtime/runtime.test.ts +19 -0
  298. package/gs/runtime/runtime.ts +98 -3
  299. package/gs/slices/slices.test.ts +94 -0
  300. package/gs/slices/slices.ts +245 -5
  301. package/gs/sort/meta.json +7 -0
  302. package/gs/sort/slice.gs.ts +16 -7
  303. package/gs/sort/sort.gs.ts +16 -13
  304. package/gs/strings/builder.ts +4 -3
  305. package/gs/sync/atomic/type.gs.ts +13 -14
  306. package/gs/sync/meta.json +3 -1
  307. package/gs/sync/sync.test.ts +13 -1
  308. package/gs/sync/sync.ts +27 -0
  309. package/gs/syscall/constants.ts +39 -24
  310. package/gs/syscall/errors.ts +10 -0
  311. package/gs/syscall/fs.ts +195 -0
  312. package/gs/syscall/js/index.ts +458 -0
  313. package/gs/syscall/js/meta.json +4 -0
  314. package/gs/syscall/net.test.ts +85 -0
  315. package/gs/syscall/types.ts +56 -0
  316. package/gs/testing/index.ts +1 -0
  317. package/gs/testing/meta.json +5 -0
  318. package/gs/testing/testing.test.ts +90 -0
  319. package/gs/testing/testing.ts +382 -0
  320. package/gs/time/time.test.ts +106 -0
  321. package/gs/time/time.ts +278 -57
  322. package/gs/unicode/unicode.test.ts +25 -0
  323. package/gs/unicode/unicode.ts +119 -9
  324. package/gs/unicode/utf8/utf8.test.ts +13 -0
  325. package/gs/unicode/utf8/utf8.ts +28 -16
  326. package/gs/unique/index.ts +91 -0
  327. package/package.json +2 -1
@@ -51,8 +51,11 @@ func (o *TypeScriptEmitOwner) Emit(
51
51
  }}
52
52
  }
53
53
 
54
+ files, diagnostics := o.EmitToMemory(ctx, program)
55
+ if diagnosticsHaveErrors(diagnostics) {
56
+ return nil, diagnostics
57
+ }
54
58
  var compiled []string
55
- var diagnostics []Diagnostic
56
59
  for _, pkg := range program.packages {
57
60
  if err := ctx.Err(); err != nil {
58
61
  diagnostics = append(diagnostics, Diagnostic{
@@ -68,12 +71,14 @@ func (o *TypeScriptEmitOwner) Emit(
68
71
  continue
69
72
  }
70
73
  for _, file := range pkg.files {
71
- path := filepath.Join(pkgDir, file.outputName)
72
- if err := os.WriteFile(path, []byte(o.renderLoweredFile(pkg, file)), 0o644); err != nil {
74
+ filePath := "@goscript/" + pkg.pkgPath + "/" + file.outputName
75
+ path := filepath.Join(req.OutputPath, filepath.FromSlash(filePath))
76
+ if err := os.WriteFile(path, []byte(files[filePath]), 0o644); err != nil {
73
77
  diagnostics = append(diagnostics, emitError("write TypeScript file", path, err))
74
78
  }
75
79
  }
76
- if err := os.WriteFile(filepath.Join(pkgDir, "index.ts"), []byte(renderIndex(pkg)), 0o644); err != nil {
80
+ indexPath := "@goscript/" + pkg.pkgPath + "/index.ts"
81
+ if err := os.WriteFile(filepath.Join(pkgDir, "index.ts"), []byte(files[indexPath]), 0o644); err != nil {
77
82
  diagnostics = append(diagnostics, emitError("write package index", pkg.pkgPath, err))
78
83
  continue
79
84
  }
@@ -82,6 +87,34 @@ func (o *TypeScriptEmitOwner) Emit(
82
87
  return compiled, diagnostics
83
88
  }
84
89
 
90
+ // EmitToMemory renders a lowered program into deterministic slash-path files.
91
+ func (o *TypeScriptEmitOwner) EmitToMemory(
92
+ ctx context.Context,
93
+ program *LoweredProgram,
94
+ ) (map[string]string, []Diagnostic) {
95
+ if err := ctx.Err(); err != nil {
96
+ return nil, []Diagnostic{contextCanceledDiagnostic(err)}
97
+ }
98
+ if program == nil {
99
+ return nil, []Diagnostic{{
100
+ Severity: DiagnosticSeverityError,
101
+ Code: "goscript/emitter:no-program",
102
+ Message: "TypeScript emission requires a lowered program",
103
+ }}
104
+ }
105
+ files := make(map[string]string)
106
+ for _, pkg := range program.packages {
107
+ if err := ctx.Err(); err != nil {
108
+ return files, []Diagnostic{contextCanceledDiagnostic(err)}
109
+ }
110
+ for _, file := range pkg.files {
111
+ files["@goscript/"+pkg.pkgPath+"/"+file.outputName] = o.renderLoweredFile(pkg, file)
112
+ }
113
+ files["@goscript/"+pkg.pkgPath+"/index.ts"] = renderIndex(pkg)
114
+ }
115
+ return files, nil
116
+ }
117
+
85
118
  func (o *TypeScriptEmitOwner) renderLoweredFile(pkg *loweredPackage, file *loweredFile) string {
86
119
  var b strings.Builder
87
120
  if file.sourcePath != "" {
@@ -102,31 +135,119 @@ func (o *TypeScriptEmitOwner) renderLoweredFile(pkg *loweredPackage, file *lower
102
135
  if len(file.imports) != 0 {
103
136
  b.WriteString("\n")
104
137
  }
105
- for idx, decl := range file.decls {
106
- if idx != 0 {
138
+ hasMain := false
139
+ wroteDecl := false
140
+ writeSeparator := func() {
141
+ if wroteDecl {
107
142
  b.WriteString("\n")
108
143
  }
144
+ wroteDecl = true
145
+ }
146
+ writeDecl := func(decl loweredDecl) {
109
147
  if decl.structType != nil {
148
+ writeSeparator()
110
149
  renderStruct(&b, decl.structType, o.runtimeOwner)
111
- continue
150
+ return
112
151
  }
113
152
  if decl.function != nil {
153
+ writeSeparator()
114
154
  renderFunction(&b, decl.function)
115
- if pkg.name == "main" && decl.function.name == "main" {
116
- b.WriteString("\n\nif (")
117
- b.WriteString(o.runtimeOwner.QualifiedHelper(RuntimeHelperIsMainScript))
118
- b.WriteString("(import.meta)) {\n")
119
- b.WriteString("\tawait main()\n")
120
- b.WriteString("}\n")
155
+ if decl.function.name == "main" {
156
+ hasMain = true
121
157
  }
122
- continue
158
+ return
123
159
  }
160
+ writeSeparator()
124
161
  b.WriteString(decl.code)
125
162
  b.WriteString("\n")
126
163
  }
164
+ for _, decl := range file.decls {
165
+ if decl.typeIndexExport != "" && decl.code != "" {
166
+ writeDecl(decl)
167
+ }
168
+ }
169
+ for _, decl := range sortedStructDecls(file.decls) {
170
+ if decl.structType != nil {
171
+ writeDecl(decl)
172
+ }
173
+ }
174
+ for _, decl := range file.decls {
175
+ if decl.structType != nil || (decl.typeIndexExport != "" && decl.code != "") {
176
+ continue
177
+ }
178
+ writeDecl(decl)
179
+ }
180
+ if pkg.name == "main" && hasMain {
181
+ writeSeparator()
182
+ b.WriteString("if (")
183
+ b.WriteString(o.runtimeOwner.QualifiedHelper(RuntimeHelperIsMainScript))
184
+ b.WriteString("(import.meta)) {\n")
185
+ b.WriteString("\tawait main()\n")
186
+ b.WriteString("}\n")
187
+ }
127
188
  return b.String()
128
189
  }
129
190
 
191
+ func sortedStructDecls(decls []loweredDecl) []loweredDecl {
192
+ structs := make([]loweredDecl, 0)
193
+ names := make(map[string]bool)
194
+ for _, decl := range decls {
195
+ if decl.structType == nil {
196
+ continue
197
+ }
198
+ structs = append(structs, decl)
199
+ names[decl.structType.name] = true
200
+ }
201
+ if len(structs) < 2 {
202
+ return structs
203
+ }
204
+ byName := make(map[string]loweredDecl, len(structs))
205
+ for _, decl := range structs {
206
+ byName[decl.structType.name] = decl
207
+ }
208
+ visiting := make(map[string]bool, len(structs))
209
+ visited := make(map[string]bool, len(structs))
210
+ sorted := make([]loweredDecl, 0, len(structs))
211
+ var visit func(loweredDecl)
212
+ visit = func(decl loweredDecl) {
213
+ name := decl.structType.name
214
+ if visited[name] || visiting[name] {
215
+ return
216
+ }
217
+ visiting[name] = true
218
+ for _, dep := range structZeroValueDeps(decl.structType, names) {
219
+ if depDecl, ok := byName[dep]; ok {
220
+ visit(depDecl)
221
+ }
222
+ }
223
+ visiting[name] = false
224
+ visited[name] = true
225
+ sorted = append(sorted, decl)
226
+ }
227
+ for _, decl := range structs {
228
+ visit(decl)
229
+ }
230
+ return sorted
231
+ }
232
+
233
+ func structZeroValueDeps(structType *loweredStruct, names map[string]bool) []string {
234
+ var deps []string
235
+ for _, field := range structType.fields {
236
+ if !field.structValue {
237
+ continue
238
+ }
239
+ for name := range names {
240
+ if name == structType.name {
241
+ continue
242
+ }
243
+ if strings.Contains(field.zero, "new "+name+"(") {
244
+ deps = append(deps, name)
245
+ }
246
+ }
247
+ }
248
+ return deps
249
+ }
250
+
130
251
  func renderStruct(b *strings.Builder, structType *loweredStruct, runtimeOwner *RuntimeContractOwner) {
131
252
  varRef := runtimeOwner.QualifiedHelper(RuntimeHelperVarRef)
132
253
  markStructValue := runtimeOwner.QualifiedHelper(RuntimeHelperMarkAsStructValue)
@@ -201,7 +322,9 @@ func renderStruct(b *strings.Builder, structType *loweredStruct, runtimeOwner *R
201
322
  b.WriteString("\n")
202
323
  }
203
324
  b.WriteString("\t\t}\n\t}\n\n")
204
- b.WriteString("\tpublic clone(): ")
325
+ b.WriteString("\tpublic ")
326
+ b.WriteString(structType.cloneMethod)
327
+ b.WriteString("(): ")
205
328
  b.WriteString(structType.name)
206
329
  b.WriteString(" {\n\t\tconst cloned = new ")
207
330
  b.WriteString(structType.name)
@@ -240,15 +363,19 @@ func renderStruct(b *strings.Builder, structType *loweredStruct, runtimeOwner *R
240
363
  b.WriteString("(\n")
241
364
  b.WriteString("\t\t")
242
365
  b.WriteString(strconvQuote(structType.typeName))
243
- b.WriteString(",\n\t\tnew ")
366
+ b.WriteString(",\n\t\t() => new ")
244
367
  b.WriteString(structType.name)
245
368
  b.WriteString("(),\n\t\t[")
246
369
  for idx, method := range structType.methods {
247
370
  if idx != 0 {
248
371
  b.WriteString(", ")
249
372
  }
373
+ methodName := method.name
374
+ if method.runtimeName != "" {
375
+ methodName = method.runtimeName
376
+ }
250
377
  b.WriteString("{ name: ")
251
- b.WriteString(strconvQuote(method.name))
378
+ b.WriteString(strconvQuote(methodName))
252
379
  b.WriteString(", args: [], returns: [] }")
253
380
  }
254
381
  b.WriteString("],\n\t\t")
@@ -260,7 +387,7 @@ func renderStruct(b *strings.Builder, structType *loweredStruct, runtimeOwner *R
260
387
  }
261
388
  b.WriteString(strconvQuote(field.name))
262
389
  b.WriteString(": ")
263
- b.WriteString(runtimeStructFieldInfoExpr(field.runtimeType, field.tag))
390
+ b.WriteString(runtimeStructFieldInfoExpr(field.runtimeType, field.runtimeName, field.tag))
264
391
  }
265
392
  b.WriteString("}\n\t)\n")
266
393
  b.WriteString("}\n")
@@ -308,10 +435,22 @@ func renderFunction(b *strings.Builder, fn *loweredFunction) {
308
435
  b.WriteString(" {\n")
309
436
  if fn.receiverAlias != "" && fn.receiverAlias != "_" {
310
437
  writeIndent(b, 1)
311
- b.WriteString("const ")
438
+ if fn.receiverMutable {
439
+ b.WriteString("let ")
440
+ } else {
441
+ b.WriteString("const ")
442
+ }
312
443
  b.WriteString(fn.receiverAlias)
313
- b.WriteString(" = this\n")
444
+ if fn.receiverType != "" {
445
+ b.WriteString(": ")
446
+ b.WriteString(fn.receiverType)
447
+ }
448
+ b.WriteString(" = ")
449
+ b.WriteString(receiverValue(fn))
450
+ b.WriteString("\n")
314
451
  }
452
+ renderStmts(b, fn.paramBindings, 1)
453
+ renderNamedResults(b, fn.namedResults, 1)
315
454
  renderDeferStack(b, fn.deferState, 1)
316
455
  renderStmts(b, fn.body, 1)
317
456
  b.WriteString("}\n")
@@ -338,16 +477,48 @@ func renderMethod(b *strings.Builder, fn *loweredFunction) {
338
477
  b.WriteString(" {\n")
339
478
  if fn.receiverAlias != "" && fn.receiverAlias != "_" {
340
479
  writeIndent(b, 2)
341
- b.WriteString("const ")
480
+ if fn.receiverMutable {
481
+ b.WriteString("let ")
482
+ } else {
483
+ b.WriteString("const ")
484
+ }
342
485
  b.WriteString(fn.receiverAlias)
343
- b.WriteString(" = this\n")
486
+ if fn.receiverType != "" {
487
+ b.WriteString(": ")
488
+ b.WriteString(fn.receiverType)
489
+ }
490
+ b.WriteString(" = ")
491
+ b.WriteString(receiverValue(fn))
492
+ b.WriteString("\n")
344
493
  }
494
+ renderStmts(b, fn.paramBindings, 2)
495
+ renderNamedResults(b, fn.namedResults, 2)
345
496
  renderDeferStack(b, fn.deferState, 2)
346
497
  renderStmts(b, fn.body, 2)
347
498
  writeIndent(b, 1)
348
499
  b.WriteString("}\n")
349
500
  }
350
501
 
502
+ func receiverValue(fn *loweredFunction) string {
503
+ if fn.receiverValue != "" {
504
+ return fn.receiverValue
505
+ }
506
+ return "this"
507
+ }
508
+
509
+ func renderNamedResults(b *strings.Builder, results []loweredNamedResult, indent int) {
510
+ for _, result := range results {
511
+ writeIndent(b, indent)
512
+ b.WriteString("let ")
513
+ b.WriteString(result.name)
514
+ b.WriteString(": ")
515
+ b.WriteString(result.typ)
516
+ b.WriteString(" = ")
517
+ b.WriteString(result.zero)
518
+ b.WriteString("\n")
519
+ }
520
+ }
521
+
351
522
  func renderDeferStack(b *strings.Builder, state *loweredDeferState, indent int) {
352
523
  if state == nil || !state.used {
353
524
  return
@@ -361,7 +532,7 @@ func renderDeferStack(b *strings.Builder, state *loweredDeferState, indent int)
361
532
  }
362
533
 
363
534
  func renderStmts(b *strings.Builder, stmts []loweredStmt, indent int) {
364
- for _, stmt := range stmts {
535
+ for idx, stmt := range stmts {
365
536
  renderLeadingLines(b, stmt.leading, indent)
366
537
  if stmt.rangeFunc != nil {
367
538
  renderRangeFunc(b, stmt.rangeFunc, indent)
@@ -380,7 +551,7 @@ func renderStmts(b *strings.Builder, stmts []loweredStmt, indent int) {
380
551
  continue
381
552
  }
382
553
  writeIndent(b, indent)
383
- if stmt.text == "" && len(stmt.children) != 0 {
554
+ if stmt.text == "" && (stmt.hasBlock || len(stmt.children) != 0) {
384
555
  b.WriteString("{\n")
385
556
  renderStmts(b, stmt.children, indent+1)
386
557
  writeIndent(b, indent)
@@ -388,7 +559,10 @@ func renderStmts(b *strings.Builder, stmts []loweredStmt, indent int) {
388
559
  continue
389
560
  }
390
561
  writeIndentedText(b, stmt.text, indent)
391
- if len(stmt.children) == 0 {
562
+ if !stmt.hasBlock && len(stmt.children) == 0 {
563
+ if idx+1 < len(stmts) && needsASIBarrier(stmt, stmts[idx+1]) {
564
+ b.WriteString(";")
565
+ }
392
566
  b.WriteString("\n")
393
567
  continue
394
568
  }
@@ -407,6 +581,23 @@ func renderStmts(b *strings.Builder, stmts []loweredStmt, indent int) {
407
581
  }
408
582
  }
409
583
 
584
+ func needsASIBarrier(current loweredStmt, next loweredStmt) bool {
585
+ if current.text == "" ||
586
+ current.hasBlock ||
587
+ len(current.children) != 0 ||
588
+ current.rangeFunc != nil ||
589
+ current.switchStmt != nil ||
590
+ current.selectStmt != nil ||
591
+ current.typeSwitch != nil {
592
+ return false
593
+ }
594
+ if strings.HasSuffix(strings.TrimSpace(current.text), ";") {
595
+ return false
596
+ }
597
+ nextText := strings.TrimLeft(next.text, " \t")
598
+ return strings.HasPrefix(nextText, "(") || strings.HasPrefix(nextText, "[")
599
+ }
600
+
410
601
  func renderLeadingLines(b *strings.Builder, lines []string, indent int) {
411
602
  for _, line := range lines {
412
603
  if strings.TrimSpace(line) == "" {
@@ -438,39 +629,66 @@ func renderSwitch(b *strings.Builder, stmt *loweredSwitch, indent int) {
438
629
  b.WriteString(stmt.value)
439
630
  b.WriteString(") {\n")
440
631
  for _, switchCase := range stmt.cases {
441
- for _, value := range switchCase.values {
632
+ if switchCase.defaultCase {
442
633
  writeIndent(b, indent+1)
443
- b.WriteString("case ")
444
- b.WriteString(value)
445
- b.WriteString(":\n")
634
+ b.WriteString("default:\n")
635
+ } else {
636
+ for _, value := range switchCase.values {
637
+ writeIndent(b, indent+1)
638
+ b.WriteString("case ")
639
+ b.WriteString(value)
640
+ b.WriteString(":\n")
641
+ }
446
642
  }
447
- renderSwitchBody(b, switchCase.body, indent+1)
448
- }
449
- if len(stmt.defaultBody) != 0 {
450
- writeIndent(b, indent+1)
451
- b.WriteString("default:\n")
452
- renderSwitchBody(b, stmt.defaultBody, indent+1)
643
+ renderSwitchBody(b, switchCase.body, switchCase.fallsThrough, indent+1)
453
644
  }
454
645
  writeIndent(b, indent)
455
646
  b.WriteString("}\n")
456
647
  }
457
648
 
458
- func renderSwitchBody(b *strings.Builder, body []loweredStmt, indent int) {
649
+ func renderSwitchBody(b *strings.Builder, body []loweredStmt, fallsThrough bool, indent int) {
459
650
  writeIndent(b, indent)
460
651
  b.WriteString("{\n")
461
652
  renderStmts(b, body, indent+1)
462
- writeIndent(b, indent+1)
463
- b.WriteString("break\n")
653
+ if !fallsThrough {
654
+ writeIndent(b, indent+1)
655
+ b.WriteString("break\n")
656
+ }
464
657
  writeIndent(b, indent)
465
658
  b.WriteString("}\n")
466
659
  }
467
660
 
468
661
  func renderRangeFunc(b *strings.Builder, stmt *loweredRangeFunc, indent int) {
662
+ if stmt.returnBranch != nil {
663
+ writeIndent(b, indent)
664
+ b.WriteString("let ")
665
+ b.WriteString(stmt.returnBranch.hasReturn)
666
+ b.WriteString(" = false\n")
667
+ if stmt.returnBranch.value != "" {
668
+ writeIndent(b, indent)
669
+ b.WriteString("let ")
670
+ b.WriteString(stmt.returnBranch.value)
671
+ b.WriteString(": ")
672
+ b.WriteString(stmt.returnBranch.resultType)
673
+ b.WriteString(" | undefined\n")
674
+ }
675
+ }
469
676
  writeIndent(b, indent)
470
- b.WriteString(";(() => {\n")
677
+ if stmt.async {
678
+ b.WriteString(";await (async () => {\n")
679
+ } else {
680
+ b.WriteString(";(() => {\n")
681
+ }
471
682
  writeIndent(b, indent+1)
683
+ if stmt.async {
684
+ b.WriteString("await ")
685
+ }
472
686
  b.WriteString(stmt.value)
473
- b.WriteString("!((")
687
+ b.WriteString("!(")
688
+ if stmt.async {
689
+ b.WriteString("async ")
690
+ }
691
+ b.WriteString("(")
474
692
  b.WriteString(strings.Join(stmt.params, ", "))
475
693
  b.WriteString(") => {\n")
476
694
  renderStmts(b, stmt.body, indent+2)
@@ -480,6 +698,66 @@ func renderRangeFunc(b *strings.Builder, stmt *loweredRangeFunc, indent int) {
480
698
  b.WriteString("})\n")
481
699
  writeIndent(b, indent)
482
700
  b.WriteString("})()\n")
701
+ if stmt.returnBranch == nil {
702
+ return
703
+ }
704
+ writeIndent(b, indent)
705
+ b.WriteString("if (")
706
+ b.WriteString(stmt.returnBranch.hasReturn)
707
+ b.WriteString(")")
708
+ if stmt.parentBranch != nil {
709
+ b.WriteString(" {\n")
710
+ writeIndent(b, indent+1)
711
+ b.WriteString(stmt.parentBranch.hasReturn)
712
+ b.WriteString(" = true\n")
713
+ if stmt.parentBranch.value != "" && stmt.returnBranch.value != "" {
714
+ writeIndent(b, indent+1)
715
+ b.WriteString(stmt.parentBranch.value)
716
+ b.WriteString(" = ")
717
+ b.WriteString(stmt.returnBranch.value)
718
+ b.WriteString("!\n")
719
+ }
720
+ writeIndent(b, indent+1)
721
+ b.WriteString("return false\n")
722
+ writeIndent(b, indent)
723
+ b.WriteString("}\n")
724
+ return
725
+ }
726
+ if stmt.returnBranch.value == "" {
727
+ b.WriteString(" {\n")
728
+ writeIndent(b, indent+1)
729
+ b.WriteString("return\n")
730
+ writeIndent(b, indent)
731
+ b.WriteString("}\n")
732
+ return
733
+ }
734
+ b.WriteString(" {\n")
735
+ writeIndent(b, indent+1)
736
+ b.WriteString("return ")
737
+ b.WriteString(stmt.returnBranch.value)
738
+ b.WriteString("!")
739
+ b.WriteString("\n")
740
+ writeIndent(b, indent)
741
+ b.WriteString("}\n")
742
+ }
743
+
744
+ func renderNamedStructConversion(expr *loweredNamedStructConversionExpr) string {
745
+ if expr == nil {
746
+ return "undefined"
747
+ }
748
+ if expr.castOnly {
749
+ return "(" + expr.value.text + " as unknown as " + expr.castTarget + ")"
750
+ }
751
+ fields := make([]string, 0, len(expr.fields))
752
+ for _, field := range expr.fields {
753
+ fields = append(fields, field.name+": "+expr.temp+"."+field.name)
754
+ }
755
+ body := "const " + expr.temp + " = " + expr.value.text + "; return " +
756
+ expr.helper + "(new " + expr.target + "({" + strings.Join(fields, ", ") + "}))"
757
+ if expr.value.async {
758
+ return "(await (async () => { " + body + " })())"
759
+ }
760
+ return "(() => { " + body + " })()"
483
761
  }
484
762
 
485
763
  func renderSelect(b *strings.Builder, stmt *loweredSelect, indent int) {
@@ -489,10 +767,14 @@ func renderSelect(b *strings.Builder, stmt *loweredSelect, indent int) {
489
767
  b.WriteString(", ")
490
768
  b.WriteString(stmt.value)
491
769
  b.WriteString("] = await $.selectStatement<any, ")
492
- b.WriteString(stmt.resultType)
770
+ if stmt.external {
771
+ b.WriteString("any")
772
+ } else {
773
+ b.WriteString(stmt.resultType)
774
+ }
493
775
  b.WriteString(">([\n")
494
776
  for idx, switchCase := range stmt.cases {
495
- renderSelectCase(b, switchCase, indent+1)
777
+ renderSelectCase(b, switchCase, stmt.external, indent+1)
496
778
  if idx != len(stmt.cases)-1 {
497
779
  b.WriteString(",")
498
780
  }
@@ -506,6 +788,10 @@ func renderSelect(b *strings.Builder, stmt *loweredSelect, indent int) {
506
788
  }
507
789
  b.WriteString(hasDefault)
508
790
  b.WriteString(")\n")
791
+ if stmt.external {
792
+ renderSelectExternalBodies(b, stmt, indent)
793
+ return
794
+ }
509
795
  writeIndent(b, indent)
510
796
  b.WriteString("if (")
511
797
  b.WriteString(stmt.hasReturn)
@@ -516,9 +802,44 @@ func renderSelect(b *strings.Builder, stmt *loweredSelect, indent int) {
516
802
  b.WriteString("\n")
517
803
  writeIndent(b, indent)
518
804
  b.WriteString("}\n")
805
+ if stmt.returns {
806
+ writeIndent(b, indent)
807
+ b.WriteString("throw new Error(\"unreachable select\")\n")
808
+ }
519
809
  }
520
810
 
521
- func renderSelectCase(b *strings.Builder, switchCase loweredSelectCase, indent int) {
811
+ func renderSelectExternalBodies(b *strings.Builder, stmt *loweredSelect, indent int) {
812
+ writeIndent(b, indent)
813
+ b.WriteString("switch (")
814
+ b.WriteString(stmt.value)
815
+ b.WriteString("?.id) {\n")
816
+ for _, switchCase := range stmt.cases {
817
+ writeIndent(b, indent+1)
818
+ b.WriteString("case ")
819
+ b.WriteString(strconv.Itoa(switchCase.id))
820
+ b.WriteString(":\n")
821
+ writeIndent(b, indent+2)
822
+ b.WriteString("{\n")
823
+ writeIndent(b, indent+3)
824
+ b.WriteString("const result = ")
825
+ b.WriteString(stmt.value)
826
+ b.WriteString("\n")
827
+ renderStmts(b, switchCase.prelude, indent+3)
828
+ renderStmts(b, switchCase.body, indent+3)
829
+ writeIndent(b, indent+3)
830
+ b.WriteString("break\n")
831
+ writeIndent(b, indent+2)
832
+ b.WriteString("}\n")
833
+ }
834
+ writeIndent(b, indent)
835
+ b.WriteString("}\n")
836
+ if stmt.returns {
837
+ writeIndent(b, indent)
838
+ b.WriteString("throw new Error(\"unreachable select\")\n")
839
+ }
840
+ }
841
+
842
+ func renderSelectCase(b *strings.Builder, switchCase loweredSelectCase, external bool, indent int) {
522
843
  writeIndent(b, indent)
523
844
  b.WriteString("{\n")
524
845
  writeIndent(b, indent+1)
@@ -545,6 +866,15 @@ func renderSelectCase(b *strings.Builder, switchCase loweredSelectCase, indent i
545
866
  }
546
867
  writeIndent(b, indent+1)
547
868
  b.WriteString("onSelected: async (result) => {\n")
869
+ if external {
870
+ writeIndent(b, indent+2)
871
+ b.WriteString("return result\n")
872
+ writeIndent(b, indent+1)
873
+ b.WriteString("}\n")
874
+ writeIndent(b, indent)
875
+ b.WriteString("}")
876
+ return
877
+ }
548
878
  renderStmts(b, switchCase.prelude, indent+2)
549
879
  renderStmts(b, switchCase.body, indent+2)
550
880
  writeIndent(b, indent+1)
@@ -555,68 +885,115 @@ func renderSelectCase(b *strings.Builder, switchCase loweredSelectCase, indent i
555
885
 
556
886
  func renderTypeSwitch(b *strings.Builder, stmt *loweredTypeSwitch, indent int) {
557
887
  writeIndent(b, indent)
558
- b.WriteString("$.typeSwitch(\n")
888
+ b.WriteString("{\n")
559
889
  writeIndent(b, indent+1)
890
+ b.WriteString("const __goscriptTypeSwitchValue = ")
560
891
  b.WriteString(stmt.value)
561
- b.WriteString(",\n")
892
+ b.WriteString("\n")
562
893
  writeIndent(b, indent+1)
563
- b.WriteString("[\n")
564
- for caseIdx, switchCase := range stmt.cases {
894
+ b.WriteString("switch (true) {\n")
895
+ for _, switchCase := range stmt.cases {
896
+ renderTypeSwitchCase(b, stmt.varName, stmt.varRef, switchCase, indent+2)
897
+ }
898
+ if len(stmt.defaultBody) != 0 {
565
899
  writeIndent(b, indent+2)
566
- b.WriteString("{\n")
900
+ b.WriteString("default:\n")
901
+ renderTypeSwitchInlineBody(b, stmt.varName, stmt.varRef || stmt.defaultRef, "any", "__goscriptTypeSwitchValue", stmt.defaultBody, indent+3)
567
902
  writeIndent(b, indent+3)
568
- b.WriteString("types: [")
903
+ b.WriteString("break\n")
904
+ }
905
+ writeIndent(b, indent+1)
906
+ b.WriteString("}\n")
907
+ writeIndent(b, indent)
908
+ b.WriteString("}\n")
909
+ }
910
+
911
+ func renderTypeSwitchCase(b *strings.Builder, varName string, varRef bool, switchCase loweredTypeSwitchCase, indent int) {
912
+ if len(switchCase.types) == 0 {
913
+ return
914
+ }
915
+ writeIndent(b, indent)
916
+ b.WriteString("case ")
917
+ if len(switchCase.types) == 1 {
918
+ b.WriteString("$.typeAssert<")
919
+ b.WriteString(typeSwitchAssertType(switchCase, 0))
920
+ b.WriteString(">(__goscriptTypeSwitchValue, ")
921
+ b.WriteString(switchCase.types[0])
922
+ b.WriteString(").ok")
923
+ } else {
569
924
  for idx, typ := range switchCase.types {
570
925
  if idx != 0 {
571
- b.WriteString(", ")
926
+ b.WriteString(" || ")
572
927
  }
928
+ b.WriteString("$.is(__goscriptTypeSwitchValue, ")
573
929
  b.WriteString(typ)
930
+ b.WriteString(")")
574
931
  }
575
- b.WriteString("],\n")
576
- writeIndent(b, indent+3)
577
- b.WriteString("body: ")
578
- renderTypeSwitchBody(b, stmt.varName, "", switchCase.body, indent+3)
579
- writeIndent(b, indent+2)
580
- b.WriteString("}")
581
- if caseIdx != len(stmt.cases)-1 {
582
- b.WriteString(",")
583
- }
584
- b.WriteString("\n")
585
932
  }
933
+ b.WriteString(":\n")
934
+ value := "__goscriptTypeSwitchValue"
935
+ if len(switchCase.types) == 1 {
936
+ value = "$.typeAssert<" + typeSwitchAssertType(switchCase, 0) +
937
+ ">(__goscriptTypeSwitchValue, " + switchCase.types[0] + ").value"
938
+ }
939
+ renderTypeSwitchInlineBody(b, varName, varRef || switchCase.varRef, typeSwitchCaseVariableType(switchCase), value, switchCase.body, indent+1)
586
940
  writeIndent(b, indent+1)
587
- b.WriteString("]")
588
- if len(stmt.defaultBody) != 0 {
589
- b.WriteString(",\n")
590
- writeIndent(b, indent+1)
591
- renderTypeSwitchBody(b, stmt.varName, stmt.value, stmt.defaultBody, indent+1)
941
+ b.WriteString("break\n")
942
+ }
943
+
944
+ func typeSwitchAssertType(switchCase loweredTypeSwitchCase, idx int) string {
945
+ if idx < len(switchCase.tsTypes) && switchCase.tsTypes[idx] != "" {
946
+ return switchCase.tsTypes[idx]
592
947
  }
593
- if len(stmt.defaultBody) == 0 {
594
- b.WriteString("\n")
948
+ return "any"
949
+ }
950
+
951
+ func typeSwitchCaseVariableType(switchCase loweredTypeSwitchCase) string {
952
+ if len(switchCase.types) == 1 {
953
+ return typeSwitchAssertType(switchCase, 0)
595
954
  }
596
- writeIndent(b, indent)
597
- b.WriteString(")\n")
955
+ return ""
598
956
  }
599
957
 
600
- func renderTypeSwitchBody(
958
+ func renderTypeSwitchInlineBody(
601
959
  b *strings.Builder,
602
960
  varName string,
603
- defaultValue string,
961
+ varRef bool,
962
+ varType string,
963
+ value string,
604
964
  body []loweredStmt,
605
965
  indent int,
606
966
  ) {
607
- header := "() => {\n"
608
- if varName != "" && defaultValue == "" {
609
- header = "(" + varName + ") => {\n"
967
+ if varName == "" {
968
+ renderStmts(b, body, indent)
969
+ return
610
970
  }
611
- b.WriteString(header)
612
- if varName != "" && defaultValue != "" {
613
- writeIndent(b, indent+1)
614
- b.WriteString("let ")
615
- b.WriteString(varName)
616
- b.WriteString(" = ")
617
- b.WriteString(defaultValue)
618
- b.WriteString("\n")
971
+ writeIndent(b, indent)
972
+ b.WriteString("{\n")
973
+ writeIndent(b, indent+1)
974
+ b.WriteString("let ")
975
+ b.WriteString(varName)
976
+ if varRef {
977
+ if varType == "" {
978
+ varType = "any"
979
+ }
980
+ b.WriteString(": $.VarRef<")
981
+ b.WriteString(varType)
982
+ b.WriteString("> = $.varRef(")
983
+ b.WriteString(value)
984
+ b.WriteString(")\n")
985
+ renderStmts(b, body, indent+1)
986
+ writeIndent(b, indent)
987
+ b.WriteString("}\n")
988
+ return
619
989
  }
990
+ if varType != "" {
991
+ b.WriteString(": ")
992
+ b.WriteString(varType)
993
+ }
994
+ b.WriteString(" = ")
995
+ b.WriteString(value)
996
+ b.WriteString("\n")
620
997
  renderStmts(b, body, indent+1)
621
998
  writeIndent(b, indent)
622
999
  b.WriteString("}\n")