goscript 0.1.1 → 0.1.3

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 (376) hide show
  1. package/cmd/goscript/cmd-test.go +104 -11
  2. package/cmd/goscript/cmd-test_test.go +1 -1
  3. package/cmd/goscript/cmd_compile.go +9 -0
  4. package/compiler/compile-request.go +31 -0
  5. package/compiler/compiler.go +1 -1
  6. package/compiler/compliance_test.go +0 -2
  7. package/compiler/config.go +2 -0
  8. package/compiler/gotest/package-result.go +2 -0
  9. package/compiler/gotest/request.go +85 -20
  10. package/compiler/gotest/runner.go +733 -96
  11. package/compiler/gotest/runner_test.go +647 -3
  12. package/compiler/lowered-program.go +10 -2
  13. package/compiler/lowering.go +2676 -349
  14. package/compiler/override-facts.go +77 -27
  15. package/compiler/override-registry.go +5 -4
  16. package/compiler/override-registry_test.go +178 -0
  17. package/compiler/package-graph_test.go +62 -7
  18. package/compiler/package-test-graph-variant.go +40 -16
  19. package/compiler/package-test-graph.go +0 -5
  20. package/compiler/package-test-graph_test.go +61 -3
  21. package/compiler/runtime-contract.go +40 -0
  22. package/compiler/semantic-model-types.go +16 -0
  23. package/compiler/semantic-model.go +336 -91
  24. package/compiler/semantic-model_test.go +50 -1
  25. package/compiler/service.go +9 -3
  26. package/compiler/skeleton_test.go +2371 -296
  27. package/compiler/tsworkspace/owner-process-unix_test.go +72 -0
  28. package/compiler/tsworkspace/owner.go +8 -0
  29. package/compiler/tsworkspace/tool-process-other.go +14 -0
  30. package/compiler/tsworkspace/tool-process-unix.go +19 -0
  31. package/compiler/typescript-emitter.go +149 -10
  32. package/dist/gs/builtin/builtin.d.ts +20 -1
  33. package/dist/gs/builtin/builtin.js +246 -26
  34. package/dist/gs/builtin/builtin.js.map +1 -1
  35. package/dist/gs/builtin/channel.d.ts +24 -10
  36. package/dist/gs/builtin/channel.js +143 -34
  37. package/dist/gs/builtin/channel.js.map +1 -1
  38. package/dist/gs/builtin/defer.d.ts +1 -0
  39. package/dist/gs/builtin/defer.js +12 -2
  40. package/dist/gs/builtin/defer.js.map +1 -1
  41. package/dist/gs/builtin/hostio.d.ts +9 -0
  42. package/dist/gs/builtin/hostio.js +25 -0
  43. package/dist/gs/builtin/hostio.js.map +1 -1
  44. package/dist/gs/builtin/map.js +40 -6
  45. package/dist/gs/builtin/map.js.map +1 -1
  46. package/dist/gs/builtin/print.js.map +1 -1
  47. package/dist/gs/builtin/slice.d.ts +43 -9
  48. package/dist/gs/builtin/slice.js +437 -234
  49. package/dist/gs/builtin/slice.js.map +1 -1
  50. package/dist/gs/builtin/type.d.ts +2 -0
  51. package/dist/gs/builtin/type.js +55 -10
  52. package/dist/gs/builtin/type.js.map +1 -1
  53. package/dist/gs/builtin/varRef.d.ts +2 -0
  54. package/dist/gs/builtin/varRef.js.map +1 -1
  55. package/dist/gs/bytes/buffer.gs.js +28 -28
  56. package/dist/gs/bytes/buffer.gs.js.map +1 -1
  57. package/dist/gs/bytes/bytes.gs.d.ts +7 -5
  58. package/dist/gs/bytes/bytes.gs.js +10 -4
  59. package/dist/gs/bytes/bytes.gs.js.map +1 -1
  60. package/dist/gs/bytes/iter.gs.js +13 -13
  61. package/dist/gs/bytes/iter.gs.js.map +1 -1
  62. package/dist/gs/compress/zlib/index.d.ts +26 -0
  63. package/dist/gs/compress/zlib/index.js +168 -0
  64. package/dist/gs/compress/zlib/index.js.map +1 -0
  65. package/dist/gs/context/context.d.ts +1 -1
  66. package/dist/gs/context/context.js +8 -3
  67. package/dist/gs/context/context.js.map +1 -1
  68. package/dist/gs/crypto/ecdh/index.d.ts +52 -0
  69. package/dist/gs/crypto/ecdh/index.js +226 -0
  70. package/dist/gs/crypto/ecdh/index.js.map +1 -0
  71. package/dist/gs/crypto/ed25519/index.d.ts +34 -0
  72. package/dist/gs/crypto/ed25519/index.js +160 -0
  73. package/dist/gs/crypto/ed25519/index.js.map +1 -0
  74. package/dist/gs/crypto/internal/constanttime/index.d.ts +4 -0
  75. package/dist/gs/crypto/internal/constanttime/index.js +18 -0
  76. package/dist/gs/crypto/internal/constanttime/index.js.map +1 -0
  77. package/dist/gs/crypto/rand/index.d.ts +2 -0
  78. package/dist/gs/crypto/rand/index.js +85 -0
  79. package/dist/gs/crypto/rand/index.js.map +1 -1
  80. package/dist/gs/crypto/sha1/index.d.ts +5 -0
  81. package/dist/gs/crypto/sha1/index.js +106 -0
  82. package/dist/gs/crypto/sha1/index.js.map +1 -0
  83. package/dist/gs/crypto/sha256/index.d.ts +8 -0
  84. package/dist/gs/crypto/sha256/index.js +118 -0
  85. package/dist/gs/crypto/sha256/index.js.map +1 -0
  86. package/dist/gs/crypto/sha512/index.d.ts +14 -0
  87. package/dist/gs/crypto/sha512/index.js +129 -0
  88. package/dist/gs/crypto/sha512/index.js.map +1 -0
  89. package/dist/gs/encoding/json/index.d.ts +3 -0
  90. package/dist/gs/encoding/json/index.js +15 -0
  91. package/dist/gs/encoding/json/index.js.map +1 -1
  92. package/dist/gs/errors/errors.js +29 -6
  93. package/dist/gs/errors/errors.js.map +1 -1
  94. package/dist/gs/fmt/fmt.d.ts +1 -1
  95. package/dist/gs/fmt/fmt.js +64 -3
  96. package/dist/gs/fmt/fmt.js.map +1 -1
  97. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +7 -7
  98. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +52 -18
  99. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  100. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js +56 -20
  101. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.js.map +1 -1
  102. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.d.ts +57 -3
  103. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js +366 -1
  104. package/dist/gs/github.com/aperturerobotics/starpc/srpc/index.js.map +1 -1
  105. package/dist/gs/github.com/aperturerobotics/util/conc/index.d.ts +20 -0
  106. package/dist/gs/github.com/aperturerobotics/util/conc/index.js +134 -0
  107. package/dist/gs/github.com/aperturerobotics/util/conc/index.js.map +1 -0
  108. package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -1
  109. package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.d.ts +3 -0
  110. package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.js +50 -0
  111. package/dist/gs/github.com/hack-pad/safejs/internal/catch/index.js.map +1 -0
  112. package/dist/gs/github.com/klauspost/compress/internal/le/index.js +3 -2
  113. package/dist/gs/github.com/klauspost/compress/internal/le/index.js.map +1 -1
  114. package/dist/gs/github.com/mr-tron/base58/base58/index.d.ts +27 -0
  115. package/dist/gs/github.com/mr-tron/base58/base58/index.js +172 -0
  116. package/dist/gs/github.com/mr-tron/base58/base58/index.js.map +1 -0
  117. package/dist/gs/github.com/zeebo/blake3/internal/consts/index.d.ts +21 -0
  118. package/dist/gs/github.com/zeebo/blake3/internal/consts/index.js +22 -0
  119. package/dist/gs/github.com/zeebo/blake3/internal/consts/index.js.map +1 -0
  120. package/dist/gs/go/token/index.js +11 -4
  121. package/dist/gs/go/token/index.js.map +1 -1
  122. package/dist/gs/hash/fnv/index.d.ts +57 -0
  123. package/dist/gs/hash/fnv/index.js +299 -0
  124. package/dist/gs/hash/fnv/index.js.map +1 -0
  125. package/dist/gs/hash/index.d.ts +17 -0
  126. package/dist/gs/hash/index.js +94 -0
  127. package/dist/gs/hash/index.js.map +1 -0
  128. package/dist/gs/io/fs/readlink.js +2 -6
  129. package/dist/gs/io/fs/readlink.js.map +1 -1
  130. package/dist/gs/io/fs/walk.js.map +1 -1
  131. package/dist/gs/io/io.d.ts +8 -5
  132. package/dist/gs/io/io.js +20 -2
  133. package/dist/gs/io/io.js.map +1 -1
  134. package/dist/gs/iter/iter.d.ts +3 -2
  135. package/dist/gs/iter/iter.js.map +1 -1
  136. package/dist/gs/maps/iter.d.ts +5 -5
  137. package/dist/gs/maps/iter.js +48 -21
  138. package/dist/gs/maps/iter.js.map +1 -1
  139. package/dist/gs/maps/maps.d.ts +6 -6
  140. package/dist/gs/math/bits/index.js +14 -24
  141. package/dist/gs/math/bits/index.js.map +1 -1
  142. package/dist/gs/mime/index.js +3 -1
  143. package/dist/gs/mime/index.js.map +1 -1
  144. package/dist/gs/net/http/httptest/index.d.ts +20 -1
  145. package/dist/gs/net/http/httptest/index.js +85 -3
  146. package/dist/gs/net/http/httptest/index.js.map +1 -1
  147. package/dist/gs/net/http/index.d.ts +118 -6
  148. package/dist/gs/net/http/index.js +389 -14
  149. package/dist/gs/net/http/index.js.map +1 -1
  150. package/dist/gs/net/http/pprof/index.d.ts +8 -0
  151. package/dist/gs/net/http/pprof/index.js +59 -0
  152. package/dist/gs/net/http/pprof/index.js.map +1 -0
  153. package/dist/gs/os/error.gs.js +9 -7
  154. package/dist/gs/os/error.gs.js.map +1 -1
  155. package/dist/gs/os/types_js.gs.js +95 -15
  156. package/dist/gs/os/types_js.gs.js.map +1 -1
  157. package/dist/gs/os/zero_copy_posix.gs.js +1 -1
  158. package/dist/gs/os/zero_copy_posix.gs.js.map +1 -1
  159. package/dist/gs/path/filepath/match.js.map +1 -1
  160. package/dist/gs/path/filepath/path.d.ts +5 -3
  161. package/dist/gs/path/filepath/path.js +65 -10
  162. package/dist/gs/path/filepath/path.js.map +1 -1
  163. package/dist/gs/reflect/index.d.ts +3 -2
  164. package/dist/gs/reflect/index.js +2 -1
  165. package/dist/gs/reflect/index.js.map +1 -1
  166. package/dist/gs/reflect/iter.js +2 -2
  167. package/dist/gs/reflect/iter.js.map +1 -1
  168. package/dist/gs/reflect/map.js +26 -0
  169. package/dist/gs/reflect/map.js.map +1 -1
  170. package/dist/gs/reflect/type.d.ts +24 -5
  171. package/dist/gs/reflect/type.js +390 -38
  172. package/dist/gs/reflect/type.js.map +1 -1
  173. package/dist/gs/reflect/types.d.ts +1 -0
  174. package/dist/gs/reflect/types.js +3 -1
  175. package/dist/gs/reflect/types.js.map +1 -1
  176. package/dist/gs/reflect/value.d.ts +4 -1
  177. package/dist/gs/reflect/value.js +39 -1
  178. package/dist/gs/reflect/value.js.map +1 -1
  179. package/dist/gs/reflect/visiblefields.js +1 -1
  180. package/dist/gs/reflect/visiblefields.js.map +1 -1
  181. package/dist/gs/runtime/debug/index.d.ts +39 -0
  182. package/dist/gs/runtime/debug/index.js +58 -0
  183. package/dist/gs/runtime/debug/index.js.map +1 -1
  184. package/dist/gs/runtime/pprof/index.d.ts +20 -0
  185. package/dist/gs/runtime/pprof/index.js +85 -0
  186. package/dist/gs/runtime/pprof/index.js.map +1 -0
  187. package/dist/gs/runtime/trace/index.d.ts +19 -0
  188. package/dist/gs/runtime/trace/index.js +64 -0
  189. package/dist/gs/runtime/trace/index.js.map +1 -0
  190. package/dist/gs/slices/slices.d.ts +24 -9
  191. package/dist/gs/slices/slices.js +229 -24
  192. package/dist/gs/slices/slices.js.map +1 -1
  193. package/dist/gs/sort/slice.gs.d.ts +5 -3
  194. package/dist/gs/sort/slice.gs.js +55 -17
  195. package/dist/gs/sort/slice.gs.js.map +1 -1
  196. package/dist/gs/strings/builder.js +26 -17
  197. package/dist/gs/strings/builder.js.map +1 -1
  198. package/dist/gs/strings/iter.js +140 -75
  199. package/dist/gs/strings/iter.js.map +1 -1
  200. package/dist/gs/strings/replace.js +2 -2
  201. package/dist/gs/strings/replace.js.map +1 -1
  202. package/dist/gs/strings/strings.js +52 -6
  203. package/dist/gs/strings/strings.js.map +1 -1
  204. package/dist/gs/sync/sync.d.ts +6 -3
  205. package/dist/gs/sync/sync.js +39 -11
  206. package/dist/gs/sync/sync.js.map +1 -1
  207. package/dist/gs/syscall/errors.d.ts +116 -112
  208. package/dist/gs/syscall/errors.js +38 -1
  209. package/dist/gs/syscall/errors.js.map +1 -1
  210. package/dist/gs/syscall/fs.d.ts +2 -8
  211. package/dist/gs/syscall/fs.js.map +1 -1
  212. package/dist/gs/syscall/js/index.js +20 -12
  213. package/dist/gs/syscall/js/index.js.map +1 -1
  214. package/dist/gs/syscall/types.d.ts +4 -1
  215. package/dist/gs/syscall/types.js.map +1 -1
  216. package/dist/gs/testing/testing.d.ts +4 -3
  217. package/dist/gs/testing/testing.js +21 -4
  218. package/dist/gs/testing/testing.js.map +1 -1
  219. package/dist/gs/time/time.js +22 -0
  220. package/dist/gs/time/time.js.map +1 -1
  221. package/dist/gs/unicode/unicode.js.map +1 -1
  222. package/dist/gs/unique/index.js +7 -2
  223. package/dist/gs/unique/index.js.map +1 -1
  224. package/go.mod +8 -8
  225. package/go.sum +14 -23
  226. package/gs/builtin/builtin.ts +364 -37
  227. package/gs/builtin/channel.ts +208 -38
  228. package/gs/builtin/defer.ts +13 -2
  229. package/gs/builtin/hostio.test.ts +1 -0
  230. package/gs/builtin/hostio.ts +38 -0
  231. package/gs/builtin/map.ts +46 -6
  232. package/gs/builtin/print.ts +12 -3
  233. package/gs/builtin/runtime-contract.test.ts +290 -10
  234. package/gs/builtin/slice.test.ts +70 -0
  235. package/gs/builtin/slice.ts +566 -255
  236. package/gs/builtin/type.ts +63 -10
  237. package/gs/builtin/varRef.ts +2 -0
  238. package/gs/bytes/buffer.gs.ts +28 -28
  239. package/gs/bytes/bytes.gs.ts +19 -10
  240. package/gs/bytes/bytes.test.ts +17 -0
  241. package/gs/bytes/iter.gs.ts +13 -14
  242. package/gs/compress/zlib/index.test.ts +28 -0
  243. package/gs/compress/zlib/index.ts +200 -0
  244. package/gs/compress/zlib/meta.json +3 -0
  245. package/gs/context/context.test.ts +36 -2
  246. package/gs/context/context.ts +9 -4
  247. package/gs/crypto/ecdh/index.test.ts +43 -0
  248. package/gs/crypto/ecdh/index.ts +274 -0
  249. package/gs/crypto/ed25519/index.test.ts +41 -0
  250. package/gs/crypto/ed25519/index.ts +238 -0
  251. package/gs/crypto/ed25519/meta.json +13 -0
  252. package/gs/crypto/internal/constanttime/index.test.ts +25 -0
  253. package/gs/crypto/internal/constanttime/index.ts +22 -0
  254. package/gs/crypto/rand/index.test.ts +89 -1
  255. package/gs/crypto/rand/index.ts +103 -1
  256. package/gs/crypto/rand/meta.json +4 -1
  257. package/gs/crypto/sha1/index.test.ts +28 -0
  258. package/gs/crypto/sha1/index.ts +130 -0
  259. package/gs/crypto/sha1/meta.json +8 -0
  260. package/gs/crypto/sha256/index.test.ts +78 -0
  261. package/gs/crypto/sha256/index.ts +150 -0
  262. package/gs/crypto/sha256/meta.json +9 -0
  263. package/gs/crypto/sha512/index.test.ts +31 -0
  264. package/gs/crypto/sha512/index.ts +161 -0
  265. package/gs/crypto/sha512/meta.json +11 -0
  266. package/gs/encoding/json/index.test.ts +25 -3
  267. package/gs/encoding/json/index.ts +21 -3
  268. package/gs/errors/errors.test.ts +4 -1
  269. package/gs/errors/errors.ts +32 -8
  270. package/gs/fmt/fmt.test.ts +23 -1
  271. package/gs/fmt/fmt.ts +76 -10
  272. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +62 -7
  273. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +78 -36
  274. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.test.ts +32 -11
  275. package/gs/github.com/aperturerobotics/protobuf-go-lite/json/index.ts +122 -43
  276. package/gs/github.com/aperturerobotics/starpc/srpc/index.test.ts +31 -0
  277. package/gs/github.com/aperturerobotics/starpc/srpc/index.ts +518 -4
  278. package/gs/github.com/aperturerobotics/starpc/srpc/meta.json +6 -0
  279. package/gs/github.com/aperturerobotics/util/conc/index.test.ts +30 -0
  280. package/gs/github.com/aperturerobotics/util/conc/index.ts +172 -0
  281. package/gs/github.com/aperturerobotics/util/conc/meta.json +9 -0
  282. package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.ts +1 -4
  283. package/gs/github.com/hack-pad/safejs/internal/catch/index.test.ts +35 -0
  284. package/gs/github.com/hack-pad/safejs/internal/catch/index.ts +65 -0
  285. package/gs/github.com/hack-pad/safejs/internal/catch/meta.json +9 -0
  286. package/gs/github.com/klauspost/compress/internal/le/index.test.ts +2 -1
  287. package/gs/github.com/klauspost/compress/internal/le/index.ts +6 -5
  288. package/gs/github.com/mr-tron/base58/base58/index.test.ts +70 -0
  289. package/gs/github.com/mr-tron/base58/base58/index.ts +231 -0
  290. package/gs/github.com/mr-tron/base58/base58/meta.json +3 -0
  291. package/gs/github.com/zeebo/blake3/internal/consts/index.test.ts +46 -0
  292. package/gs/github.com/zeebo/blake3/internal/consts/index.ts +26 -0
  293. package/gs/go/token/index.ts +17 -4
  294. package/gs/hash/fnv/index.test.ts +67 -0
  295. package/gs/hash/fnv/index.ts +351 -0
  296. package/gs/hash/fnv/meta.json +3 -0
  297. package/gs/hash/index.test.ts +37 -0
  298. package/gs/hash/index.ts +118 -0
  299. package/gs/hash/meta.json +5 -0
  300. package/gs/internal/byteorder/index.test.ts +6 -6
  301. package/gs/io/fs/readlink.ts +40 -48
  302. package/gs/io/fs/walk.ts +10 -2
  303. package/gs/io/io.test.ts +64 -0
  304. package/gs/io/io.ts +34 -13
  305. package/gs/iter/iter.ts +8 -2
  306. package/gs/maps/iter.ts +69 -26
  307. package/gs/maps/maps.test.ts +23 -0
  308. package/gs/maps/maps.ts +6 -6
  309. package/gs/math/bits/index.test.ts +20 -0
  310. package/gs/math/bits/index.ts +15 -28
  311. package/gs/mime/index.ts +8 -2
  312. package/gs/net/http/httptest/index.test.ts +85 -0
  313. package/gs/net/http/httptest/index.ts +113 -3
  314. package/gs/net/http/index.test.ts +159 -1
  315. package/gs/net/http/index.ts +515 -15
  316. package/gs/net/http/meta.json +6 -0
  317. package/gs/net/http/pprof/index.test.ts +47 -0
  318. package/gs/net/http/pprof/index.ts +65 -0
  319. package/gs/os/error.gs.ts +9 -10
  320. package/gs/os/error.test.ts +41 -0
  321. package/gs/os/file_unix_js.test.ts +55 -0
  322. package/gs/os/tempfile.gs.test.ts +37 -10
  323. package/gs/os/types_js.gs.ts +94 -15
  324. package/gs/os/zero_copy_posix.gs.ts +1 -2
  325. package/gs/path/filepath/match.ts +4 -1
  326. package/gs/path/filepath/meta.json +6 -0
  327. package/gs/path/filepath/path.test.ts +57 -2
  328. package/gs/path/filepath/path.ts +91 -12
  329. package/gs/reflect/field.test.ts +63 -0
  330. package/gs/reflect/index.ts +4 -1
  331. package/gs/reflect/iter.ts +2 -2
  332. package/gs/reflect/map.test.ts +24 -2
  333. package/gs/reflect/map.ts +35 -0
  334. package/gs/reflect/type.ts +543 -60
  335. package/gs/reflect/typefor.test.ts +100 -0
  336. package/gs/reflect/types.ts +3 -1
  337. package/gs/reflect/value.ts +50 -1
  338. package/gs/reflect/visiblefields.ts +1 -1
  339. package/gs/runtime/debug/index.test.ts +22 -1
  340. package/gs/runtime/debug/index.ts +88 -0
  341. package/gs/runtime/pprof/index.test.ts +36 -0
  342. package/gs/runtime/pprof/index.ts +104 -0
  343. package/gs/runtime/pprof/meta.json +6 -0
  344. package/gs/runtime/trace/index.test.ts +45 -0
  345. package/gs/runtime/trace/index.ts +97 -0
  346. package/gs/runtime/trace/meta.json +7 -0
  347. package/gs/slices/meta.json +2 -1
  348. package/gs/slices/slices.test.ts +86 -0
  349. package/gs/slices/slices.ts +284 -37
  350. package/gs/sort/slice.gs.ts +73 -23
  351. package/gs/sort/slice.test.ts +40 -0
  352. package/gs/strings/builder.test.ts +8 -0
  353. package/gs/strings/builder.ts +29 -17
  354. package/gs/strings/iter.test.ts +5 -7
  355. package/gs/strings/iter.ts +146 -71
  356. package/gs/strings/replace.test.ts +1 -4
  357. package/gs/strings/replace.ts +6 -6
  358. package/gs/strings/strings.test.ts +4 -0
  359. package/gs/strings/strings.ts +54 -6
  360. package/gs/sync/meta.json +1 -0
  361. package/gs/sync/sync.test.ts +57 -1
  362. package/gs/sync/sync.ts +45 -13
  363. package/gs/syscall/errors.ts +158 -115
  364. package/gs/syscall/fs.ts +8 -8
  365. package/gs/syscall/js/index.ts +49 -22
  366. package/gs/syscall/net.test.ts +26 -0
  367. package/gs/syscall/types.ts +7 -2
  368. package/gs/testing/testing.test.ts +56 -0
  369. package/gs/testing/testing.ts +27 -10
  370. package/gs/time/meta.json +2 -2
  371. package/gs/time/time.test.ts +4 -0
  372. package/gs/time/time.ts +33 -2
  373. package/gs/unicode/unicode.test.ts +14 -3
  374. package/gs/unicode/unicode.ts +1 -5
  375. package/gs/unique/index.ts +9 -2
  376. package/package.json +3 -3
