goscript 0.2.1 → 0.2.2

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 (36) hide show
  1. package/compiler/gotest/runner.go +98 -0
  2. package/compiler/gotest/runner_test.go +45 -0
  3. package/compiler/lowering.go +4 -2
  4. package/compiler/protobuf-ts-binding.go +1 -1
  5. package/compiler/protobuf-ts-binding_test.go +109 -0
  6. package/compiler/skeleton_test.go +4 -1
  7. package/dist/gs/builtin/hostio.js +2 -2
  8. package/dist/gs/builtin/hostio.js.map +1 -1
  9. package/dist/gs/crypto/aes/index.d.ts +15 -0
  10. package/dist/gs/crypto/aes/index.js +57 -0
  11. package/dist/gs/crypto/aes/index.js.map +1 -0
  12. package/dist/gs/crypto/cipher/index.d.ts +41 -0
  13. package/dist/gs/crypto/cipher/index.js +255 -0
  14. package/dist/gs/crypto/cipher/index.js.map +1 -0
  15. package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.d.ts +31 -0
  16. package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.js +117 -0
  17. package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.js.map +1 -0
  18. package/dist/gs/io/io.js +18 -2
  19. package/dist/gs/io/io.js.map +1 -1
  20. package/dist/gs/runtime/debug/index.js +2 -1
  21. package/dist/gs/runtime/debug/index.js.map +1 -1
  22. package/go.mod +2 -2
  23. package/go.sum +2 -0
  24. package/gs/builtin/hostio.test.ts +8 -3
  25. package/gs/builtin/hostio.ts +2 -4
  26. package/gs/crypto/aes/index.test.ts +120 -0
  27. package/gs/crypto/aes/index.ts +76 -0
  28. package/gs/crypto/cipher/index.ts +345 -0
  29. package/gs/crypto/cipher/meta.json +6 -0
  30. package/gs/golang.org/x/crypto/chacha20poly1305/index.test.ts +91 -0
  31. package/gs/golang.org/x/crypto/chacha20poly1305/index.ts +245 -0
  32. package/gs/io/io.test.ts +56 -1
  33. package/gs/io/io.ts +19 -2
  34. package/gs/runtime/debug/index.test.ts +32 -4
  35. package/gs/runtime/debug/index.ts +5 -2
  36. package/package.json +10 -3
