goscript 0.2.1 → 0.2.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 (164) hide show
  1. package/compiler/gotest/runner.go +98 -0
  2. package/compiler/gotest/runner_test.go +45 -0
  3. package/compiler/gotest/testdata/browserapi/browserapi_test.go +36 -0
  4. package/compiler/lowering.go +227 -11
  5. package/compiler/override-registry_test.go +50 -0
  6. package/compiler/protobuf-ts-binding.go +155 -7
  7. package/compiler/protobuf-ts-binding_test.go +116 -2
  8. package/compiler/runtime-contract.go +2 -0
  9. package/compiler/runtime-contract_test.go +1 -0
  10. package/compiler/semantic-model.go +16 -0
  11. package/compiler/semantic-model_test.go +38 -0
  12. package/compiler/skeleton_test.go +477 -16
  13. package/compiler/typescript-emitter.go +4 -0
  14. package/dist/gs/builtin/builtin.js +7 -9
  15. package/dist/gs/builtin/builtin.js.map +1 -1
  16. package/dist/gs/builtin/defer.js +2 -2
  17. package/dist/gs/builtin/hostio.js +5 -5
  18. package/dist/gs/builtin/hostio.js.map +1 -1
  19. package/dist/gs/builtin/map.js +2 -1
  20. package/dist/gs/builtin/map.js.map +1 -1
  21. package/dist/gs/builtin/slice.d.ts +3 -0
  22. package/dist/gs/builtin/slice.js +39 -0
  23. package/dist/gs/builtin/slice.js.map +1 -1
  24. package/dist/gs/builtin/type.js +49 -0
  25. package/dist/gs/builtin/type.js.map +1 -1
  26. package/dist/gs/compress/zlib/index.js +5 -2
  27. package/dist/gs/compress/zlib/index.js.map +1 -1
  28. package/dist/gs/crypto/aes/index.d.ts +15 -0
  29. package/dist/gs/crypto/aes/index.js +57 -0
  30. package/dist/gs/crypto/aes/index.js.map +1 -0
  31. package/dist/gs/crypto/cipher/index.d.ts +41 -0
  32. package/dist/gs/crypto/cipher/index.js +255 -0
  33. package/dist/gs/crypto/cipher/index.js.map +1 -0
  34. package/dist/gs/crypto/ecdh/index.js +27 -8
  35. package/dist/gs/crypto/ecdh/index.js.map +1 -1
  36. package/dist/gs/crypto/ed25519/index.js +3 -3
  37. package/dist/gs/crypto/ed25519/index.js.map +1 -1
  38. package/dist/gs/crypto/rand/index.js +6 -3
  39. package/dist/gs/crypto/rand/index.js.map +1 -1
  40. package/dist/gs/embed/index.js +9 -3
  41. package/dist/gs/embed/index.js.map +1 -1
  42. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -0
  43. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +33 -0
  44. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  45. package/dist/gs/github.com/mr-tron/base58/base58/index.js +4 -1
  46. package/dist/gs/github.com/mr-tron/base58/base58/index.js.map +1 -1
  47. package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.d.ts +31 -0
  48. package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.js +117 -0
  49. package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.js.map +1 -0
  50. package/dist/gs/golang.org/x/crypto/scrypt/index.d.ts +2 -0
  51. package/dist/gs/golang.org/x/crypto/scrypt/index.js +39 -0
  52. package/dist/gs/golang.org/x/crypto/scrypt/index.js.map +1 -0
  53. package/dist/gs/hash/fnv/index.js +13 -5
  54. package/dist/gs/hash/fnv/index.js.map +1 -1
  55. package/dist/gs/io/fs/glob.d.ts +3 -3
  56. package/dist/gs/io/fs/glob.js +8 -8
  57. package/dist/gs/io/fs/glob.js.map +1 -1
  58. package/dist/gs/io/fs/readdir.d.ts +2 -2
  59. package/dist/gs/io/fs/readdir.js +13 -74
  60. package/dist/gs/io/fs/readdir.js.map +1 -1
  61. package/dist/gs/io/fs/sub.js +4 -4
  62. package/dist/gs/io/fs/sub.js.map +1 -1
  63. package/dist/gs/io/fs/walk.js +1 -1
  64. package/dist/gs/io/fs/walk.js.map +1 -1
  65. package/dist/gs/io/io.js +18 -2
  66. package/dist/gs/io/io.js.map +1 -1
  67. package/dist/gs/maps/iter.js.map +1 -1
  68. package/dist/gs/maps/maps.js.map +1 -1
  69. package/dist/gs/mime/index.js +5 -2
  70. package/dist/gs/mime/index.js.map +1 -1
  71. package/dist/gs/net/http/httptest/index.js +6 -3
  72. package/dist/gs/net/http/httptest/index.js.map +1 -1
  73. package/dist/gs/net/http/index.d.ts +16 -4
  74. package/dist/gs/net/http/index.js +236 -40
  75. package/dist/gs/net/http/index.js.map +1 -1
  76. package/dist/gs/net/http/pprof/index.js.map +1 -1
  77. package/dist/gs/reflect/iter.js +1 -1
  78. package/dist/gs/reflect/iter.js.map +1 -1
  79. package/dist/gs/reflect/type.d.ts +2 -0
  80. package/dist/gs/reflect/type.js +53 -21
  81. package/dist/gs/reflect/type.js.map +1 -1
  82. package/dist/gs/runtime/debug/index.js +2 -1
  83. package/dist/gs/runtime/debug/index.js.map +1 -1
  84. package/dist/gs/runtime/pprof/index.js.map +1 -1
  85. package/dist/gs/runtime/runtime.js +2 -2
  86. package/dist/gs/runtime/runtime.js.map +1 -1
  87. package/dist/gs/runtime/trace/index.js.map +1 -1
  88. package/dist/gs/slices/slices.d.ts +1 -1
  89. package/dist/gs/slices/slices.js +37 -4
  90. package/dist/gs/slices/slices.js.map +1 -1
  91. package/go.mod +2 -2
  92. package/go.sum +2 -0
  93. package/gs/builtin/builtin.ts +11 -14
  94. package/gs/builtin/defer.ts +2 -2
  95. package/gs/builtin/hostio.test.ts +8 -3
  96. package/gs/builtin/hostio.ts +5 -7
  97. package/gs/builtin/map.ts +4 -1
  98. package/gs/builtin/slice.test.ts +14 -0
  99. package/gs/builtin/slice.ts +64 -0
  100. package/gs/builtin/type.ts +72 -0
  101. package/gs/bytes/bytes.test.ts +14 -13
  102. package/gs/compress/zlib/index.test.ts +19 -5
  103. package/gs/compress/zlib/index.ts +16 -7
  104. package/gs/context/context.test.ts +3 -1
  105. package/gs/crypto/aes/index.test.ts +120 -0
  106. package/gs/crypto/aes/index.ts +76 -0
  107. package/gs/crypto/cipher/index.ts +345 -0
  108. package/gs/crypto/cipher/meta.json +6 -0
  109. package/gs/crypto/ecdh/index.test.ts +6 -2
  110. package/gs/crypto/ecdh/index.ts +49 -12
  111. package/gs/crypto/ed25519/index.ts +20 -7
  112. package/gs/crypto/rand/index.ts +6 -3
  113. package/gs/embed/index.test.ts +3 -3
  114. package/gs/embed/index.ts +9 -3
  115. package/gs/fmt/fmt.test.ts +29 -4
  116. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +126 -0
  117. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +46 -0
  118. package/gs/github.com/mr-tron/base58/base58/index.ts +9 -3
  119. package/gs/github.com/zeebo/blake3/internal/consts/index.test.ts +2 -8
  120. package/gs/golang.org/x/crypto/chacha20poly1305/index.test.ts +91 -0
  121. package/gs/golang.org/x/crypto/chacha20poly1305/index.ts +245 -0
  122. package/gs/golang.org/x/crypto/scrypt/index.test.ts +81 -0
  123. package/gs/golang.org/x/crypto/scrypt/index.ts +54 -0
  124. package/gs/golang.org/x/crypto/scrypt/meta.json +5 -0
  125. package/gs/hash/fnv/index.test.ts +1 -8
  126. package/gs/hash/fnv/index.ts +27 -10
  127. package/gs/io/fs/glob.ts +13 -10
  128. package/gs/io/fs/meta.json +2 -0
  129. package/gs/io/fs/readdir.test.ts +63 -2
  130. package/gs/io/fs/readdir.ts +33 -30
  131. package/gs/io/fs/sub.ts +4 -4
  132. package/gs/io/fs/walk.ts +1 -1
  133. package/gs/io/io.test.ts +56 -1
  134. package/gs/io/io.ts +19 -2
  135. package/gs/maps/iter.ts +9 -9
  136. package/gs/maps/maps.ts +4 -4
  137. package/gs/math/bits/index.test.ts +10 -1
  138. package/gs/mime/index.test.ts +33 -15
  139. package/gs/mime/index.ts +9 -2
  140. package/gs/net/http/httptest/index.test.ts +17 -3
  141. package/gs/net/http/httptest/index.ts +8 -3
  142. package/gs/net/http/index.test.ts +645 -123
  143. package/gs/net/http/index.ts +548 -113
  144. package/gs/net/http/pprof/index.ts +24 -6
  145. package/gs/os/file_unix_js.test.ts +22 -0
  146. package/gs/reflect/iter.ts +4 -2
  147. package/gs/reflect/map.test.ts +56 -1
  148. package/gs/reflect/type.ts +76 -37
  149. package/gs/runtime/debug/index.test.ts +32 -4
  150. package/gs/runtime/debug/index.ts +5 -2
  151. package/gs/runtime/pprof/index.test.ts +7 -1
  152. package/gs/runtime/pprof/index.ts +5 -1
  153. package/gs/runtime/runtime.test.ts +7 -0
  154. package/gs/runtime/runtime.ts +2 -4
  155. package/gs/runtime/trace/index.test.ts +9 -1
  156. package/gs/runtime/trace/index.ts +5 -1
  157. package/gs/slices/meta.json +3 -0
  158. package/gs/slices/slices.test.ts +59 -21
  159. package/gs/slices/slices.ts +61 -20
  160. package/gs/strconv/complex.test.ts +17 -3
  161. package/gs/sync/atomic/doc_64.test.ts +2 -9
  162. package/gs/sync/sync.test.ts +18 -8
  163. package/gs/syscall/js/index.test.ts +9 -4
  164. package/package.json +13 -5