@@ -0,0 +1,78 @@
1
+ import { describe, expect, test } from 'vitest'
2
+ import * as $ from '@goscript/builtin/index.js'
3
+
4
+ import { New, New224, Size, Size224, Sum224, Sum256 } from './index.js'
5
+
6
+ describe('crypto/sha256 override', () => {
7
+ test('sums with WebCrypto', async () => {
8
+ const sum = await Sum256($.stringToBytes('abc'))
9
+ expect(Array.from(sum)).toEqual([
10
+ 186, 120, 22, 191, 143, 1, 207, 234, 65, 65, 64, 222, 93, 174, 34, 35,
11
+ 176, 3, 97, 163, 150, 23, 122, 156, 180, 16, 255, 97, 242, 0, 21, 173,
12
+ ])
13
+ })
14
+
15
+ test('streaming digest appends to prefix', async () => {
16
+ const digest = New()
17
+ expect(digest.Write($.stringToBytes('a'))).toEqual([1, null])
18
+ expect(digest.Write($.stringToBytes('bc'))).toEqual([2, null])
19
+
20
+ const out = await digest.Sum(new Uint8Array([1, 2]))
21
+ expect(Array.from(out).slice(0, 2)).toEqual([1, 2])
22
+ expect(out.length).toBe(Size + 2)
23
+ expect(Array.from(out).slice(2)).toEqual(
24
+ Array.from(await Sum256($.stringToBytes('abc'))),
25
+ )
26
+ })
27
+
28
+ test('sums SHA-224 with host crypto', async () => {
29
+ const sum = await Sum224($.stringToBytes('abc'))
30
+ expect(Array.from(sum)).toEqual([
31
+ 35, 9, 125, 34, 52, 5, 216, 34, 134, 66, 164, 119, 189, 162, 85, 179,
32
+ 42, 173, 188, 228, 189, 160, 179, 247, 227, 108, 157, 167,
33
+ ])
34
+ })
35
+
36
+ test('streaming SHA-224 digest appends to prefix', async () => {
37
+ const digest = New224()
38
+ expect(digest.Write($.stringToBytes('a'))).toEqual([1, null])
39
+ expect(digest.Write($.stringToBytes('bc'))).toEqual([2, null])
40
+
41
+ const out = await digest.Sum(new Uint8Array([1, 2]))
42
+ expect(Array.from(out).slice(0, 2)).toEqual([1, 2])
43
+ expect(out.length).toBe(Size224 + 2)
44
+ expect(Array.from(out).slice(2)).toEqual(
45
+ Array.from(await Sum224($.stringToBytes('abc'))),
46
+ )
47
+ })
48
+
49
+ test('streaming Sum does not finalize the digest', async () => {
50
+ const digest = New()
51
+ expect(digest.Write($.stringToBytes('abc'))).toEqual([3, null])
52
+
53
+ const first = await digest.Sum(null)
54
+ expect(Array.from(first)).toEqual(
55
+ Array.from(await Sum256($.stringToBytes('abc'))),
56
+ )
57
+
58
+ expect(digest.Write($.stringToBytes('d'))).toEqual([1, null])
59
+ const second = await digest.Sum(null)
60
+ expect(Array.from(second)).toEqual(
61
+ Array.from(await Sum256($.stringToBytes('abcd'))),
62
+ )
63
+ })
64
+
65
+ test('streaming digest handles many small writes', async () => {
66
+ const digest = New()
67
+ let data = ''
68
+ for (let i = 0; i < 4096; i++) {
69
+ const part = `key-${i};`
70
+ data += part
71
+ expect(digest.Write($.stringToBytes(part))).toEqual([part.length, null])
72
+ }
73
+
74
+ expect(Array.from(await digest.Sum(null))).toEqual(
75
+ Array.from(await Sum256($.stringToBytes(data))),
76
+ )
77
+ })
78
+ })
@@ -0,0 +1,150 @@
1
+ import * as $ from '@goscript/builtin/index.js'
2
+ import {
3
+ getHostRuntime,
4
+ type NodeCryptoHash,
5
+ } from '@goscript/builtin/hostio.js'
6
+
7
+ export const Size = 32
8
+ export const Size224 = 28
9
+ export const BlockSize = 64
10
+
11
+ type ShaAlgorithm = 'sha224' | 'sha256'
12
+
13
+ class Sha256Error {
14
+ constructor(private readonly message: string) {}
15
+
16
+ Error(): string {
17
+ return this.message
18
+ }
19
+ }
20
+
21
+ class Digest {
22
+ private chunks: Uint8Array[] = []
23
+ private dataLength = 0
24
+ private hash: NodeCryptoHash | null
25
+ private canCopyHash: boolean
26
+
27
+ constructor(private readonly algorithm: ShaAlgorithm) {
28
+ this.hash = createNodeHash(algorithm)
29
+ this.canCopyHash = typeof this.hash?.copy === 'function'
30
+ }
31
+
32
+ Write(p: $.Bytes): [number, $.GoError] {
33
+ const bytes = $.bytesToUint8Array(p)
34
+ this.hash?.update(bytes)
35
+ if (!this.canCopyHash) {
36
+ this.chunks.push(bytes.slice())
37
+ this.dataLength += bytes.length
38
+ }
39
+ return [bytes.length, null]
40
+ }
41
+
42
+ async Sum(b: $.Bytes): Promise<$.Bytes> {
43
+ const digest =
44
+ this.canCopyHash ?
45
+ new Uint8Array(this.hash!.copy!().digest())
46
+ : await sum(this.algorithm, this.snapshotBytes())
47
+ return appendDigest($.bytesToUint8Array(b), digest)
48
+ }
49
+
50
+ Reset(): void {
51
+ this.chunks = []
52
+ this.dataLength = 0
53
+ this.hash = createNodeHash(this.algorithm)
54
+ this.canCopyHash = typeof this.hash?.copy === 'function'
55
+ }
56
+
57
+ Size(): number {
58
+ return this.algorithm === 'sha224' ? Size224 : Size
59
+ }
60
+
61
+ BlockSize(): number {
62
+ return BlockSize
63
+ }
64
+
65
+ private snapshotBytes(): Uint8Array {
66
+ return concatChunks(this.chunks, this.dataLength)
67
+ }
68
+ }
69
+
70
+ export function New(): any {
71
+ return new Digest('sha256')
72
+ }
73
+
74
+ export function New224(): any {
75
+ return new Digest('sha224')
76
+ }
77
+
78
+ export async function Sum224(data: $.Bytes): Promise<Uint8Array> {
79
+ return sum('sha224', data)
80
+ }
81
+
82
+ export async function Sum256(data: $.Bytes): Promise<Uint8Array> {
83
+ return sum('sha256', data)
84
+ }
85
+
86
+ async function sum(
87
+ algorithm: ShaAlgorithm,
88
+ data: $.Bytes,
89
+ ): Promise<Uint8Array> {
90
+ const hash = createNodeHash(algorithm)
91
+ if (hash != null) {
92
+ return new Uint8Array(hash.update($.bytesToUint8Array(data)).digest())
93
+ }
94
+
95
+ if (algorithm === 'sha224') {
96
+ throw new Error(
97
+ new Sha256Error('crypto/sha256: SHA-224 digest is unavailable').Error(),
98
+ )
99
+ }
100
+
101
+ const subtle = subtleCrypto()
102
+ if (subtle == null) {
103
+ throw new Error(
104
+ new Sha256Error('crypto/sha256: WebCrypto digest is unavailable').Error(),
105
+ )
106
+ }
107
+
108
+ const digest = await subtle.digest(
109
+ 'SHA-256',
110
+ $.bytesToUint8Array(data) as unknown as BufferSource,
111
+ )
112
+ return new Uint8Array(digest)
113
+ }
114
+
115
+ function appendDigest(prefix: Uint8Array, digest: Uint8Array): Uint8Array {
116
+ const out = new Uint8Array(prefix.length + digest.length)
117
+ out.set(prefix)
118
+ out.set(digest, prefix.length)
119
+ return out
120
+ }
121
+
122
+ function createNodeHash(algorithm: ShaAlgorithm): NodeCryptoHash | null {
123
+ const nodeCrypto = getHostRuntime().nodeCrypto
124
+ if (!nodeCrypto?.createHash) {
125
+ return null
126
+ }
127
+ try {
128
+ return nodeCrypto.createHash(algorithm)
129
+ } catch {
130
+ return null
131
+ }
132
+ }
133
+
134
+ function concatChunks(chunks: Uint8Array[], length: number): Uint8Array {
135
+ const out = new Uint8Array(length)
136
+ let offset = 0
137
+ for (const chunk of chunks) {
138
+ out.set(chunk, offset)
139
+ offset += chunk.length
140
+ }
141
+ return out
142
+ }
143
+
144
+ function subtleCrypto(): SubtleCrypto | null {
145
+ const crypto = globalThis.crypto
146
+ if (crypto?.subtle && typeof crypto.subtle.digest === 'function') {
147
+ return crypto.subtle
148
+ }
149
+ return null
150
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "asyncFunctions": {
3
+ "Sum224": true,
4
+ "Sum256": true
5
+ },
6
+ "asyncMethods": {
7
+ "Digest.Sum": true
8
+ }
9
+ }
@@ -0,0 +1,31 @@
1
+ import { createHash } from 'node:crypto'
2
+ import { describe, expect, it } from 'vitest'
3
+
4
+ import { New, Sum384, Sum512, Sum512_224, Sum512_256 } from './index.js'
5
+
6
+ describe('crypto/sha512 override', () => {
7
+ it('matches Node digests', async () => {
8
+ const data = new TextEncoder().encode('goscript sha512')
9
+
10
+ expect(toHex(await Sum512(data))).toBe(nodeHash('sha512', data))
11
+ expect(toHex(await Sum384(data))).toBe(nodeHash('sha384', data))
12
+ expect(toHex(await Sum512_224(data))).toBe(nodeHash('sha512-224', data))
13
+ expect(toHex(await Sum512_256(data))).toBe(nodeHash('sha512-256', data))
14
+ })
15
+
16
+ it('supports incremental hash.Hash use', async () => {
17
+ const h = New()
18
+ h.Write(new TextEncoder().encode('go'))
19
+ h.Write(new TextEncoder().encode('script'))
20
+
21
+ expect(toHex(await h.Sum(null))).toBe(nodeHash('sha512', new TextEncoder().encode('goscript')))
22
+ })
23
+ })
24
+
25
+ function nodeHash(algorithm: string, data: Uint8Array): string {
26
+ return createHash(algorithm).update(data).digest('hex')
27
+ }
28
+
29
+ function toHex(value: Uint8Array): string {
30
+ return Buffer.from(value).toString('hex')
31
+ }
@@ -0,0 +1,161 @@
1
+ import * as $ from '@goscript/builtin/index.js'
2
+ import {
3
+ getHostRuntime,
4
+ type NodeCryptoHash,
5
+ } from '@goscript/builtin/hostio.js'
6
+
7
+ export const Size = 64
8
+ export const Size224 = 28
9
+ export const Size256 = 32
10
+ export const Size384 = 48
11
+ export const BlockSize = 128
12
+
13
+ type ShaAlgorithm = 'sha384' | 'sha512' | 'sha512-224' | 'sha512-256'
14
+
15
+ class Digest {
16
+ private chunks: Uint8Array[] = []
17
+ private dataLength = 0
18
+ private hash: NodeCryptoHash | null
19
+ private canCopyHash: boolean
20
+
21
+ constructor(private readonly algorithm: ShaAlgorithm) {
22
+ this.hash = createNodeHash(algorithm)
23
+ this.canCopyHash = typeof this.hash?.copy === 'function'
24
+ }
25
+
26
+ Write(p: $.Bytes): [number, $.GoError] {
27
+ const bytes = $.bytesToUint8Array(p)
28
+ this.hash?.update(bytes)
29
+ if (!this.canCopyHash) {
30
+ this.chunks.push(bytes.slice())
31
+ this.dataLength += bytes.length
32
+ }
33
+ return [bytes.length, null]
34
+ }
35
+
36
+ async Sum(b: $.Bytes): Promise<$.Bytes> {
37
+ const digest =
38
+ this.canCopyHash ?
39
+ new Uint8Array(this.hash!.copy!().digest())
40
+ : await sum(this.algorithm, this.snapshotBytes())
41
+ return appendDigest($.bytesToUint8Array(b), digest)
42
+ }
43
+
44
+ Reset(): void {
45
+ this.chunks = []
46
+ this.dataLength = 0
47
+ this.hash = createNodeHash(this.algorithm)
48
+ this.canCopyHash = typeof this.hash?.copy === 'function'
49
+ }
50
+
51
+ Size(): number {
52
+ switch (this.algorithm) {
53
+ case 'sha384':
54
+ return Size384
55
+ case 'sha512-224':
56
+ return Size224
57
+ case 'sha512-256':
58
+ return Size256
59
+ default:
60
+ return Size
61
+ }
62
+ }
63
+
64
+ BlockSize(): number {
65
+ return BlockSize
66
+ }
67
+
68
+ private snapshotBytes(): Uint8Array {
69
+ return concatChunks(this.chunks, this.dataLength)
70
+ }
71
+ }
72
+
73
+ export function New(): any {
74
+ return new Digest('sha512')
75
+ }
76
+
77
+ export function New384(): any {
78
+ return new Digest('sha384')
79
+ }
80
+
81
+ export function New512_224(): any {
82
+ return new Digest('sha512-224')
83
+ }
84
+
85
+ export function New512_256(): any {
86
+ return new Digest('sha512-256')
87
+ }
88
+
89
+ export async function Sum384(data: $.Bytes): Promise<Uint8Array> {
90
+ return sum('sha384', data)
91
+ }
92
+
93
+ export async function Sum512(data: $.Bytes): Promise<Uint8Array> {
94
+ return sum('sha512', data)
95
+ }
96
+
97
+ export async function Sum512_224(data: $.Bytes): Promise<Uint8Array> {
98
+ return sum('sha512-224', data)
99
+ }
100
+
101
+ export async function Sum512_256(data: $.Bytes): Promise<Uint8Array> {
102
+ return sum('sha512-256', data)
103
+ }
104
+
105
+ async function sum(
106
+ algorithm: ShaAlgorithm,
107
+ data: $.Bytes,
108
+ ): Promise<Uint8Array> {
109
+ const hash = createNodeHash(algorithm)
110
+ if (hash != null) {
111
+ return new Uint8Array(hash.update($.bytesToUint8Array(data)).digest())
112
+ }
113
+
114
+ const subtle = subtleCrypto()
115
+ if (subtle == null || (algorithm !== 'sha384' && algorithm !== 'sha512')) {
116
+ throw new Error(`crypto/sha512: ${algorithm} digest is unavailable`)
117
+ }
118
+
119
+ const digest = await subtle.digest(
120
+ algorithm === 'sha384' ? 'SHA-384' : 'SHA-512',
121
+ $.bytesToUint8Array(data) as unknown as BufferSource,
122
+ )
123
+ return new Uint8Array(digest)
124
+ }
125
+
126
+ function appendDigest(prefix: Uint8Array, digest: Uint8Array): Uint8Array {
127
+ const out = new Uint8Array(prefix.length + digest.length)
128
+ out.set(prefix)
129
+ out.set(digest, prefix.length)
130
+ return out
131
+ }
132
+
133
+ function createNodeHash(algorithm: ShaAlgorithm): NodeCryptoHash | null {
134
+ const nodeCrypto = getHostRuntime().nodeCrypto
135
+ if (!nodeCrypto?.createHash) {
136
+ return null
137
+ }
138
+ try {
139
+ return nodeCrypto.createHash(algorithm)
140
+ } catch {
141
+ return null
142
+ }
143
+ }
144
+
145
+ function concatChunks(chunks: Uint8Array[], length: number): Uint8Array {
146
+ const out = new Uint8Array(length)
147
+ let offset = 0
148
+ for (const chunk of chunks) {
149
+ out.set(chunk, offset)
150
+ offset += chunk.length
151
+ }
152
+ return out
153
+ }
154
+
155
+ function subtleCrypto(): SubtleCrypto | null {
156
+ const crypto = globalThis.crypto
157
+ if (crypto?.subtle && typeof crypto.subtle.digest === 'function') {
158
+ return crypto.subtle
159
+ }
160
+ return null
161
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "asyncFunctions": {
3
+ "Sum384": true,
4
+ "Sum512": true,
5
+ "Sum512_224": true,
6
+ "Sum512_256": true
7
+ },
8
+ "asyncMethods": {
9
+ "Digest.Sum": true
10
+ }
11
+ }
@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest'
2
2
 