@@ -0,0 +1,245 @@
1
+ import * as $ from '@goscript/builtin/index.js'
2
+ import * as errors from '@goscript/errors/index.js'
3
+ import {
4
+ chacha20poly1305 as nobleChaCha20Poly1305,
5
+ xchacha20poly1305 as nobleXChaCha20Poly1305,
6
+ } from '@noble/ciphers/chacha.js'
7
+
8
+ export const KeySize = 32
9
+ export const NonceSize = 12
10
+ export const NonceSizeX = 24
11
+ export const Overhead = 16
12
+
13
+ const maxIETFPlaintext = 2 ** 38 - 64
14
+ const maxIETFCiphertext = 2 ** 38 - 48
15
+
16
+ type NobleAEAD = typeof nobleChaCha20Poly1305 | typeof nobleXChaCha20Poly1305
17
+
18
+ export let errOpen: $.GoError = errors.New(
19
+ 'chacha20poly1305: message authentication failed',
20
+ )
21
+
22
+ export function __goscript_set_errOpen(value: $.GoError): void {
23
+ errOpen = value
24
+ }
25
+
26
+ export interface AEAD {
27
+ NonceSize(): number
28
+ Overhead(): number
29
+ Seal(
30
+ dst: $.Slice<number>,
31
+ nonce: $.Slice<number>,
32
+ plaintext: $.Slice<number>,
33
+ additionalData: $.Slice<number>,
34
+ ): $.Slice<number>
35
+ Open(
36
+ dst: $.Slice<number>,
37
+ nonce: $.Slice<number>,
38
+ ciphertext: $.Slice<number>,
39
+ additionalData: $.Slice<number>,
40
+ ): [$.Slice<number>, $.GoError]
41
+ }
42
+
43
+ export class chacha20poly1305 implements AEAD {
44
+ readonly key: Uint8Array
45
+
46
+ constructor(key: Uint8Array) {
47
+ this.key = key.slice()
48
+ }
49
+
50
+ NonceSize(): number {
51
+ return NonceSize
52
+ }
53
+
54
+ Overhead(): number {
55
+ return Overhead
56
+ }
57
+
58
+ Seal(
59
+ dst: $.Slice<number>,
60
+ nonce: $.Slice<number>,
61
+ plaintext: $.Slice<number>,
62
+ additionalData: $.Slice<number>,
63
+ ): $.Slice<number> {
64
+ return seal(
65
+ dst,
66
+ nobleChaCha20Poly1305,
67
+ this.key,
68
+ nonce,
69
+ NonceSize,
70
+ plaintext,
71
+ additionalData,
72
+ )
73
+ }
74
+
75
+ Open(
76
+ dst: $.Slice<number>,
77
+ nonce: $.Slice<number>,
78
+ ciphertext: $.Slice<number>,
79
+ additionalData: $.Slice<number>,
80
+ ): [$.Slice<number>, $.GoError] {
81
+ return open(
82
+ dst,
83
+ nobleChaCha20Poly1305,
84
+ this.key,
85
+ nonce,
86
+ NonceSize,
87
+ ciphertext,
88
+ additionalData,
89
+ )
90
+ }
91
+ }
92
+
93
+ export class xchacha20poly1305 implements AEAD {
94
+ readonly key: Uint8Array
95
+
96
+ constructor(key: Uint8Array) {
97
+ this.key = key.slice()
98
+ }
99
+
100
+ NonceSize(): number {
101
+ return NonceSizeX
102
+ }
103
+
104
+ Overhead(): number {
105
+ return Overhead
106
+ }
107
+
108
+ Seal(
109
+ dst: $.Slice<number>,
110
+ nonce: $.Slice<number>,
111
+ plaintext: $.Slice<number>,
112
+ additionalData: $.Slice<number>,
113
+ ): $.Slice<number> {
114
+ return seal(
115
+ dst,
116
+ nobleXChaCha20Poly1305,
117
+ this.key,
118
+ nonce,
119
+ NonceSizeX,
120
+ plaintext,
121
+ additionalData,
122
+ )
123
+ }
124
+
125
+ Open(
126
+ dst: $.Slice<number>,
127
+ nonce: $.Slice<number>,
128
+ ciphertext: $.Slice<number>,
129
+ additionalData: $.Slice<number>,
130
+ ): [$.Slice<number>, $.GoError] {
131
+ return open(
132
+ dst,
133
+ nobleXChaCha20Poly1305,
134
+ this.key,
135
+ nonce,
136
+ NonceSizeX,
137
+ ciphertext,
138
+ additionalData,
139
+ )
140
+ }
141
+ }
142
+
143
+ export function New(key: $.Slice<number>): [AEAD | null, $.GoError] {
144
+ const keyBytes = bytes(key)
145
+ if (keyBytes.length !== KeySize) {
146
+ return [null, errors.New('chacha20poly1305: bad key length')]
147
+ }
148
+ return [
149
+ $.interfaceValue<AEAD | null>(
150
+ new chacha20poly1305(keyBytes),
151
+ '*chacha20poly1305.chacha20poly1305',
152
+ ),
153
+ null,
154
+ ]
155
+ }
156
+
157
+ export function NewX(key: $.Slice<number>): [AEAD | null, $.GoError] {
158
+ const keyBytes = bytes(key)
159
+ if (keyBytes.length !== KeySize) {
160
+ return [null, errors.New('chacha20poly1305: bad key length')]
161
+ }
162
+ return [
163
+ $.interfaceValue<AEAD | null>(
164
+ new xchacha20poly1305(keyBytes),
165
+ '*chacha20poly1305.xchacha20poly1305',
166
+ ),
167
+ null,
168
+ ]
169
+ }
170
+
171
+ function seal(
172
+ dst: $.Slice<number>,
173
+ cipher: NobleAEAD,
174
+ key: Uint8Array,
175
+ nonce: $.Slice<number>,
176
+ expectedNonceSize: number,
177
+ plaintext: $.Slice<number>,
178
+ additionalData: $.Slice<number>,
179
+ ): $.Slice<number> {
180
+ const nonceBytes = bytes(nonce)
181
+ if (nonceBytes.length !== expectedNonceSize) {
182
+ $.panic('chacha20poly1305: bad nonce length passed to Seal')
183
+ }
184
+ const plaintextBytes = bytes(plaintext)
185
+ if (plaintextBytes.length > maxIETFPlaintext) {
186
+ $.panic('chacha20poly1305: plaintext too large')
187
+ }
188
+
189
+ const sealed = cipher(key, nonceBytes, bytes(additionalData)).encrypt(
190
+ plaintextBytes,
191
+ )
192
+ return appendBytes(dst, sealed)
193
+ }
194
+
195
+ function open(
196
+ dst: $.Slice<number>,
197
+ cipher: NobleAEAD,
198
+ key: Uint8Array,
199
+ nonce: $.Slice<number>,
200
+ expectedNonceSize: number,
201
+ ciphertext: $.Slice<number>,
202
+ additionalData: $.Slice<number>,
203
+ ): [$.Slice<number>, $.GoError] {
204
+ const nonceBytes = bytes(nonce)
205
+ if (nonceBytes.length !== expectedNonceSize) {
206
+ $.panic('chacha20poly1305: bad nonce length passed to Open')
207
+ }
208
+ const ciphertextBytes = bytes(ciphertext)
209
+ if (ciphertextBytes.length < Overhead) {
210
+ return [null, errOpen]
211
+ }
212
+ if (ciphertextBytes.length > maxIETFCiphertext) {
213
+ $.panic('chacha20poly1305: ciphertext too large')
214
+ }
215
+
216
+ try {
217
+ return [
218
+ appendBytes(
219
+ dst,
220
+ cipher(key, nonceBytes, bytes(additionalData)).decrypt(ciphertextBytes),
221
+ ),
222
+ null,
223
+ ]
224
+ } catch {
225
+ return [null, errOpen]
226
+ }
227
+ }
228
+
229
+ function bytes(value: $.Slice<number>): Uint8Array {
230
+ return $.bytesToUint8Array(value).slice()
231
+ }
232
+
233
+ function appendBytes(
234
+ dst: $.Slice<number>,
235
+ suffix: Uint8Array,
236
+ ): $.Slice<number> {
237
+ const prefix = $.bytesToUint8Array(dst)
238
+ if (prefix.length === 0) {
239
+ return suffix.slice()
240
+ }
241
+ const out = new Uint8Array(prefix.length + suffix.length)
242
+ out.set(prefix)
243
+ out.set(suffix, prefix.length)
244
+ return out
245
+ }
package/gs/io/io.test.ts CHANGED
@@ -1,5 +1,12 @@
1
1
  import * as $ from '@goscript/builtin/index.js'
