goscript 0.2.3 → 0.2.5

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 (160) hide show
  1. package/README.md +8 -8
  2. package/cmd/go_js_wasm_exec/main.go +1 -1
  3. package/cmd/go_js_wasm_exec/main_test.go +1 -1
  4. package/cmd/goscript/cmd-compile.go +9 -1
  5. package/cmd/goscript/cmd-test.go +1 -1
  6. package/cmd/goscript/cmd_compile_test.go +44 -0
  7. package/cmd/goscript/deps.go +1 -1
  8. package/cmd/goscript-wasm/main.go +2 -2
  9. package/compiler/compile-request.go +19 -0
  10. package/compiler/compile_bench_test.go +121 -0
  11. package/compiler/compliance_test.go +17 -1
  12. package/compiler/config.go +2 -0
  13. package/compiler/gotest/result.go +1 -1
  14. package/compiler/gotest/runner.go +2 -2
  15. package/compiler/gotest/runner_test.go +4 -7
  16. package/compiler/index.test.ts +28 -0
  17. package/compiler/index.ts +32 -16
  18. package/compiler/lowering.go +1236 -143
  19. package/compiler/lowering_bench_test.go +4 -0
  20. package/compiler/override-facts.go +1 -1
  21. package/compiler/override-registry_test.go +125 -0
  22. package/compiler/package-graph.go +92 -0
  23. package/compiler/package-graph_test.go +113 -0
  24. package/compiler/runtime-contract.go +1 -1
  25. package/compiler/semantic-model.go +32 -0
  26. package/compiler/skeleton_test.go +284 -11
  27. package/compiler/wasm/compile.go +1 -1
  28. package/compiler/wasm/compile_test.go +1 -1
  29. package/dist/compiler/index.d.ts +4 -0
  30. package/dist/compiler/index.js +26 -15
  31. package/dist/compiler/index.js.map +1 -1
  32. package/dist/gs/compress/gzip/index.d.ts +41 -0
  33. package/dist/gs/compress/gzip/index.js +235 -0
  34. package/dist/gs/compress/gzip/index.js.map +1 -0
  35. package/dist/gs/database/sql/driver/index.d.ts +165 -0
  36. package/dist/gs/database/sql/driver/index.js +432 -0
  37. package/dist/gs/database/sql/driver/index.js.map +1 -0
  38. package/dist/gs/encoding/binary/index.d.ts +71 -0
  39. package/dist/gs/encoding/binary/index.js +778 -0
  40. package/dist/gs/encoding/binary/index.js.map +1 -0
  41. package/dist/gs/fmt/fmt.js +156 -57
  42. package/dist/gs/fmt/fmt.js.map +1 -1
  43. package/dist/gs/github.com/klauspost/cpuid/v2/index.d.ts +11 -0
  44. package/dist/gs/github.com/klauspost/cpuid/v2/index.js +28 -0
  45. package/dist/gs/github.com/klauspost/cpuid/v2/index.js.map +1 -0
  46. package/dist/gs/github.com/pkg/errors/errors.d.ts +0 -2
  47. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  48. package/dist/gs/github.com/pkg/errors/index.d.ts +2 -1
  49. package/dist/gs/github.com/pkg/errors/index.js +1 -1
  50. package/dist/gs/github.com/pkg/errors/index.js.map +1 -1
  51. package/dist/gs/github.com/pkg/errors/stack.d.ts +8 -19
  52. package/dist/gs/github.com/pkg/errors/stack.js +26 -61
  53. package/dist/gs/github.com/pkg/errors/stack.js.map +1 -1
  54. package/dist/gs/golang.org/x/crypto/cryptobyte/asn1/index.d.ts +19 -0
  55. package/dist/gs/golang.org/x/crypto/cryptobyte/asn1/index.js +25 -0
  56. package/dist/gs/golang.org/x/crypto/cryptobyte/asn1/index.js.map +1 -0
  57. package/dist/gs/golang.org/x/crypto/cryptobyte/index.d.ts +104 -0
  58. package/dist/gs/golang.org/x/crypto/cryptobyte/index.js +1107 -0
  59. package/dist/gs/golang.org/x/crypto/cryptobyte/index.js.map +1 -0
  60. package/dist/gs/golang.org/x/crypto/internal/alias/index.d.ts +3 -0
  61. package/dist/gs/golang.org/x/crypto/internal/alias/index.js +39 -0
  62. package/dist/gs/golang.org/x/crypto/internal/alias/index.js.map +1 -0
  63. package/dist/gs/io/fs/glob.js +1 -1
  64. package/dist/gs/io/fs/glob.js.map +1 -1
  65. package/dist/gs/io/fs/readlink.d.ts +1 -1
  66. package/dist/gs/io/fs/readlink.js +2 -2
  67. package/dist/gs/io/fs/readlink.js.map +1 -1
  68. package/dist/gs/io/fs/stat.d.ts +4 -2
  69. package/dist/gs/io/fs/stat.js +12 -73
  70. package/dist/gs/io/fs/stat.js.map +1 -1
  71. package/dist/gs/io/fs/sub.d.ts +2 -2
  72. package/dist/gs/io/fs/sub.js +7 -7
  73. package/dist/gs/io/fs/sub.js.map +1 -1
  74. package/dist/gs/io/fs/walk.js +1 -1
  75. package/dist/gs/io/fs/walk.js.map +1 -1
  76. package/dist/gs/net/http/index.d.ts +18 -14
  77. package/dist/gs/net/http/index.js +44 -23
  78. package/dist/gs/net/http/index.js.map +1 -1
  79. package/dist/gs/net/http/pprof/index.d.ts +5 -5
  80. package/dist/gs/net/http/pprof/index.js +21 -21
  81. package/dist/gs/net/http/pprof/index.js.map +1 -1
  82. package/dist/gs/runtime/runtime.d.ts +6 -1
  83. package/dist/gs/runtime/runtime.js +15 -8
  84. package/dist/gs/runtime/runtime.js.map +1 -1
  85. package/dist/gs/runtime/trace/index.d.ts +8 -5
  86. package/dist/gs/runtime/trace/index.js +324 -23
  87. package/dist/gs/runtime/trace/index.js.map +1 -1
  88. package/dist/gs/slices/slices.d.ts +2 -1
  89. package/dist/gs/slices/slices.js +9 -3
  90. package/dist/gs/slices/slices.js.map +1 -1
  91. package/dist/gs/sort/search.gs.d.ts +3 -1
  92. package/dist/gs/sort/search.gs.js +18 -53
  93. package/dist/gs/sort/search.gs.js.map +1 -1
  94. package/dist/gs/sync/sync.d.ts +1 -1
  95. package/dist/gs/sync/sync.js +3 -0
  96. package/dist/gs/sync/sync.js.map +1 -1
  97. package/dist/gs/time/time.d.ts +22 -29
  98. package/dist/gs/time/time.js +111 -32
  99. package/dist/gs/time/time.js.map +1 -1
  100. package/dist/gs/unsafe/unsafe.d.ts +3 -2
  101. package/dist/gs/unsafe/unsafe.js.map +1 -1
  102. package/go.mod +7 -5
  103. package/go.sum +12 -26
  104. package/gs/builtin/runtime-contract.test.ts +25 -0
  105. package/gs/compress/gzip/index.test.ts +86 -0
  106. package/gs/compress/gzip/index.ts +297 -0
  107. package/gs/compress/gzip/meta.json +6 -0
  108. package/gs/compress/gzip/parity.json +45 -0
  109. package/gs/database/sql/driver/index.test.ts +88 -0
  110. package/gs/database/sql/driver/index.ts +675 -0
  111. package/gs/database/sql/driver/meta.json +3 -0
  112. package/gs/database/sql/driver/parity.json +144 -0
  113. package/gs/embed/index.test.ts +1 -1
  114. package/gs/encoding/binary/index.test.ts +239 -0
  115. package/gs/encoding/binary/index.ts +999 -0
  116. package/gs/encoding/binary/meta.json +9 -0
  117. package/gs/encoding/binary/parity.json +72 -0
  118. package/gs/fmt/fmt.test.ts +28 -0
  119. package/gs/fmt/fmt.ts +198 -61
  120. package/gs/fmt/meta.json +2 -1
  121. package/gs/github.com/klauspost/cpuid/v2/index.ts +38 -0
  122. package/gs/github.com/klauspost/cpuid/v2/meta.json +3 -0
  123. package/gs/github.com/pkg/errors/errors.ts +1 -2
  124. package/gs/github.com/pkg/errors/index.ts +2 -1
  125. package/gs/github.com/pkg/errors/stack.ts +34 -62
  126. package/gs/golang.org/x/crypto/cryptobyte/asn1/index.test.ts +19 -0
  127. package/gs/golang.org/x/crypto/cryptobyte/asn1/index.ts +29 -0
  128. package/gs/golang.org/x/crypto/cryptobyte/index.test.ts +255 -0
  129. package/gs/golang.org/x/crypto/cryptobyte/index.ts +1441 -0
  130. package/gs/golang.org/x/crypto/cryptobyte/meta.json +3 -0
  131. package/gs/golang.org/x/crypto/internal/alias/index.test.ts +40 -0
  132. package/gs/golang.org/x/crypto/internal/alias/index.ts +40 -0
  133. package/gs/io/fs/glob.ts +1 -1
  134. package/gs/io/fs/meta.json +3 -0
  135. package/gs/io/fs/readlink.test.ts +2 -2
  136. package/gs/io/fs/readlink.ts +5 -2
  137. package/gs/io/fs/stat.test.ts +79 -0
  138. package/gs/io/fs/stat.ts +24 -10
  139. package/gs/io/fs/sub.test.ts +93 -0
  140. package/gs/io/fs/sub.ts +9 -9
  141. package/gs/io/fs/walk.ts +1 -1
  142. package/gs/net/http/index.test.ts +207 -2
  143. package/gs/net/http/index.ts +68 -37
  144. package/gs/net/http/meta.json +3 -1
  145. package/gs/net/http/pprof/index.test.ts +4 -4
  146. package/gs/net/http/pprof/index.ts +30 -27
  147. package/gs/runtime/runtime.test.ts +16 -0
  148. package/gs/runtime/runtime.ts +17 -9
  149. package/gs/runtime/trace/index.test.ts +113 -14
  150. package/gs/runtime/trace/index.ts +384 -34
  151. package/gs/runtime/trace/meta.json +1 -0
  152. package/gs/slices/slices.test.ts +24 -1
  153. package/gs/slices/slices.ts +14 -4
  154. package/gs/sort/meta.json +1 -0
  155. package/gs/sort/search.gs.ts +20 -5
  156. package/gs/sync/sync.ts +4 -1
  157. package/gs/time/time.test.ts +79 -2
  158. package/gs/time/time.ts +133 -33
  159. package/gs/unsafe/unsafe.ts +4 -2
  160. package/package.json +2 -2