3
3
  import * as $ from '@goscript/builtin/index.js'
4
4
 
5
- import { Marshal, MarshalIndent, Unmarshal } from './index.js'
5
+ import { Marshal, MarshalIndent, Unmarshal, type Unmarshaler } from './index.js'
6
6
 
7
7
  class Person {
8
8
  public _fields = {
@@ -17,14 +17,36 @@ class Person {
17
17
  [],
18
18
  Person,
19
19
  {
20
- Name: { type: { kind: $.TypeKind.Basic, name: 'string' }, tag: 'json:"name"' },
20
+ Name: {
21
+ type: { kind: $.TypeKind.Basic, name: 'string' },
22
+ tag: 'json:"name"',
23
+ },
21
24
  Age: { type: { kind: $.TypeKind.Basic, name: 'int' }, tag: 'json:"age"' },
22
- Active: { type: { kind: $.TypeKind.Basic, name: 'bool' }, tag: 'json:"active"' },
25
+ Active: {
26
+ type: { kind: $.TypeKind.Basic, name: 'bool' },
27
+ tag: 'json:"active"',
28
+ },
23
29
  },
24
30
  )
25
31
  }
26
32
 
27
33
  describe('encoding/json override', () => {
34
+ it('registers the Unmarshaler interface shape', () => {
35
+ class CustomUnmarshaler implements Unmarshaler {
36
+ UnmarshalJSON(_data: $.Slice<number>): $.GoError {
37
+ return null
38
+ }
39
+ }
40
+
41
+ const [value, ok] = $.typeAssertTuple<Unmarshaler>(
42
+ new CustomUnmarshaler(),
43
+ 'json.Unmarshaler',
44
+ )
45
+
46
+ expect(ok).toBe(true)
47
+ expect(value.UnmarshalJSON($.stringToBytes('{}'))).toBeNull()
48
+ })
49
+
28
50
  it('marshals struct fields through json tags', () => {
29
51
  const person = new Person()
30
52
  person._fields.Name.value = 'Alice'
@@ -1,5 +1,25 @@
1
1
  import * as $ from '@goscript/builtin/index.js'
2
2
 
3
+ export interface Unmarshaler {
4
+ UnmarshalJSON(data: $.Slice<number>): $.GoError
5
+ }
6
+
7
+ $.registerInterfaceType('json.Unmarshaler', null, [
8
+ {
9
+ name: 'UnmarshalJSON',
10
+ args: [
11
+ {
12
+ name: 'data',
13
+ type: {
14
+ kind: $.TypeKind.Slice,
15
+ elemType: { kind: $.TypeKind.Basic, name: 'uint8' },
16
+ },
17
+ },
18
+ ],
19
+ returns: [{ type: 'GoError' }],
20
+ },
21
+ ])
22
+
3
23
  export function Marshal(v: unknown): [$.Slice<number>, $.GoError] {
4
24
  try {
5
25
  return [$.stringToBytes(JSON.stringify(marshalValue(v))), null]
@@ -147,9 +167,7 @@ function isPlainObject(value: unknown): value is Record<string, unknown> {
147
167
  )
148
168
  }
149
169
 
150
- function structFieldMetadata(
151
- value: unknown,
152
- ): Record<string, { tag?: string }> {
170
+ function structFieldMetadata(value: unknown): Record<string, { tag?: string }> {
153
171
  if (value === null || typeof value !== 'object') {
154
172
  return {}
155
173
  }
@@ -43,7 +43,10 @@ describe('errors.AsType', () => {
43
43
 
44
44
  it('walks wrapped errors depth first', () => {
45
45
  const dns = $.interfaceValue<$.GoError>(new DNSError(), '*net.DNSError')
46
- const wrapped = $.interfaceValue<$.GoError>(new Wrapper(dns), '*main.Wrapper')
46
+ const wrapped = $.interfaceValue<$.GoError>(
47
+ new Wrapper(dns),
48
+ '*main.Wrapper',
49
+ )
47
50
 
48
51
  const [matched, ok] = AsType(dnsTypeArgs, Join(null, wrapped))
49
52
 
@@ -191,10 +191,7 @@ export function As(err: $.GoError, target: any): boolean {
191
191
  throw new Error('errors: target cannot be nil')
192
192
  }
193
193
 
194
- // Check if err matches target type
195
- if (err.constructor === target.constructor) {
196
- // Copy properties from err to target
197
- Object.assign(target, err)
194
+ if (assignAsTarget(err, target)) {
198
195
  return true
199
196
  }
200
197
 
@@ -230,6 +227,36 @@ export function As(err: $.GoError, target: any): boolean {
230
227
  return false
231
228
  }
232
229
 
230
+ function assignAsTarget(err: Exclude<$.GoError, null>, target: any): boolean {
231
+ const targetType = asTargetType(target)
232
+ if (targetType !== undefined) {
233
+ const [matched, ok] = $.typeAssertTuple<any>(err, targetType)
234
+ if (!ok) {
235
+ return false
236
+ }
237
+ if ($.isVarRef(target)) {
238
+ target.value = matched
239
+ return true
240
+ }
241
+ Object.assign(target, matched)
242
+ return true
243
+ }
244
+
245
+ if (err.constructor === target.constructor) {
246
+ Object.assign(target, err)
247
+ return true
248
+ }
249
+ return false
250
+ }
251
+
252
+ function asTargetType(target: any): string | undefined {
253
+ const goType = target?.__goType
254
+ if (typeof goType !== 'string' || !goType.startsWith('*')) {
255
+ return undefined
256
+ }
257
+ return goType.slice(1)
258
+ }
259
+
233
260
  // AsType finds the first error in err's tree that matches the generic error
234
261
  // type E, returning the matching error and true. Otherwise it returns E's zero
235
262
  // value and false.
@@ -263,10 +290,7 @@ function asType(
263
290
  const result = (err as any).Unwrap()
264
291
  if (Array.isArray(result)) {
265
292
  for (const wrappedErr of result) {
266
- if (
267
- wrappedErr &&
268
- typeof wrappedErr.Error === 'function'
269
- ) {
293
+ if (wrappedErr && typeof wrappedErr.Error === 'function') {
270
294
  const [matched, matchedOK] = asType(wrappedErr, typeInfo, zero)
271
295
  if (matchedOK) {
272
296
  return [matched, true]
@@ -1,5 +1,6 @@
1
1
  import { afterEach, describe, expect, it, vi } from 'vitest'
2
2
  import { resetHostRuntimeForTests } from '@goscript/builtin/hostio.js'
3
+ import * as $ from '@goscript/builtin/index.js'
3
4
  import * as fmt from './fmt.js'
4
5
 
5
6
  const originalDeno = (globalThis as any).Deno
@@ -36,7 +37,9 @@ function captureStdout(run: () => void): string {
36
37
  length?: number,
37
38
  _position?: number | null,
38
39
  ) => {
39
- buf += new TextDecoder().decode(chunk.subarray(0, length ?? chunk.length))
40
+ buf += new TextDecoder().decode(
41
+ chunk.subarray(0, length ?? chunk.length),
42
+ )
40
43
  return length ?? chunk.length
41
44
  },
42
45
  ),
@@ -185,3 +188,22 @@ describe('fmt parseFormat basic cases', () => {
185
188
  expect(fmt.Sprintf('%c', 65)).toBe('A')
186
189
  })
187
190
  })
191
+
192
+ describe('fmt scanning', () => {
193
+ it('scans decimal fields separated by literals', () => {
194
+ const start = $.varRef(0)
195
+ const end = $.varRef(0)
196
+
197
+ const [n, err] = fmt.Sscanf(
198
+ 'bytes=12-34',
199
+ 'bytes=%d-%d',
200
+ $.interfaceValue(start, '*int64'),
201
+ $.interfaceValue(end, '*int64'),
202
+ )
203
+
204
+ expect(err).toBeNull()
205
+ expect(n).toBe(2)
206
+ expect(start.value).toBe(12)
207
+ expect(end.value).toBe(34)
208
+ })
209
+ })