2
- import { LimitedReader, MultiWriter, NopCloser, Pipe, TeeReader } from './index.js'
2
+ import {
3
+ LimitedReader,
4
+ MultiWriter,
5
+ NewSectionReader,
6
+ NopCloser,
7
+ Pipe,
8
+ TeeReader,
9
+ } from './index.js'
3
10
  import { describe, expect, test } from 'vitest'
4
11
 
5
12
  class sliceReader {
@@ -22,6 +29,15 @@ class captureWriter {
22
29
  }
23
30
  }
24
31
 
32
+ class syncReaderAt {
33
+ constructor(private data: Uint8Array) {}
34
+
35
+ ReadAt(p: $.Bytes, off: number): [number, $.GoError] {
36
+ const n = $.copy(p, this.data.subarray(off))
37
+ return [n, n < $.len(p) ? (new Error('EOF') as $.GoError) : null]
38
+ }
39
+ }
40
+
25
41
  describe('io override', () => {
26
42
  test('LimitedReader accepts generated struct-literal construction', async () => {
27
43
  const reader = new LimitedReader({
@@ -118,6 +134,45 @@ describe('io override', () => {
118
134
  expect(Buffer.from(chunks).toString('utf8')).toBe('abc')
119
135
  })
120
136
 
137
+ test('SectionReader preserves sync reads for sync ReaderAt', () => {
138
+ const reader = NewSectionReader(
139
+ new syncReaderAt($.stringToBytes('abcdef')),
140
+ 1,
141
+ 3,
142
+ )
143
+ const buf = new Uint8Array(4)
144
+
145
+ const result = reader.Read(buf)
146
+ expect(result).not.toBeInstanceOf(Promise)
147
+ const [n, err] = result
148
+
149
+ expect(err).toBeNull()
150
+ expect(n).toBe(3)
151
+ expect(Buffer.from(buf.subarray(0, n)).toString('utf8')).toBe('bcd')
152
+ })
153
+
154
+ test('SectionReader awaits async ReaderAt', async () => {
155
+ const reader = NewSectionReader(
156
+ {
157
+ async ReadAt(p: $.Bytes, off: number): Promise<[number, $.GoError]> {
158
+ await Promise.resolve()
159
+ const data = $.stringToBytes('abcdef')
160
+ const n = $.copy(p, data.subarray(off))
161
+ return [n, n < $.len(p) ? (new Error('EOF') as $.GoError) : null]
162
+ },
163
+ } as any,
164
+ 1,
165
+ 3,
166
+ )
167
+ const buf = new Uint8Array(4)
168
+
169
+ const [n, err] = await reader.Read(buf)
170
+
171
+ expect(err).toBeNull()
172
+ expect(n).toBe(3)
173
+ expect(Buffer.from(buf.subarray(0, n)).toString('utf8')).toBe('bcd')
174
+ })
175
+
121
176
  test('PipeReader waits for a later write', async () => {
122
177
  const [reader, writer] = Pipe()
123
178
  const buf = new Uint8Array(5)
package/gs/io/io.ts CHANGED
@@ -363,7 +363,15 @@ export class SectionReader implements Reader, Seeker, ReaderAt {
363
363
  p = $.goSlice(p, 0, max)
364
364
  }
365
365
 
366
- const [n, err] = this.r.ReadAt(p, this.off)
366
+ const res = this.r.ReadAt(p, this.off) as any
367
+ if (res instanceof Promise) {
368
+ return res.then(([n, err]: [number, $.GoError]) => {
369
+ this.off += n
370
+ return [n, err]
371
+ }) as any
372
+ }
373
+
374
+ const [n, err] = res
367
375
  this.off += n
368
376
  return [n, err]
369
377
  }
@@ -400,7 +408,16 @@ export class SectionReader implements Reader, Seeker, ReaderAt {
400
408
  off += this.base
401
409
  if (off + $.len(p) > this.limit) {
402
410
  p = $.goSlice(p, 0, this.limit - off)
403
- const [n, err] = this.r.ReadAt(p, off)
411
+ const res = this.r.ReadAt(p, off) as any
412
+ if (res instanceof Promise) {
413
+ return res.then(([n, err]: [number, $.GoError]) => {
414
+ if (err === null) {
415
+ return [n, EOF]
416
+ }
417
+ return [n, err]
418
+ }) as any
419
+ }
420
+ const [n, err] = res
404
421
  if (err === null) {
405
422
  return [n, EOF]
406
423
  }
@@ -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] {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "goscript",
3
3
  "description": "Go to TypeScript transpiler",
4
- "version": "0.2.1",
4
+ "version": "0.2.2",
5
5
  "author": {
6
6
  "name": "Aperture Robotics LLC.",
7
7
  "email": "support@aperture.us",
@@ -94,7 +94,7 @@
94
94
  "./{src,builtin,example}/**/(*.ts|*.tsx|*.html|*.css|*.scss)": "prettier --config .prettierrc.yaml --write"
95
95
  },
96
96
  "devDependencies": {
97
- "@aptre/protobuf-es-lite": "^1.0.2",
97
+ "@aptre/protobuf-es-lite": "1.1.0",
98
98
  "@eslint/js": "^10.0.0",
99
99
  "@types/node": "^25.5.2",
100
100
  "@typescript-eslint/eslint-plugin": "^8.58.0",
@@ -108,12 +108,19 @@
108
108
  "husky": "^9.1.7",
109
109
  "lint-staged": "^17.0.0",
110
110
  "prettier": "^3.8.1",
111
- "starpc": "0.49.16",
111
+ "starpc": "0.49.17",
112
112
  "typescript": "^6.0.0",
113
113
  "typescript-eslint": "^8.58.0",
114
114
  "vitest": "^4.1.2"
115
115
  },
116
116
  "dependencies": {
117
+ "@noble/ciphers": "2.2.0",
117
118
  "globals": "^17.4.0"
119
+ },
120
+ "resolutions": {
121
+ "@aptre/protobuf-es-lite": "1.1.0"
122
+ },
123
+ "overrides": {
124
+ "@aptre/protobuf-es-lite": "1.1.0"
118
125
  }
119
126
  }