@@ -0,0 +1,297 @@
1
+ import * as $ from '@goscript/builtin/index.js'
2
+ import * as errors from '@goscript/errors/index.js'
3
+ import * as io from '@goscript/io/index.js'
4
+
5
+ type maybeAsyncWriter = {
6
+ Write(p: $.Bytes): [number, $.GoError] | Promise<[number, $.GoError]>
7
+ }
8
+
9
+ type compressionRuntime = {
10
+ gzipSync?: (data: Uint8Array, opts?: Record<string, unknown>) => Uint8Array
11
+ gunzipSync?: (data: Uint8Array) => Uint8Array
12
+ }
13
+
14
+ export const NoCompression = 0
15
+ export const BestSpeed = 1
16
+ export const BestCompression = 9
17
+ export const DefaultCompression = -1
18
+ export const HuffmanOnly = -2
19
+
20
+ export let ErrChecksum = errors.New('gzip: invalid checksum')
21
+ export let ErrHeader = errors.New('gzip: invalid header')
22
+
23
+ export function __goscript_set_ErrChecksum(value: $.GoError): void {
24
+ ErrChecksum = value
25
+ }
26
+
27
+ export function __goscript_set_ErrHeader(value: $.GoError): void {
28
+ ErrHeader = value
29
+ }
30
+
31
+ export class Header {
32
+ Comment = ''
33
+ Extra: $.Bytes = null
34
+ ModTime: any = null
35
+ Name = ''
36
+ OS = 255
37
+ }
38
+
39
+ export class Reader {
40
+ private data: Uint8Array = new Uint8Array(0)
41
+ private offset = 0
42
+ private pending: Promise<{ data: Uint8Array | null; err: $.GoError }> | null =
43
+ null
44
+
45
+ constructor(r?: io.Reader | null) {
46
+ if (r != null) {
47
+ this.Reset(r)
48
+ }
49
+ }
50
+
51
+ async Read(p: $.Bytes): Promise<[number, $.GoError]> {
52
+ const pending = this.pending
53
+ if (pending != null) {
54
+ this.pending = null
55
+ const result = await pending
56
+ if (result.err != null) {
57
+ return [0, result.err]
58
+ }
59
+ this.data = result.data ?? new Uint8Array(0)
60
+ this.offset = 0
61
+ }
62
+ if (this.offset >= this.data.length) {
63
+ return [0, io.EOF]
64
+ }
65
+ const out = $.bytesToUint8Array(p)
66
+ const n = Math.min(out.length, this.data.length - this.offset)
67
+ out.set(this.data.subarray(this.offset, this.offset + n))
68
+ this.offset += n
69
+ return [n, null]
70
+ }
71
+
72
+ Close(): $.GoError {
73
+ return null
74
+ }
75
+
76
+ Reset(r: io.Reader | null): $.GoError {
77
+ if (r == null) {
78
+ return errors.New('gzip: nil reader')
79
+ }
80
+ const result = readGunzipped(r)
81
+ this.data = new Uint8Array(0)
82
+ this.offset = 0
83
+ if (result instanceof Promise) {
84
+ this.pending = result
85
+ return null
86
+ }
87
+ this.pending = null
88
+ if (result.err != null) {
89
+ return result.err
90
+ }
91
+ this.data = result.data ?? new Uint8Array(0)
92
+ return null
93
+ }
94
+ }
95
+
96
+ export class Writer {
97
+ private chunks: Uint8Array[] = []
98
+ private closed = false
99
+
100
+ constructor(
101
+ private w: io.Writer | null,
102
+ private level = DefaultCompression,
103
+ ) {}
104
+
105
+ Write(p: $.Bytes): [number, $.GoError] {
106
+ if (this.closed) {
107
+ return [0, errors.New('gzip: writer closed')]
108
+ }
109
+ const data = $.bytesToUint8Array(p)
110
+ this.chunks.push(data.slice())
111
+ return [data.length, null]
112
+ }
113
+
114
+ async Close(): Promise<$.GoError> {
115
+ if (this.closed) {
116
+ return null
117
+ }
118
+ this.closed = true
119
+ if (this.w == null) {
120
+ return errors.New('gzip: nil writer')
121
+ }
122
+ const compressed = await gzipBytes(concat(this.chunks), this.level)
123
+ const writer = $.pointerValue<maybeAsyncWriter>(this.w)
124
+ const [, err] = await writer.Write(compressed)
125
+ return err
126
+ }
127
+
128
+ Flush(): $.GoError {
129
+ return null
130
+ }
131
+
132
+ Reset(w: io.Writer | null): void {
133
+ this.w = w
134
+ this.chunks = []
135
+ this.closed = false
136
+ }
137
+ }
138
+
139
+ export function NewReader(
140
+ r: io.Reader | null,
141
+ ): [io.ReadCloser | null, $.GoError] {
142
+ const reader = new Reader()
143
+ const err = reader.Reset(r)
144
+ if (err != null) {
145
+ return [null, err]
146
+ }
147
+ return [reader as any, null]
148
+ }
149
+
150
+ export function NewWriter(w: io.Writer | null): Writer {
151
+ return new Writer(w)
152
+ }
153
+
154
+ export function NewWriterLevel(
155
+ w: io.Writer | null,
156
+ level: number,
157
+ ): [Writer | null, $.GoError] {
158
+ if (level < HuffmanOnly || level > BestCompression) {
159
+ return [null, errors.New(`gzip: invalid compression level: ${level}`)]
160
+ }
161
+ return [new Writer(w, level), null]
162
+ }
163
+
164
+ async function gzipBytes(data: Uint8Array, level: number): Promise<Uint8Array> {
165
+ const runtime = nodeCompressionRuntime()
166
+ if (runtime?.gzipSync != null) {
167
+ return runtime.gzipSync(data, { level })
168
+ }
169
+
170
+ const CompressionStreamCtor = (globalThis as any).CompressionStream
171
+ if (typeof CompressionStreamCtor !== 'function') {
172
+ throw new Error('compress/gzip: CompressionStream unavailable')
173
+ }
174
+ return streamTransform(data, new CompressionStreamCtor('gzip'))
175
+ }
176
+
177
+ function gunzipBytes(
178
+ data: Uint8Array,
179
+ ): Uint8Array | Promise<Uint8Array> {
180
+ const runtime = nodeCompressionRuntime()
181
+ if (runtime?.gunzipSync != null) {
182
+ return runtime.gunzipSync(data)
183
+ }
184
+
185
+ const DecompressionStreamCtor = (globalThis as any).DecompressionStream
186
+ if (typeof DecompressionStreamCtor !== 'function') {
187
+ throw new Error('compress/gzip: DecompressionStream unavailable')
188
+ }
189
+ return streamTransform(data, new DecompressionStreamCtor('gzip'))
190
+ }
191
+
192
+ async function streamTransform(
193
+ data: Uint8Array,
194
+ stream: ReadableWritablePair<Uint8Array, Uint8Array>,
195
+ ): Promise<Uint8Array> {
196
+ const body = new ArrayBuffer(data.length)
197
+ new Uint8Array(body).set(data)
198
+ const response = new Response(
199
+ new Blob([body]).stream().pipeThrough(stream as any),
200
+ )
201
+ return new Uint8Array(await response.arrayBuffer())
202
+ }
203
+
204
+ function readGunzipped(
205
+ r: io.Reader,
206
+ ):
207
+ | { data: Uint8Array | null; err: $.GoError }
208
+ | Promise<{ data: Uint8Array | null; err: $.GoError }> {
209
+ const chunks: Uint8Array[] = []
210
+ const buf = $.makeSlice<number>(1, undefined, 'byte')
211
+ while (true) {
212
+ const read = r.Read(buf)
213
+ if (read instanceof Promise) {
214
+ return readGunzippedAsync(read, r, buf, chunks)
215
+ }
216
+ const [n, err] = read
217
+ recordChunk(chunks, buf, n)
218
+ if (err != null) {
219
+ if (err === io.EOF) {
220
+ return inflateRecorded(chunks)
221
+ }
222
+ return { data: null, err }
223
+ }
224
+ }
225
+ }
226
+
227
+ async function readGunzippedAsync(
228
+ read: Promise<[number, $.GoError]>,
229
+ r: io.Reader,
230
+ buf: $.Bytes,
231
+ chunks: Uint8Array[],
232
+ ): Promise<{ data: Uint8Array | null; err: $.GoError }> {
233
+ while (true) {
234
+ const [n, err] = await read
235
+ recordChunk(chunks, buf, n)
236
+ if (err != null) {
237
+ if (err === io.EOF) {
238
+ return inflateRecorded(chunks)
239
+ }
240
+ return { data: null, err }
241
+ }
242
+ read = r.Read(buf) as any
243
+ }
244
+ }
245
+
246
+ function recordChunk(chunks: Uint8Array[], buf: $.Bytes, n: number): void {
247
+ if (n > 0) {
248
+ chunks.push($.bytesToUint8Array($.goSlice(buf, 0, n)).slice())
249
+ }
250
+ }
251
+
252
+ function inflateRecorded(
253
+ chunks: Uint8Array[],
254
+ ): { data: Uint8Array | null; err: $.GoError } | Promise<{
255
+ data: Uint8Array | null
256
+ err: $.GoError
257
+ }> {
258
+ try {
259
+ const inflated = gunzipBytes(concat(chunks))
260
+ if (inflated instanceof Promise) {
261
+ return inflated
262
+ .then((data) => ({ data, err: null }))
263
+ .catch(() => ({ data: null, err: ErrHeader }))
264
+ }
265
+ return { data: inflated, err: null }
266
+ } catch {
267
+ return { data: null, err: ErrHeader }
268
+ }
269
+ }
270
+
271
+ function concat(chunks: Uint8Array[]): Uint8Array {
272
+ let length = 0
273
+ for (const chunk of chunks) {
274
+ length += chunk.length
275
+ }
276
+ const out = new Uint8Array(length)
277
+ let offset = 0
278
+ for (const chunk of chunks) {
279
+ out.set(chunk, offset)
280
+ offset += chunk.length
281
+ }
282
+ return out
283
+ }
284
+
285
+ function nodeCompressionRuntime(): compressionRuntime | null {
286
+ const processObj = (globalThis as any).process
287
+ if (processObj && typeof processObj.getBuiltinModule === 'function') {
288
+ const mod = processObj.getBuiltinModule('zlib')
289
+ if (mod && typeof mod.gzipSync === 'function') {
290
+ return {
291
+ gzipSync: (data, opts) => new Uint8Array(mod.gzipSync(data, opts)),
292
+ gunzipSync: (data) => new Uint8Array(mod.gunzipSync(data)),
293
+ }
294
+ }
295
+ }
296
+ return null
297
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "dependencies": [],
3
+ "asyncMethods": {
4
+ "Writer.Close": true
5
+ }
6
+ }
@@ -0,0 +1,45 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "strict": true,
4
+ "symbols": {
5
+ "BestCompression": {
6
+ "status": "real"
7
+ },
8
+ "BestSpeed": {
9
+ "status": "real"
10
+ },
11
+ "DefaultCompression": {
12
+ "status": "real"
13
+ },
14
+ "ErrChecksum": {
15
+ "status": "real"
16
+ },
17
+ "ErrHeader": {
18
+ "status": "real"
19
+ },
20
+ "Header": {
21
+ "status": "real"
22
+ },
23
+ "HuffmanOnly": {
24
+ "status": "real"
25
+ },
26
+ "NewReader": {
27
+ "status": "real"
28
+ },
29
+ "NewWriter": {
30
+ "status": "real"
31
+ },
32
+ "NewWriterLevel": {
33
+ "status": "real"
34
+ },
35
+ "NoCompression": {
36
+ "status": "real"
37
+ },
38
+ "Reader": {
39
+ "status": "real"
40
+ },
41
+ "Writer": {
42
+ "status": "real"
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,88 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import * as $ from '@goscript/builtin/index.js'
4
+ import * as time from '@goscript/time/index.js'
5
+
6
+ import {
7
+ Bool,
8
+ DefaultParameterConverter,
9
+ ErrBadConn,
10
+ ErrSkip,
11
+ Int32,
12
+ IsScanValue,
13
+ IsValue,
14
+ RowsAffected_LastInsertId,
15
+ RowsAffected_RowsAffected,
16
+ String,
17
+ } from './index.js'
18
+
19
+ function expectGoErrorThrow(fn: () => unknown, message: string): void {
20
+ try {
21
+ fn()
22
+ } catch (err) {
23
+ expect((err as $.GoError)?.Error()).toBe(message)
24
+ return
25
+ }
26
+ throw new Error('expected Go error throw')
27
+ }
28
+
29
+ describe('database/sql/driver override', () => {
30
+ it('recognizes reflect-free Value-compatible inputs', () => {
31
+ expect(IsValue(null)).toBe(true)
32
+ expect(IsValue(new Uint8Array([1, 2]))).toBe(true)
33
+ expect(IsValue('query')).toBe(true)
34
+ expect(IsValue(true)).toBe(true)
35
+ expect(IsValue($.int(7, 64))).toBe(true)
36
+ expect(IsValue($.uint(8, 64))).toBe(true)
37
+ expect(IsValue(1.5)).toBe(true)
38
+ expect(IsValue(9n)).toBe(true)
39
+ expect(IsValue(new time.Time())).toBe(true)
40
+ expect(IsScanValue('scan')).toBe(true)
41
+ expect(IsValue({ unsupported: true })).toBe(false)
42
+ })
43
+
44
+ it('converts supported Bool, String, and Int32 inputs', () => {
45
+ expect(Bool.ConvertValue(true)).toEqual([true, null])
46
+ expect(Bool.ConvertValue('true')).toEqual([true, null])
47
+ expect(Bool.ConvertValue(new Uint8Array([0x30]))).toEqual([false, null])
48
+ expect(String.ConvertValue('already')).toEqual(['already', null])
49
+ expect(Int32.ConvertValue(123)).toEqual([123, null])
50
+ })
51
+
52
+ it('guards reflect-dependent named and pointer converter arms', () => {
53
+ const namedBool = $.namedValueInterfaceValue<unknown>(
54
+ true,
55
+ 'main.NamedBool',
56
+ {},
57
+ )
58
+
59
+ expectGoErrorThrow(
60
+ () => Bool.ConvertValue(namedBool),
61
+ 'database/sql/driver: Bool.ConvertValue of named type is not supported in the GoScript browser build',
62
+ )
63
+ expectGoErrorThrow(
64
+ () => Int32.ConvertValue($.varRef(1)),
65
+ 'database/sql/driver: Int32.ConvertValue of pointer is not supported in the GoScript browser build',
66
+ )
67
+ expectGoErrorThrow(
68
+ () => DefaultParameterConverter.ConvertValue($.varRef(1)),
69
+ 'database/sql/driver: DefaultParameterConverter.ConvertValue of pointer is not supported in the GoScript browser build',
70
+ )
71
+ })
72
+
73
+ it('round trips RowsAffected result methods', () => {
74
+ expect(RowsAffected_RowsAffected(42)).toEqual([42, null])
75
+ const [id, err] = RowsAffected_LastInsertId(42)
76
+ expect(id).toBe(0)
77
+ expect(err?.Error()).toBe('LastInsertId is not supported by this driver')
78
+ })
79
+
80
+ it('keeps sentinel error identity stable', () => {
81
+ const skip = ErrSkip
82
+ const bad = ErrBadConn
83
+
84
+ expect(ErrSkip).toBe(skip)
85
+ expect(ErrBadConn).toBe(bad)
86
+ expect(ErrSkip).not.toBe(ErrBadConn)
87
+ })
88
+ })