@wasm-fmt/gofmt 0.4.9 → 0.5.0

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 (4) hide show
  1. package/README.md +13 -8
  2. package/gofmt.js +179 -99
  3. package/gofmt.wasm +0 -0
  4. package/package.json +5 -2
package/README.md CHANGED
@@ -2,13 +2,13 @@
2
2
 
3
3
  # Install
4
4
 
5
- [![npm](https://img.shields.io/npm/v/@wasm-fmt/gofmt)](https://www.npmjs.com/package/@wasm-fmt/gofmt)
5
+ [![npm](https://img.shields.io/npm/v/@wasm-fmt/gofmt?color=00ADD8)](https://www.npmjs.com/package/@wasm-fmt/gofmt)
6
6
 
7
7
  ```bash
8
8
  npm install @wasm-fmt/gofmt
9
9
  ```
10
10
 
11
- [![jsr.io](https://jsr.io/badges/@fmt/gofmt)](https://jsr.io/@fmt/gofmt)
11
+ [![jsr.io](https://jsr.io/badges/@fmt/gofmt?color=00ADD8)](https://jsr.io/@fmt/gofmt)
12
12
 
13
13
  ```bash
14
14
  npx jsr add @fmt/gofmt
@@ -41,14 +41,19 @@ import init, { format } from "@wasm-fmt/gofmt/vite";
41
41
  # Build from source
42
42
 
43
43
  ```bash
44
- # 1. clone this repo
45
- git clone https://github.com/wasm-fmt/gofmt.git
44
+ # 1. install Go https://go.dev/doc/install
46
45
 
47
46
  # 2. install TinyGo https://tinygo.org/getting-started/install/
48
47
 
49
- # 3. build
50
- pnpm build
48
+ # 3. clone this repo
49
+ git clone https://github.com/wasm-fmt/gofmt.git
50
+
51
+ # 4. install dependencies inside the repo
52
+ npm install
53
+
54
+ # 5. build
55
+ npm run build
51
56
 
52
- # 4. test
53
- pnpm run /^test:/
57
+ # 6. test
58
+ npm run /^test:/
54
59
  ```
package/gofmt.js CHANGED
@@ -1,13 +1,17 @@
1
+ /* @ts-self-types="./gofmt.d.ts" */
1
2
  // Copyright 2018 The Go Authors. All rights reserved.
2
3
  // Use of this source code is governed by a BSD-style
3
4
  // license that can be found in the LICENSE file.
4
5
  //
5
6
  // This file has been modified for use by the TinyGo compiler.
6
7
 
8
+ // End of polyfills for common API.
9
+
7
10
  const encoder = new TextEncoder("utf-8");
8
11
  const decoder = new TextDecoder("utf-8");
9
12
  let reinterpretBuf = new DataView(new ArrayBuffer(8));
10
13
  var logLine = [];
14
+ const wasmExit = {}; // thrown to exit via proc_exit (not an error)
11
15
 
12
16
  class Go {
13
17
  constructor() {
@@ -115,33 +119,78 @@
115
119
  this.importObject = {
116
120
  wasi_snapshot_preview1: {
117
121
  // https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#fd_write
118
- fd_write: () => 0, // dummy
122
+ fd_write: function(fd, iovs_ptr, iovs_len, nwritten_ptr) {
123
+ let nwritten = 0;
124
+ if (fd == 1) {
125
+ for (let iovs_i=0; iovs_i<iovs_len;iovs_i++) {
126
+ let iov_ptr = iovs_ptr+iovs_i*8; // assuming wasm32
127
+ let ptr = mem().getUint32(iov_ptr + 0, true);
128
+ let len = mem().getUint32(iov_ptr + 4, true);
129
+ nwritten += len;
130
+ for (let i=0; i<len; i++) {
131
+ let c = mem().getUint8(ptr+i);
132
+ if (c == 13) { // CR
133
+ // ignore
134
+ } else if (c == 10) { // LF
135
+ // write line
136
+ let line = decoder.decode(new Uint8Array(logLine));
137
+ logLine = [];
138
+ console.log(line);
139
+ } else {
140
+ logLine.push(c);
141
+ }
142
+ }
143
+ }
144
+ } else {
145
+ console.error('invalid file descriptor:', fd);
146
+ }
147
+ mem().setUint32(nwritten_ptr, nwritten, true);
148
+ return 0;
149
+ },
150
+ /* removed fd_close */ // dummy
151
+ /* removed fd_fdstat_get */ // dummy
152
+ /* removed fd_seek */ // dummy
153
+ proc_exit: (code) => {
154
+ this.exited = true;
155
+ this.exitCode = code;
156
+ this._resolveExitPromise();
157
+ throw wasmExit;
158
+ },
159
+ random_get: (bufPtr, bufLen) => {
160
+ crypto.getRandomValues(loadSlice(bufPtr, bufLen));
161
+ return 0;
162
+ },
119
163
  },
120
164
  gojs: {
121
- // func ticks() float64
165
+ // func ticks() int64
122
166
  "runtime.ticks": () => {
123
- return timeOrigin + performance.now();
167
+ return BigInt((timeOrigin + performance.now()) * 1e6);
124
168
  },
125
169
 
170
+ // func sleepTicks(timeout int64)
171
+ /* removed runtime.sleepTicks */
172
+
126
173
  // func finalizeRef(v ref)
127
174
  "syscall/js.finalizeRef": (v_ref) => {
128
- reinterpretBuf.setBigInt64(0, v_ref, true);
129
- const f = reinterpretBuf.getFloat64(0, true);
130
- if (f === 0 || !isNaN(f)) {
131
- return;
132
- }
175
+ // Note: TinyGo does not support finalizers so this is only called
176
+ // for one specific case, by js.go:jsString. and can/might leak memory.
133
177
  const id = v_ref & 0xffffffffn;
134
- this._goRefCounts[id]--;
135
- if (this._goRefCounts[id] === 0) {
136
- const v = this._values[id];
137
- this._values[id] = null;
138
- this._ids.delete(v);
139
- this._idPool.push(id);
178
+ if (this._goRefCounts?.[id] !== undefined) {
179
+ this._goRefCounts[id]--;
180
+ if (this._goRefCounts[id] === 0) {
181
+ const v = this._values[id];
182
+ this._values[id] = null;
183
+ this._ids.delete(v);
184
+ this._idPool.push(id);
185
+ }
186
+ } else {
187
+ console.error("syscall/js.finalizeRef: unknown id", id);
140
188
  }
141
189
  },
142
190
 
143
191
  // func stringVal(value string) ref
144
192
  "syscall/js.stringVal": (value_ptr, value_len) => {
193
+ value_ptr >>>= 0;
145
194
  const s = loadString(value_ptr, value_len);
146
195
  return boxValue(s);
147
196
  },
@@ -162,6 +211,9 @@
162
211
  Reflect.set(v, p, x);
163
212
  },
164
213
 
214
+ // func valueDelete(v ref, p string)
215
+ /* removed syscall/js.valueDelete */
216
+
165
217
  // func valueIndex(v ref, i int) ref
166
218
  "syscall/js.valueIndex": (v_ref, i) => {
167
219
  return boxValue(Reflect.get(unboxValue(v_ref), i));
@@ -187,6 +239,9 @@
187
239
  }
188
240
  },
189
241
 
242
+ // func valueInvoke(v ref, args []ref) (ref, bool)
243
+ /* removed syscall/js.valueInvoke */
244
+
190
245
  // func valueNew(v ref, args []ref) (ref, bool)
191
246
  "syscall/js.valueNew": (ret_addr, v_ref, args_ptr, args_len, args_cap) => {
192
247
  const v = unboxValue(v_ref);
@@ -218,6 +273,17 @@
218
273
  const str = unboxValue(v_ref);
219
274
  loadSlice(slice_ptr, slice_len, slice_cap).set(str);
220
275
  },
276
+
277
+ // func valueInstanceOf(v ref, t ref) bool
278
+ /* removed syscall/js.valueInstanceOf */
279
+
280
+ // func copyBytesToGo(dst []byte, src ref) (int, bool)
281
+ /* removed syscall/js.copyBytesToGo */
282
+
283
+ // copyBytesToJS(dst ref, src []byte) (int, bool)
284
+ // Originally copied from upstream Go project, then modified:
285
+ // https://github.com/golang/go/blob/3f995c3f3b43033013013e6c7ccc93a9b1411ca9/misc/wasm/wasm_exec.js#L404-L416
286
+ /* removed syscall/js.copyBytesToJS */
221
287
  }
222
288
  };
223
289
 
@@ -234,33 +300,32 @@
234
300
  null,
235
301
  true,
236
302
  false,
237
- // fake global
238
- {
239
- set format(fn){ instance.format = fn; },
240
- Array,
241
- Object,
242
- },
303
+ /* fake global */ { set format(fn) { instance.format = fn }, Array, Object},
243
304
  this,
244
305
  ];
245
306
  this._goRefCounts = []; // number of references that Go has to a JS value, indexed by reference id
246
307
  this._ids = new Map(); // mapping from JS values to reference ids
247
308
  this._idPool = []; // unused ids that have been garbage collected
248
309
  this.exited = false; // whether the Go program has exited
310
+ this.exitCode = 0;
249
311
 
250
- while (true) {
251
- const callbackPromise = new Promise((resolve) => {
252
- this._resolveCallbackPromise = () => {
253
- if (this.exited) {
254
- throw new Error("bad callback: Go program has already exited");
255
- }
256
- setTimeout(resolve, 0); // make sure it is asynchronous
257
- };
312
+ if (this._inst.exports._start) {
313
+ let exitPromise = new Promise((resolve, reject) => {
314
+ this._resolveExitPromise = resolve;
258
315
  });
259
- this._inst.exports._start();
260
- if (this.exited) {
261
- break;
316
+
317
+ // Run program, but catch the wasmExit exception that's thrown
318
+ // to return back here.
319
+ try {
320
+ this._inst.exports._start();
321
+ } catch (e) {
322
+ if (e !== wasmExit) throw e;
262
323
  }
263
- await callbackPromise;
324
+
325
+ await exitPromise;
326
+ return this.exitCode;
327
+ } else {
328
+ this._inst.exports._initialize();
264
329
  }
265
330
  }
266
331
 
@@ -268,7 +333,11 @@
268
333
  if (this.exited) {
269
334
  throw new Error("Go program has already exited");
270
335
  }
271
- this._inst.exports.resume();
336
+ try {
337
+ this._inst.exports.resume();
338
+ } catch (e) {
339
+ if (e !== wasmExit) throw e;
340
+ }
272
341
  if (this.exited) {
273
342
  this._resolveExitPromise();
274
343
  }
@@ -284,72 +353,83 @@
284
353
  };
285
354
  }
286
355
  }
287
-
288
356
  /**
289
357
  * ================== End of wasm_exec.js ==================
290
358
  */
291
- /**/let wasm;
292
- /**/async function __load(module, imports) {
293
- /**/ if (typeof Response === 'function' && module instanceof Response) {
294
- /**/ if (typeof WebAssembly.instantiateStreaming === 'function') {
295
- /**/ try { return await WebAssembly.instantiateStreaming(module, imports); }
296
- /**/ catch (e) {
297
- /**/ if (module.headers.get('Content-Type') != 'application/wasm') {
298
- /**/ console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
299
- /**/ } else { throw e; }
300
- /**/ }
301
- /**/ }
302
- /**/ const bytes = await module.arrayBuffer();
303
- /**/ return await WebAssembly.instantiate(bytes, imports);
304
- /**/ } else {
305
- /**/ const instance = await WebAssembly.instantiate(module, imports);
306
- /**/ if (instance instanceof WebAssembly.Instance) return { instance, module };
307
- /**/ else return instance;
308
- /**/ }
309
- /**/}
310
- /**/function __finalize_init(instance) {
311
- /**/ return wasm = instance;
312
- /**/}
313
- /**/function __init_memory(imports, maybe_memory) { }
314
- /**/export function initSync(module) {
315
- /**/ if (wasm !== undefined) return wasm;
316
- /**/
317
- /**/ const go = new Go;
318
- /**/ const imports = go.importObject;
319
- /**/
320
- /**/ __init_memory(imports);
321
- /**/
322
- /**/ if (!(module instanceof WebAssembly.Module)) module = new WebAssembly.Module(module);
323
- /**/
324
- /**/ const instance = new WebAssembly.Instance(module, imports);
325
- /**/
326
- /**/ go.run(instance);
327
- /**/ return __finalize_init(instance, module);
328
- /**/}
329
- /**/export default async function initAsync(input) {
330
- /**/ if (wasm !== undefined) return wasm;
331
- /**/
332
- /**/ if (typeof input === 'undefined') input = new URL('gofmt.wasm', import.meta.url);
333
- /**/
334
- /**/ const go = new Go;
335
- /**/ const imports = go.importObject;
336
- /**/
337
- /**/ if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
338
- /**/ input = fetch(input);
339
- /**/ }
340
- /**/
341
- /**/ __init_memory(imports);
342
- /**/
343
- /**/ const { instance, module } = await __load(await input, imports);
344
- /**/
345
- /**/ go.run(instance);
346
- /**/ return __finalize_init(instance, module);
347
- /**/}
348
- /**/export function format(input) {
349
- /**/ const [err, result] = wasm.format(input);
350
- /**/ if (err) {
351
- /**/ throw new Error(result);
352
- /**/ }
353
- /**/ return result;
354
- /**/}
355
- /**/
359
+ let wasm;
360
+ async function __load(module, imports) {
361
+ if (typeof Response === "function" && module instanceof Response) {
362
+ if (typeof WebAssembly.instantiateStreaming === "function") {
363
+ try {
364
+ return await WebAssembly.instantiateStreaming(module, imports);
365
+ } catch (e) {
366
+ if (module.headers.get("Content-Type") != "application/wasm") {
367
+ console.warn(
368
+ "`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n",
369
+ e,
370
+ );
371
+ } else {
372
+ throw e;
373
+ }
374
+ }
375
+ }
376
+ const bytes = await module.arrayBuffer();
377
+ return await WebAssembly.instantiate(bytes, imports);
378
+ } else {
379
+ const instance = await WebAssembly.instantiate(module, imports);
380
+ if (instance instanceof WebAssembly.Instance)
381
+ return { instance, module };
382
+ else return instance;
383
+ }
384
+ }
385
+ function __finalize_init(instance) {
386
+ return (wasm = instance);
387
+ }
388
+ function __init_memory(imports, maybe_memory) {}
389
+ export function initSync(module) {
390
+ if (wasm !== undefined) return wasm;
391
+
392
+ const go = new Go();
393
+ const imports = go.importObject;
394
+
395
+ __init_memory(imports);
396
+
397
+ if (!(module instanceof WebAssembly.Module))
398
+ module = new WebAssembly.Module(module);
399
+
400
+ const instance = new WebAssembly.Instance(module, imports);
401
+
402
+ go.run(instance);
403
+ return __finalize_init(instance, module);
404
+ }
405
+ export default async function initAsync(input) {
406
+ if (wasm !== undefined) return wasm;
407
+
408
+ if (typeof input === "undefined")
409
+ input = new URL("gofmt.wasm", import.meta.url);
410
+
411
+ const go = new Go();
412
+ const imports = go.importObject;
413
+
414
+ if (
415
+ typeof input === "string" ||
416
+ (typeof Request === "function" && input instanceof Request) ||
417
+ (typeof URL === "function" && input instanceof URL)
418
+ ) {
419
+ input = fetch(input);
420
+ }
421
+
422
+ __init_memory(imports);
423
+
424
+ const { instance, module } = await __load(await input, imports);
425
+
426
+ go.run(instance);
427
+ return __finalize_init(instance, module);
428
+ }
429
+ export function format(input) {
430
+ const [err, result] = wasm.format(input);
431
+ if (err) {
432
+ throw new Error(result);
433
+ }
434
+ return result;
435
+ }
package/gofmt.wasm CHANGED
Binary file
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@wasm-fmt/gofmt",
3
3
  "description": "A wasm based golang formatter",
4
4
  "author": "magic-akari <akari.ccino@gamil.com>",
5
- "version": "0.4.9",
5
+ "version": "0.5.0",
6
6
  "license": "MIT",
7
7
  "keywords": [
8
8
  "wasm",
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "scripts": {
38
38
  "build": "./scripts/build.sh",
39
- "test:node": "node --test test_node",
39
+ "test:node": "node --test test_node/node.test.js",
40
40
  "test:deno": "deno test test_deno --allow-read",
41
41
  "test:bun": "bun test test_bun"
42
42
  },
@@ -45,5 +45,8 @@
45
45
  },
46
46
  "publishConfig": {
47
47
  "access": "public"
48
+ },
49
+ "devDependencies": {
50
+ "@ast-grep/napi": "0.40.0"
48
51
  }
49
52
  }