@@ -6,15 +6,24 @@ function writeString(w: http.ResponseWriter | null, value: string): void {
6
6
  w?.Write($.stringToBytes(value))
7
7
  }
8
8
 
9
- export function Index(w: http.ResponseWriter | null, _r: http.Request | $.VarRef<http.Request> | null): void {
9
+ export function Index(
10
+ w: http.ResponseWriter | null,
11
+ _r: http.Request | $.VarRef<http.Request> | null,
12
+ ): void {
10
13
  const header = w?.Header()
11
14
  if (header != null) {
12
15
  http.Header_Set(header, 'Content-Type', 'text/html; charset=utf-8')
13
16
  }
14
- writeString(w, '<html><body><a href="goroutine?debug=2">full goroutine stack dump</a></body></html>')
17
+ writeString(
18
+ w,
19
+ '<html><body><a href="goroutine?debug=2">full goroutine stack dump</a></body></html>',
20
+ )
15
21
  }
16
22
 
17
- export function Cmdline(w: http.ResponseWriter | null, _r: http.Request | $.VarRef<http.Request> | null): void {
23
+ export function Cmdline(
24
+ w: http.ResponseWriter | null,
25
+ _r: http.Request | $.VarRef<http.Request> | null,
26
+ ): void {
18
27
  const header = w?.Header()
19
28
  if (header != null) {
20
29
  http.Header_Set(header, 'Content-Type', 'text/plain; charset=utf-8')
@@ -22,7 +31,10 @@ export function Cmdline(w: http.ResponseWriter | null, _r: http.Request | $.VarR
22
31
  writeString(w, 'goscript')
23
32
  }
24
33
 
25
- export function Profile(w: http.ResponseWriter | null, _r: http.Request | $.VarRef<http.Request> | null): void {
34
+ export function Profile(
35
+ w: http.ResponseWriter | null,
36
+ _r: http.Request | $.VarRef<http.Request> | null,
37
+ ): void {
26
38
  const header = w?.Header()
27
39
  if (header != null) {
28
40
  http.Header_Set(header, 'Content-Type', 'application/octet-stream')
@@ -30,7 +42,10 @@ export function Profile(w: http.ResponseWriter | null, _r: http.Request | $.VarR
30
42
  writeString(w, 'cpu profile\n')
31
43
  }
32
44
 
33
- export function Symbol(w: http.ResponseWriter | null, _r: http.Request | $.VarRef<http.Request> | null): void {
45
+ export function Symbol(
46
+ w: http.ResponseWriter | null,
47
+ _r: http.Request | $.VarRef<http.Request> | null,
48
+ ): void {
34
49
  const header = w?.Header()
35
50
  if (header != null) {
36
51
  http.Header_Set(header, 'Content-Type', 'text/plain; charset=utf-8')
@@ -38,7 +53,10 @@ export function Symbol(w: http.ResponseWriter | null, _r: http.Request | $.VarRe
38
53
  writeString(w, 'num_symbols: 0\n')
39
54
  }
40
55
 
41
- export function Trace(w: http.ResponseWriter | null, _r: http.Request | $.VarRef<http.Request> | null): void {
56
+ export function Trace(
57
+ w: http.ResponseWriter | null,
58
+ _r: http.Request | $.VarRef<http.Request> | null,
59
+ ): void {
42
60
  const header = w?.Header()
43
61
  if (header != null) {
44
62
  http.Header_Set(header, 'Content-Type', 'application/octet-stream')
@@ -115,6 +115,28 @@ describe('os stdio', () => {
115
115
  expect(writeSync).toHaveBeenCalledTimes(1)
116
116
  })
117
117
 
118
+ it('writes stderr to console.log in browser-like hosts', () => {
119
+ const consoleLog = vi.spyOn(console, 'log').mockImplementation(() => {})
120
+ const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
121
+
122
+ delete (globalThis as any).Deno
123
+ delete (globalThis as any).process
124
+ resetHostRuntimeForTests()
125
+
126
+ try {
127
+ const stderr = NewFile(2, 'stderr')!
128
+ const [writeN, writeErr] = stderr.Write(new TextEncoder().encode('err\n'))
129
+
130
+ expect(writeN).toBe(4)
131
+ expect(writeErr).toBeNull()
132
+ expect(consoleLog).toHaveBeenCalledWith('err')
133
+ expect(consoleError).not.toHaveBeenCalled()
134
+ } finally {
135
+ consoleLog.mockRestore()
136
+ consoleError.mockRestore()
137
+ }
138
+ })
139
+
118
140
  it('falls back to process builtin fs when Deno lacks sync stdio', () => {
119
141
  const readSync = vi.fn(
120
142
  (
@@ -11,7 +11,9 @@ export function rangeNum<T extends number | uintptr, N extends number | number>(
11
11
 
12
12
  // if the iteration value type is define by
13
13
  // type T built-in type.
14
- return async (_yield: ((v: Value) => iter.YieldResult) | null): Promise<void> => {
14
+ return async (
15
+ _yield: ((v: Value) => iter.YieldResult) | null,
16
+ ): Promise<void> => {
15
17
  let convert = t!.PkgPath!() != ''
16
18
  // cannot use range T(v) because no core type.
17
19
 
@@ -24,7 +26,7 @@ export function rangeNum<T extends number | uintptr, N extends number | number>(
24
26
  if (convert) {
25
27
  tmp = tmp.Convert(t).clone()
26
28
  }
27
- if (!await _yield!(tmp)) {
29
+ if (!(await _yield!(tmp))) {
28
30
  return
29
31
  }
30
32
  }
@@ -1,5 +1,13 @@
1
1
  import { describe, it, expect } from 'vitest'
2
- import { AppendSlice, MakeMapWithSize, MapIter, MapOf, TypeOf, ValueOf } from './index.js'
2
+ import {
3
+ AppendSlice,
4
+ MakeMapWithSize,
5
+ MapIter,
6
+ MapOf,
7
+ TypeOf,
8
+ Value,
9
+ ValueOf,
10
+ } from './index.js'
3
11
 
4
12
  describe('MapIter', () => {
5
13
  it('should iterate over map entries with proper typing', () => {
@@ -31,6 +39,53 @@ describe('MapIter', () => {
31
39
  })
32
40
 
33
41
  describe('Value.MapKeys', () => {
42
+ it('reports map length', () => {
43
+ const map = new Map<string, number>()
44
+ map.set('alpha', 1)
45
+ map.set('beta', 2)
46
+
47
+ expect(ValueOf(map).Len()).toBe(2)
48
+ })
49
+
50
+ it('sets and mutates map fields through the same addressable value', () => {
51
+ const typ = MapOf(TypeOf(''), TypeOf(0))
52
+ const holder: { Items: Map<string, number> | null } = { Items: null }
53
+ const field = new Value(holder.Items, typ, undefined, holder, 'Items')
54
+
55
+ field.Set(MakeMapWithSize(typ, 0))
56
+ field.SetMapIndex(ValueOf('alpha'), ValueOf(1))
57
+
58
+ expect(holder.Items?.get('alpha')).toBe(1)
59
+ expect(field.Len()).toBe(1)
60
+ expect(field.MapIndex(ValueOf('alpha')).Interface()).toBe(1)
61
+ })
62
+
63
+ it('deletes map entries when SetMapIndex receives a zero value', () => {
64
+ const typ = MapOf(TypeOf(''), TypeOf(0))
65
+ const mapValue = MakeMapWithSize(typ, 0)
66
+
67
+ mapValue.SetMapIndex(ValueOf('alpha'), ValueOf(1))
68
+ mapValue.SetMapIndex(ValueOf('alpha'), new Value())
69
+
70
+ const raw = mapValue.Interface()
71
+ expect(raw).toBeInstanceOf(Map)
72
+ expect(mapValue.Len()).toBe(0)
73
+ expect(raw.has('alpha')).toBe(false)
74
+ })
75
+
76
+ it('rejects nil map insertion and invalid map backing values', () => {
77
+ const typ = MapOf(TypeOf(''), TypeOf(0))
78
+ const nilMap = new Value(null, typ)
79
+ const badMap = new Value({ bad: true }, typ)
80
+
81
+ expect(() => nilMap.SetMapIndex(ValueOf('alpha'), ValueOf(1))).toThrow(
82
+ 'reflect: assignment to entry in nil map',
83
+ )
84
+ expect(() => badMap.Len()).toThrow(
85
+ 'reflect: call of reflect.Value.Len on map Value',
86
+ )
87
+ })
88
+
34
89
  it('returns map keys as reflect values', () => {
35
90
  const map = new Map<string, number>()
36
91
  map.set('alpha', 1)
@@ -565,6 +565,27 @@ export class Value {
565
565
  return cloned
566
566
  }
567
567
 
568
+ private currentValue(): ReflectValue {
569
+ if (this._parentVarRef) {
570
+ return this._parentVarRef.value
571
+ }
572
+ if (this._parentStruct && this._fieldName !== undefined) {
573
+ const value = this._parentStruct[this._fieldName]
574
+ return value === undefined ? null : (value as ReflectValue)
575
+ }
576
+ return this._value
577
+ }
578
+
579
+ private storeValue(value: ReflectValue): void {
580
+ this._value = value
581
+ if (this._parentVarRef) {
582
+ this._parentVarRef.value = value
583
+ }
584
+ if (this._parentStruct && this._fieldName !== undefined) {
585
+ this._parentStruct[this._fieldName] = value
586
+ }
587
+ }
588
+
568
589
  // Methods required by godoc.txt and used throughout the codebase
569
590
  public Int(): number {
570
591
  const value = this.numericValue()
@@ -645,6 +666,16 @@ export class Value {
645
666
  if (this.Kind() === Slice || this.Kind() === Array) {
646
667
  return $.len(this._value as any)
647
668
  }
669
+ if (this.Kind() === Map) {
670
+ const value = this.currentValue()
671
+ if (value instanceof globalThis.Map) {
672
+ return value.size
673
+ }
674
+ if (value !== null && value !== undefined) {
675
+ throw new ValueError({ Kind: this.Kind(), Method: 'Len' })
676
+ }
677
+ return 0
678
+ }
648
679
 
649
680
  // Check for slice objects created by $.arrayToSlice
650
681
  if (
@@ -705,7 +736,8 @@ export class Value {
705
736
  }
706
737
 
707
738
  public IsNil(): boolean {
708
- return this._value === null || this._value === undefined
739
+ const value = this.currentValue()
740
+ return value === null || value === undefined
709
741
  }
710
742
 
711
743
  public Index(i: number): Value {
@@ -945,15 +977,7 @@ export class Value {
945
977
  if (!xType.AssignableTo(thisType)) {
946
978
  throw new Error('reflect: assign to wrong type')
947
979
  }
948
- this._value = x.value
949
- // Also update the parent VarRef if we were dereferenced from one
950
- if (this._parentVarRef) {
951
- this._parentVarRef.value = x.value
952
- }
953
- // Also update the parent struct field if this is a struct field
954
- if (this._parentStruct && this._fieldName) {
955
- this._parentStruct[this._fieldName] = x.value
956
- }
980
+ this.storeValue(x.value)
957
981
  }
958
982
 
959
983
  // Additional methods from deleted reflect.gs.ts
@@ -1026,28 +1050,30 @@ export class Value {
1026
1050
  if (this.Kind() !== Map) {
1027
1051
  throw new ValueError({ Kind: this.Kind(), Method: 'MapRange' })
1028
1052
  }
1029
- if (this._value === null || this._value === undefined) {
1053
+ const value = this.currentValue()
1054
+ if (value === null || value === undefined) {
1030
1055
  return new MapIter(new globalThis.Map())
1031
1056
  }
1032
- if (!(this._value instanceof globalThis.Map)) {
1057
+ if (!(value instanceof globalThis.Map)) {
1033
1058
  throw new ValueError({ Kind: this.Kind(), Method: 'MapRange' })
1034
1059
  }
1035
- return new MapIter(this._value)
1060
+ return new MapIter(value)
1036
1061
  }
1037
1062
 
1038
1063
  public MapIndex(key: Value): Value {
1039
1064
  if (this.Kind() !== Map) {
1040
1065
  throw new ValueError({ Kind: this.Kind(), Method: 'MapIndex' })
1041
1066
  }
1042
- if (!(this._value instanceof globalThis.Map)) {
1067
+ const value = this.currentValue()
1068
+ if (!(value instanceof globalThis.Map)) {
1043
1069
  return new Value(null, new BasicType(Invalid, 'invalid'))
1044
1070
  }
1045
1071
  const rawKey = key.Interface()
1046
- if (!this._value.has(rawKey)) {
1072
+ if (!value.has(rawKey)) {
1047
1073
  return new Value(null, new BasicType(Invalid, 'invalid'))
1048
1074
  }
1049
1075
  return new Value(
1050
- this._value.get(rawKey) as ReflectValue,
1076
+ value.get(rawKey) as ReflectValue,
1051
1077
  this.Type().Elem(),
1052
1078
  )
1053
1079
  }
@@ -1056,15 +1082,16 @@ export class Value {
1056
1082
  if (this.Kind() !== Map) {
1057
1083
  throw new ValueError({ Kind: this.Kind(), Method: 'MapKeys' })
1058
1084
  }
1059
- if (this._value === null || this._value === undefined) {
1085
+ const value = this.currentValue()
1086
+ if (value === null || value === undefined) {
1060
1087
  return $.makeSlice<Value>(0)
1061
1088
  }
1062
- if (!(this._value instanceof globalThis.Map)) {
1089
+ if (!(value instanceof globalThis.Map)) {
1063
1090
  throw new ValueError({ Kind: this.Kind(), Method: 'MapKeys' })
1064
1091
  }
1065
1092
  const keyType = this.Type().Key()
1066
1093
  const keys: Value[] = []
1067
- for (const key of this._value.keys()) {
1094
+ for (const key of value.keys()) {
1068
1095
  keys.push(new Value(key as ReflectValue, keyType))
1069
1096
  }
1070
1097
  return $.arrayToSlice(keys)
@@ -1278,7 +1305,7 @@ export class Value {
1278
1305
  )
1279
1306
  }
1280
1307
  const zeroVal = Zero(this.Type())
1281
- this._value = (zeroVal as unknown as { value: ReflectValue }).value
1308
+ this.storeValue((zeroVal as unknown as { value: ReflectValue }).value)
1282
1309
  }
1283
1310
 
1284
1311
  // SetLen sets v's length to n
@@ -1312,9 +1339,16 @@ export class Value {
1312
1339
  ' Value',
1313
1340
  )
1314
1341
  }
1315
- const mapObj = this._value as globalThis.Map<unknown, unknown>
1342
+ const mapObj = this.currentValue()
1343
+ if (!(mapObj instanceof globalThis.Map)) {
1344
+ throw new Error('reflect: assignment to entry in nil map')
1345
+ }
1316
1346
  const keyVal = (key as unknown as { value: ReflectValue }).value
1317
1347
  const elemVal = (elem as unknown as { value: ReflectValue }).value
1348
+ if (!elem.IsValid()) {
1349
+ mapObj.delete(keyVal)
1350
+ return
1351
+ }
1318
1352
  mapObj.set(keyVal, elemVal)
1319
1353
  }
1320
1354
 
@@ -2719,15 +2753,14 @@ function typeInfoIdentityKey(
2719
2753
  return `named:${info.name}`
2720
2754
  }
2721
2755
  return `struct:${(info.fields ?? [])
2722
- .map(
2723
- (field) =>
2724
- [
2725
- field.name,
2726
- field.pkgPath ?? '',
2727
- field.tag ?? '',
2728
- field.anonymous === true ? 'anonymous' : 'named',
2729
- typeInfoIdentityKey(field.type, seen),
2730
- ].join('\u0000'),
2756
+ .map((field) =>
2757
+ [
2758
+ field.name,
2759
+ field.pkgPath ?? '',
2760
+ field.tag ?? '',
2761
+ field.anonymous === true ? 'anonymous' : 'named',
2762
+ typeInfoIdentityKey(field.type, seen),
2763
+ ].join('\u0000'),
2731
2764
  )
2732
2765
  .join('\u0001')}`
2733
2766
  case $.TypeKind.Pointer:
@@ -2904,10 +2937,7 @@ function typeMethods(t: Type): $.MethodSignature[] {
2904
2937
  return t.methodSignatures()
2905
2938
  }
2906
2939
  if (!typeInfo && t instanceof PointerType) {
2907
- return mergeMethodSignatureList(
2908
- typeMethods(t.Elem()),
2909
- t.methodSignatures(),
2910
- )
2940
+ return mergeMethodSignatureList(typeMethods(t.Elem()), t.methodSignatures())
2911
2941
  }
2912
2942
  if (!typeInfo && t instanceof BasicType) {
2913
2943
  return t.methodSignatures()
@@ -3331,13 +3361,22 @@ function typeFromGoTypeName(typeName: string): Type | null {
3331
3361
  if (trimmed === '') return null
3332
3362
 
3333
3363
  if (trimmed.startsWith('<-chan ')) {
3334
- return new ChannelType(typeFromGoTypeName(trimmed.slice(7)) ?? anyType(), RecvDir)
3364
+ return new ChannelType(
3365
+ typeFromGoTypeName(trimmed.slice(7)) ?? anyType(),
3366
+ RecvDir,
3367
+ )
3335
3368
  }
3336
3369
  if (trimmed.startsWith('chan<- ')) {
3337
- return new ChannelType(typeFromGoTypeName(trimmed.slice(7)) ?? anyType(), SendDir)
3370
+ return new ChannelType(
3371
+ typeFromGoTypeName(trimmed.slice(7)) ?? anyType(),
3372
+ SendDir,
3373
+ )
3338
3374
  }
3339
3375
  if (trimmed.startsWith('chan ')) {
3340
- return new ChannelType(typeFromGoTypeName(trimmed.slice(5)) ?? anyType(), BothDir)
3376
+ return new ChannelType(
3377
+ typeFromGoTypeName(trimmed.slice(5)) ?? anyType(),
3378
+ BothDir,
3379
+ )
3341
3380
  }
3342
3381
  if (trimmed.startsWith('[]')) {
3343
3382
  return new SliceType(typeFromGoTypeName(trimmed.slice(2)) ?? anyType())
@@ -1,6 +1,15 @@
1
1
  import { describe, expect, it, vi } from 'vitest'
2
2
 
3
- import { BuildInfo, BuildSetting, Module, PrintStack, ReadBuildInfo, Stack } from './index.js'
3
+ import { resetHostRuntimeForTests } from '@goscript/builtin/hostio.js'
4
+
5
+ import {
6
+ BuildInfo,
7
+ BuildSetting,
8
+ Module,
9
+ PrintStack,
10
+ ReadBuildInfo,
11
+ Stack,
12
+ } from './index.js'
4
13
 
5
14
  describe('runtime/debug override', () => {
6
15
  it('returns a stack trace as bytes', () => {
@@ -10,14 +19,33 @@ describe('runtime/debug override', () => {
10
19
  expect(new TextDecoder().decode(stack)).toContain('Error')
11
20
  })
12
21
 
13
- it('prints the current stack trace', () => {
22
+ it('prints the current stack trace through the browser-like stderr console fallback', () => {
23
+ const consoleLog = vi.spyOn(console, 'log').mockImplementation(() => {})
14
24
  const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
25
+ const originalDeno = (globalThis as any).Deno
26
+ const originalProcess = (globalThis as any).process
27
+ delete (globalThis as any).Deno
28
+ delete (globalThis as any).process
29
+ resetHostRuntimeForTests()
15
30
 
16
31
  try {
17
32
  PrintStack()
18
- expect(consoleError).toHaveBeenCalledTimes(1)
19
- expect(consoleError.mock.calls[0][0]).toContain('Error')
33
+ expect(consoleLog).toHaveBeenCalledTimes(1)
34
+ expect(consoleLog.mock.calls[0][0]).toContain('Error')
35
+ expect(consoleError).not.toHaveBeenCalled()
20
36
  } finally {
37
+ if (originalDeno === undefined) {
38
+ delete (globalThis as any).Deno
39
+ } else {
40
+ ;(globalThis as any).Deno = originalDeno
41
+ }
42
+ if (originalProcess === undefined) {
43
+ delete (globalThis as any).process
44
+ } else {
45
+ ;(globalThis as any).process = originalProcess
46
+ }
47
+ resetHostRuntimeForTests()
48
+ consoleLog.mockRestore()
21
49
  consoleError.mockRestore()
22
50
  }
23
51
  })
@@ -1,4 +1,5 @@
1
1
  import * as $ from '@goscript/builtin/index.js'
2
+ import { writeHostStderrText } from '@goscript/builtin/hostio.js'
2
3
 
3
4
  export class BuildSetting {
4
5
  public Key: string
@@ -10,7 +11,9 @@ export class BuildSetting {
10
11
  }
11
12
 
12
13
  public clone(): BuildSetting {
13
- return $.markAsStructValue(new BuildSetting({ Key: this.Key, Value: this.Value }))
14
+ return $.markAsStructValue(
15
+ new BuildSetting({ Key: this.Key, Value: this.Value }),
16
+ )
14
17
  }
15
18
  }
16
19
 
@@ -88,7 +91,7 @@ export function Stack(): Uint8Array {
88
91
  }
89
92
 
90
93
  export function PrintStack(): void {
91
- console.error(new TextDecoder().decode(Stack()))
94
+ writeHostStderrText(new TextDecoder().decode(Stack()))
92
95
  }
93
96
 
94
97
  export function ReadBuildInfo(): [BuildInfo | null, boolean] {
@@ -1,6 +1,12 @@
1
1
  import { describe, expect, it } from 'vitest'
2
2
 
3
- import { Lookup, NewProfile, StartCPUProfile, StopCPUProfile, WriteHeapProfile } from './index.js'
3
+ import {
4
+ Lookup,
5
+ NewProfile,
6
+ StartCPUProfile,
7
+ StopCPUProfile,
8
+ WriteHeapProfile,
9
+ } from './index.js'
4
10
 
5
11
  describe('runtime/pprof override', () => {
6
12
  it('reports CPU profiles as unsupported', () => {
@@ -105,7 +105,11 @@ export function WriteHeapProfile(w: WriterArg): $.GoError {
105
105
 
106
106
  export function SetGoroutineLabels(_ctx: unknown): void {}
107
107
 
108
- export function Do(_ctx: unknown, _labels: unknown, fn: (() => void) | null): void {
108
+ export function Do(
109
+ _ctx: unknown,
110
+ _labels: unknown,
111
+ fn: (() => void) | null,
112
+ ): void {
109
113
  fn?.()
110
114
  }
111
115
 
@@ -4,6 +4,7 @@ import {
4
4
  Compiler,
5
5
  FuncForPC,
6
6
  ReadTrace,
7
+ SetFinalizer,
7
8
  StartTrace,
8
9
  StopTrace,
9
10
  } from './runtime.js'
@@ -18,4 +19,10 @@ describe('runtime override', () => {
18
19
  expect(ReadTrace()).toBeNull()
19
20
  expect(() => StopTrace()).not.toThrow()
20
21
  })
22
+
23
+ it('ignores finalizer registration and clearing', () => {
24
+ const obj = {}
25
+ expect(() => SetFinalizer(obj, () => {})).not.toThrow()
26
+ expect(() => SetFinalizer(obj, null)).not.toThrow()
27
+ })
21
28
  })
@@ -234,14 +234,12 @@ export class PanicError implements Error {
234
234
  }
235
235
 
236
236
  // SetFinalizer sets the finalizer associated with obj to the provided finalizer function.
237
- // In goscript/TypeScript environment, finalizers are not supported, so this throws an error.
238
237
  export function SetFinalizer(
239
238
  _obj: object,
240
239
  _finalizer: ((obj: object) => void) | null,
241
240
  ): void {
242
- throw new Error(
243
- 'runtime.SetFinalizer is not supported in goscript TypeScript environment',
244
- )
241
+ // JavaScript runtimes do not expose Go's finalizer scheduling contract. Treat
242
+ // registration and clearing as no-ops so cleanup backstops don't become fatal.
245
243
  }
246
244
 
247
245
  // Cleanup is a handle to a cleanup call for a specific object.
@@ -2,7 +2,15 @@ import { describe, expect, it } from 'vitest'
2
2
 
3
3
  import * as context from '@goscript/context/index.js'
4
4
 
5
- import { IsEnabled, Log, NewTask, Start, StartRegion, Stop, WithRegion } from './index.js'
5
+ import {
6
+ IsEnabled,
7
+ Log,
8
+ NewTask,
9
+ Start,
10
+ StartRegion,
11
+ Stop,
12
+ WithRegion,
13
+ } from './index.js'
6
14
 
7
15
  describe('runtime/trace override', () => {
8
16
  it('creates no-op tasks from nil context', () => {
@@ -43,7 +43,11 @@ export function NewTask(
43
43
  ]
44
44
  }
45
45
 
46
- export function Log(_ctx: context.Context | null, category: string, message: string): void {
46
+ export function Log(
47
+ _ctx: context.Context | null,
48
+ category: string,
49
+ message: string,
50
+ ): void {
47
51
  void category
48
52
  void message
49
53
  }
@@ -1,4 +1,7 @@
1
1
  {
2
+ "asyncFunctions": {
3
+ "SortFunc": true
4
+ },
2
5
  "dependencies": [
3
6
  "cmp",
4
7
  "iter"