@wasm-fmt/gofmt 0.0.1
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.
- package/.node-version +1 -0
- package/LICENSE +21 -0
- package/README.md +16 -0
- package/go.mod +3 -0
- package/go_wasm.js +410 -0
- package/lib.d.ts +1 -0
- package/lib.js +33 -0
- package/lib.wasm +0 -0
- package/package.json +23 -0
- package/src/lib.go +31 -0
- package/test.js +31 -0
package/.node-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
v18.17.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 wasm-fmt
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Build from source
|
|
2
|
+
|
|
3
|
+
```bash
|
|
4
|
+
# 1. clone this repo
|
|
5
|
+
git clone https://github.com/wasm-fmt/gofmt.git
|
|
6
|
+
|
|
7
|
+
# 2. install TinyGo https://tinygo.org/getting-started/install/
|
|
8
|
+
|
|
9
|
+
# 3. build
|
|
10
|
+
npm run go_wasm # copy `wasm_exec.js`
|
|
11
|
+
npm run patch
|
|
12
|
+
npm run build
|
|
13
|
+
|
|
14
|
+
# 4. test
|
|
15
|
+
npm run test
|
|
16
|
+
```
|
package/go.mod
ADDED
package/go_wasm.js
ADDED
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
// Copyright 2018 The Go Authors. All rights reserved.
|
|
2
|
+
// Use of this source code is governed by a BSD-style
|
|
3
|
+
// license that can be found in the LICENSE file.
|
|
4
|
+
//
|
|
5
|
+
// This file has been modified for use by the TinyGo compiler.
|
|
6
|
+
|
|
7
|
+
const encoder = new TextEncoder("utf-8");
|
|
8
|
+
const decoder = new TextDecoder("utf-8");
|
|
9
|
+
var logLine = [];
|
|
10
|
+
|
|
11
|
+
export class Go {
|
|
12
|
+
constructor() {
|
|
13
|
+
this._callbackTimeouts = new Map();
|
|
14
|
+
this._nextCallbackTimeoutID = 1;
|
|
15
|
+
|
|
16
|
+
const mem = () => {
|
|
17
|
+
// The buffer may change when requesting more memory.
|
|
18
|
+
return new DataView(this._inst.exports.memory.buffer);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const setInt64 = (addr, v) => {
|
|
22
|
+
mem().setUint32(addr + 0, v, true);
|
|
23
|
+
mem().setUint32(addr + 4, Math.floor(v / 4294967296), true);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const getInt64 = (addr) => {
|
|
27
|
+
const low = mem().getUint32(addr + 0, true);
|
|
28
|
+
const high = mem().getInt32(addr + 4, true);
|
|
29
|
+
return low + high * 4294967296;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const loadValue = (addr) => {
|
|
33
|
+
const f = mem().getFloat64(addr, true);
|
|
34
|
+
if (f === 0) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
if (!isNaN(f)) {
|
|
38
|
+
return f;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const id = mem().getUint32(addr, true);
|
|
42
|
+
return this._values[id];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const storeValue = (addr, v) => {
|
|
46
|
+
const nanHead = 0x7FF80000;
|
|
47
|
+
|
|
48
|
+
if (typeof v === "number") {
|
|
49
|
+
if (isNaN(v)) {
|
|
50
|
+
mem().setUint32(addr + 4, nanHead, true);
|
|
51
|
+
mem().setUint32(addr, 0, true);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (v === 0) {
|
|
55
|
+
mem().setUint32(addr + 4, nanHead, true);
|
|
56
|
+
mem().setUint32(addr, 1, true);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
mem().setFloat64(addr, v, true);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
switch (v) {
|
|
64
|
+
case undefined:
|
|
65
|
+
mem().setFloat64(addr, 0, true);
|
|
66
|
+
return;
|
|
67
|
+
case null:
|
|
68
|
+
mem().setUint32(addr + 4, nanHead, true);
|
|
69
|
+
mem().setUint32(addr, 2, true);
|
|
70
|
+
return;
|
|
71
|
+
case true:
|
|
72
|
+
mem().setUint32(addr + 4, nanHead, true);
|
|
73
|
+
mem().setUint32(addr, 3, true);
|
|
74
|
+
return;
|
|
75
|
+
case false:
|
|
76
|
+
mem().setUint32(addr + 4, nanHead, true);
|
|
77
|
+
mem().setUint32(addr, 4, true);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
let id = this._ids.get(v);
|
|
82
|
+
if (id === undefined) {
|
|
83
|
+
id = this._idPool.pop();
|
|
84
|
+
if (id === undefined) {
|
|
85
|
+
id = this._values.length;
|
|
86
|
+
}
|
|
87
|
+
this._values[id] = v;
|
|
88
|
+
this._goRefCounts[id] = 0;
|
|
89
|
+
this._ids.set(v, id);
|
|
90
|
+
}
|
|
91
|
+
this._goRefCounts[id]++;
|
|
92
|
+
let typeFlag = 1;
|
|
93
|
+
switch (typeof v) {
|
|
94
|
+
case "string":
|
|
95
|
+
typeFlag = 2;
|
|
96
|
+
break;
|
|
97
|
+
case "symbol":
|
|
98
|
+
typeFlag = 3;
|
|
99
|
+
break;
|
|
100
|
+
case "function":
|
|
101
|
+
typeFlag = 4;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
mem().setUint32(addr + 4, nanHead | typeFlag, true);
|
|
105
|
+
mem().setUint32(addr, id, true);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const loadSlice = (array, len, cap) => {
|
|
109
|
+
return new Uint8Array(this._inst.exports.memory.buffer, array, len);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const loadSliceOfValues = (array, len, cap) => {
|
|
113
|
+
const a = new Array(len);
|
|
114
|
+
for (let i = 0; i < len; i++) {
|
|
115
|
+
a[i] = loadValue(array + i * 8);
|
|
116
|
+
}
|
|
117
|
+
return a;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const loadString = (ptr, len) => {
|
|
121
|
+
return decoder.decode(new DataView(this._inst.exports.memory.buffer, ptr, len));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const timeOrigin = Date.now() - performance.now();
|
|
125
|
+
this.importObject = {
|
|
126
|
+
wasi_snapshot_preview1: {
|
|
127
|
+
// https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#fd_write
|
|
128
|
+
fd_write: function(fd, iovs_ptr, iovs_len, nwritten_ptr) {
|
|
129
|
+
let nwritten = 0;
|
|
130
|
+
if (fd == 1) {
|
|
131
|
+
for (let iovs_i=0; iovs_i<iovs_len;iovs_i++) {
|
|
132
|
+
let iov_ptr = iovs_ptr+iovs_i*8; // assuming wasm32
|
|
133
|
+
let ptr = mem().getUint32(iov_ptr + 0, true);
|
|
134
|
+
let len = mem().getUint32(iov_ptr + 4, true);
|
|
135
|
+
nwritten += len;
|
|
136
|
+
for (let i=0; i<len; i++) {
|
|
137
|
+
let c = mem().getUint8(ptr+i);
|
|
138
|
+
if (c == 13) { // CR
|
|
139
|
+
// ignore
|
|
140
|
+
} else if (c == 10) { // LF
|
|
141
|
+
// write line
|
|
142
|
+
let line = decoder.decode(new Uint8Array(logLine));
|
|
143
|
+
logLine = [];
|
|
144
|
+
console.log(line);
|
|
145
|
+
} else {
|
|
146
|
+
logLine.push(c);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
console.error('invalid file descriptor:', fd);
|
|
152
|
+
}
|
|
153
|
+
mem().setUint32(nwritten_ptr, nwritten, true);
|
|
154
|
+
return 0;
|
|
155
|
+
},
|
|
156
|
+
fd_close: () => 0, // dummy
|
|
157
|
+
fd_fdstat_get: () => 0, // dummy
|
|
158
|
+
fd_seek: () => 0, // dummy
|
|
159
|
+
"proc_exit": (code) => {
|
|
160
|
+
if (global.process) {
|
|
161
|
+
// Node.js
|
|
162
|
+
process.exit(code);
|
|
163
|
+
} else {
|
|
164
|
+
// Can't exit in a browser.
|
|
165
|
+
throw 'trying to exit with code ' + code;
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
random_get: (bufPtr, bufLen) => {
|
|
169
|
+
crypto.getRandomValues(loadSlice(bufPtr, bufLen));
|
|
170
|
+
return 0;
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
env: {
|
|
174
|
+
// func ticks() float64
|
|
175
|
+
"runtime.ticks": () => {
|
|
176
|
+
return timeOrigin + performance.now();
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
// func sleepTicks(timeout float64)
|
|
180
|
+
"runtime.sleepTicks": (timeout) => {
|
|
181
|
+
// Do not sleep, only reactivate scheduler after the given timeout.
|
|
182
|
+
setTimeout(this._inst.exports.go_scheduler, timeout);
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
// func finalizeRef(v ref)
|
|
186
|
+
"syscall/js.finalizeRef": (v_addr) => {
|
|
187
|
+
const id = mem().getUint32(v_addr, true);
|
|
188
|
+
this._goRefCounts[id]--;
|
|
189
|
+
if (this._goRefCounts[id] === 0) {
|
|
190
|
+
const v = this._values[id];
|
|
191
|
+
this._values[id] = null;
|
|
192
|
+
this._ids.delete(v);
|
|
193
|
+
this._idPool.push(id);
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
// func stringVal(value string) ref
|
|
198
|
+
"syscall/js.stringVal": (ret_ptr, value_ptr, value_len) => {
|
|
199
|
+
const s = loadString(value_ptr, value_len);
|
|
200
|
+
storeValue(ret_ptr, s);
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
// func valueGet(v ref, p string) ref
|
|
204
|
+
"syscall/js.valueGet": (retval, v_addr, p_ptr, p_len) => {
|
|
205
|
+
let prop = loadString(p_ptr, p_len);
|
|
206
|
+
let value = loadValue(v_addr);
|
|
207
|
+
let result = Reflect.get(value, prop);
|
|
208
|
+
storeValue(retval, result);
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
// func valueSet(v ref, p string, x ref)
|
|
212
|
+
"syscall/js.valueSet": (v_addr, p_ptr, p_len, x_addr) => {
|
|
213
|
+
const v = loadValue(v_addr);
|
|
214
|
+
const p = loadString(p_ptr, p_len);
|
|
215
|
+
const x = loadValue(x_addr);
|
|
216
|
+
Reflect.set(v, p, x);
|
|
217
|
+
},
|
|
218
|
+
|
|
219
|
+
// func valueDelete(v ref, p string)
|
|
220
|
+
"syscall/js.valueDelete": (v_addr, p_ptr, p_len) => {
|
|
221
|
+
const v = loadValue(v_addr);
|
|
222
|
+
const p = loadString(p_ptr, p_len);
|
|
223
|
+
Reflect.deleteProperty(v, p);
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
// func valueIndex(v ref, i int) ref
|
|
227
|
+
"syscall/js.valueIndex": (ret_addr, v_addr, i) => {
|
|
228
|
+
storeValue(ret_addr, Reflect.get(loadValue(v_addr), i));
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
// valueSetIndex(v ref, i int, x ref)
|
|
232
|
+
"syscall/js.valueSetIndex": (v_addr, i, x_addr) => {
|
|
233
|
+
Reflect.set(loadValue(v_addr), i, loadValue(x_addr));
|
|
234
|
+
},
|
|
235
|
+
|
|
236
|
+
// func valueCall(v ref, m string, args []ref) (ref, bool)
|
|
237
|
+
"syscall/js.valueCall": (ret_addr, v_addr, m_ptr, m_len, args_ptr, args_len, args_cap) => {
|
|
238
|
+
const v = loadValue(v_addr);
|
|
239
|
+
const name = loadString(m_ptr, m_len);
|
|
240
|
+
const args = loadSliceOfValues(args_ptr, args_len, args_cap);
|
|
241
|
+
try {
|
|
242
|
+
const m = Reflect.get(v, name);
|
|
243
|
+
storeValue(ret_addr, Reflect.apply(m, v, args));
|
|
244
|
+
mem().setUint8(ret_addr + 8, 1);
|
|
245
|
+
} catch (err) {
|
|
246
|
+
storeValue(ret_addr, err);
|
|
247
|
+
mem().setUint8(ret_addr + 8, 0);
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
|
|
251
|
+
// func valueInvoke(v ref, args []ref) (ref, bool)
|
|
252
|
+
"syscall/js.valueInvoke": (ret_addr, v_addr, args_ptr, args_len, args_cap) => {
|
|
253
|
+
try {
|
|
254
|
+
const v = loadValue(v_addr);
|
|
255
|
+
const args = loadSliceOfValues(args_ptr, args_len, args_cap);
|
|
256
|
+
storeValue(ret_addr, Reflect.apply(v, undefined, args));
|
|
257
|
+
mem().setUint8(ret_addr + 8, 1);
|
|
258
|
+
} catch (err) {
|
|
259
|
+
storeValue(ret_addr, err);
|
|
260
|
+
mem().setUint8(ret_addr + 8, 0);
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
|
|
264
|
+
// func valueNew(v ref, args []ref) (ref, bool)
|
|
265
|
+
"syscall/js.valueNew": (ret_addr, v_addr, args_ptr, args_len, args_cap) => {
|
|
266
|
+
const v = loadValue(v_addr);
|
|
267
|
+
const args = loadSliceOfValues(args_ptr, args_len, args_cap);
|
|
268
|
+
try {
|
|
269
|
+
storeValue(ret_addr, Reflect.construct(v, args));
|
|
270
|
+
mem().setUint8(ret_addr + 8, 1);
|
|
271
|
+
} catch (err) {
|
|
272
|
+
storeValue(ret_addr, err);
|
|
273
|
+
mem().setUint8(ret_addr+ 8, 0);
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
|
|
277
|
+
// func valueLength(v ref) int
|
|
278
|
+
"syscall/js.valueLength": (v_addr) => {
|
|
279
|
+
return loadValue(v_addr).length;
|
|
280
|
+
},
|
|
281
|
+
|
|
282
|
+
// valuePrepareString(v ref) (ref, int)
|
|
283
|
+
"syscall/js.valuePrepareString": (ret_addr, v_addr) => {
|
|
284
|
+
const s = String(loadValue(v_addr));
|
|
285
|
+
const str = encoder.encode(s);
|
|
286
|
+
storeValue(ret_addr, str);
|
|
287
|
+
setInt64(ret_addr + 8, str.length);
|
|
288
|
+
},
|
|
289
|
+
|
|
290
|
+
// valueLoadString(v ref, b []byte)
|
|
291
|
+
"syscall/js.valueLoadString": (v_addr, slice_ptr, slice_len, slice_cap) => {
|
|
292
|
+
const str = loadValue(v_addr);
|
|
293
|
+
loadSlice(slice_ptr, slice_len, slice_cap).set(str);
|
|
294
|
+
},
|
|
295
|
+
|
|
296
|
+
// func valueInstanceOf(v ref, t ref) bool
|
|
297
|
+
"syscall/js.valueInstanceOf": (v_addr, t_addr) => {
|
|
298
|
+
return loadValue(v_addr) instanceof loadValue(t_addr);
|
|
299
|
+
},
|
|
300
|
+
|
|
301
|
+
// func copyBytesToGo(dst []byte, src ref) (int, bool)
|
|
302
|
+
"syscall/js.copyBytesToGo": (ret_addr, dest_addr, dest_len, dest_cap, source_addr) => {
|
|
303
|
+
let num_bytes_copied_addr = ret_addr;
|
|
304
|
+
let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable
|
|
305
|
+
|
|
306
|
+
const dst = loadSlice(dest_addr, dest_len);
|
|
307
|
+
const src = loadValue(source_addr);
|
|
308
|
+
if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
|
|
309
|
+
mem().setUint8(returned_status_addr, 0); // Return "not ok" status
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
const toCopy = src.subarray(0, dst.length);
|
|
313
|
+
dst.set(toCopy);
|
|
314
|
+
setInt64(num_bytes_copied_addr, toCopy.length);
|
|
315
|
+
mem().setUint8(returned_status_addr, 1); // Return "ok" status
|
|
316
|
+
},
|
|
317
|
+
|
|
318
|
+
// copyBytesToJS(dst ref, src []byte) (int, bool)
|
|
319
|
+
// Originally copied from upstream Go project, then modified:
|
|
320
|
+
// https://github.com/golang/go/blob/3f995c3f3b43033013013e6c7ccc93a9b1411ca9/misc/wasm/wasm_exec.js#L404-L416
|
|
321
|
+
"syscall/js.copyBytesToJS": (ret_addr, dest_addr, source_addr, source_len, source_cap) => {
|
|
322
|
+
let num_bytes_copied_addr = ret_addr;
|
|
323
|
+
let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable
|
|
324
|
+
|
|
325
|
+
const dst = loadValue(dest_addr);
|
|
326
|
+
const src = loadSlice(source_addr, source_len);
|
|
327
|
+
if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
|
|
328
|
+
mem().setUint8(returned_status_addr, 0); // Return "not ok" status
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
const toCopy = src.subarray(0, dst.length);
|
|
332
|
+
dst.set(toCopy);
|
|
333
|
+
setInt64(num_bytes_copied_addr, toCopy.length);
|
|
334
|
+
mem().setUint8(returned_status_addr, 1); // Return "ok" status
|
|
335
|
+
},
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
storeString(str) {
|
|
341
|
+
const addr = this._inst.exports.getBuffer();
|
|
342
|
+
const buf = this._inst.exports.memory.buffer;
|
|
343
|
+
|
|
344
|
+
const mem = new Uint8Array(buf);
|
|
345
|
+
const view = mem.subarray(addr);
|
|
346
|
+
return encoder.encodeInto(str, view).written;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
loadString(len) {
|
|
350
|
+
const addr = this._inst.exports.getBuffer();
|
|
351
|
+
const buf = this._inst.exports.memory.buffer;
|
|
352
|
+
|
|
353
|
+
return decoder.decode(new DataView(buf, addr, len));
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
async run(instance) {
|
|
357
|
+
this._inst = instance;
|
|
358
|
+
this._values = [ // JS values that Go currently has references to, indexed by reference id
|
|
359
|
+
NaN,
|
|
360
|
+
0,
|
|
361
|
+
null,
|
|
362
|
+
true,
|
|
363
|
+
false,
|
|
364
|
+
"undefined" != typeof globalThis ? globalThis : global || self,
|
|
365
|
+
this,
|
|
366
|
+
];
|
|
367
|
+
this._goRefCounts = []; // number of references that Go has to a JS value, indexed by reference id
|
|
368
|
+
this._ids = new Map(); // mapping from JS values to reference ids
|
|
369
|
+
this._idPool = []; // unused ids that have been garbage collected
|
|
370
|
+
this.exited = false; // whether the Go program has exited
|
|
371
|
+
|
|
372
|
+
const mem = new DataView(this._inst.exports.memory.buffer)
|
|
373
|
+
|
|
374
|
+
while (true) {
|
|
375
|
+
const callbackPromise = new Promise((resolve) => {
|
|
376
|
+
this._resolveCallbackPromise = () => {
|
|
377
|
+
if (this.exited) {
|
|
378
|
+
throw new Error("bad callback: Go program has already exited");
|
|
379
|
+
}
|
|
380
|
+
setTimeout(resolve, 0); // make sure it is asynchronous
|
|
381
|
+
};
|
|
382
|
+
});
|
|
383
|
+
this._inst.exports._start();
|
|
384
|
+
if (this.exited) {
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
await callbackPromise;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
_resume() {
|
|
392
|
+
if (this.exited) {
|
|
393
|
+
throw new Error("Go program has already exited");
|
|
394
|
+
}
|
|
395
|
+
this._inst.exports.resume();
|
|
396
|
+
if (this.exited) {
|
|
397
|
+
this._resolveExitPromise();
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
_makeFuncWrapper(id) {
|
|
402
|
+
const go = this;
|
|
403
|
+
return function () {
|
|
404
|
+
const event = { id: id, this: this, args: arguments };
|
|
405
|
+
go._pendingEvent = event;
|
|
406
|
+
go._resume();
|
|
407
|
+
return event.result;
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
}
|
package/lib.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function format(input: string): Promise<string>;
|
package/lib.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Go } from "./go_wasm.js";
|
|
2
|
+
const go = new Go();
|
|
3
|
+
|
|
4
|
+
let mod;
|
|
5
|
+
|
|
6
|
+
export async function format(input) {
|
|
7
|
+
if (!mod) {
|
|
8
|
+
const url = new URL("lib.wasm", import.meta.url);
|
|
9
|
+
|
|
10
|
+
if (url.protocol === "file:") {
|
|
11
|
+
const fs = await import("node:fs");
|
|
12
|
+
const bytes = fs.readFileSync(url);
|
|
13
|
+
mod = new WebAssembly.Module(bytes);
|
|
14
|
+
} else if ("instantiateStreaming" in WebAssembly) {
|
|
15
|
+
mod = await WebAssembly.compileStreaming(fetch(url), go.importObject);
|
|
16
|
+
} else {
|
|
17
|
+
const response = await fetch(url);
|
|
18
|
+
const bytes = await response.arrayBuffer();
|
|
19
|
+
mod = new WebAssembly.Module(bytes);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const inst = new WebAssembly.Instance(mod, go.importObject);
|
|
24
|
+
go.run(inst);
|
|
25
|
+
|
|
26
|
+
const input_len = go.storeString(input);
|
|
27
|
+
const output_len = inst.exports.format(input_len);
|
|
28
|
+
if (output_len < 0) {
|
|
29
|
+
throw new Error(go.loadString(-output_len));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return go.loadString(output_len);
|
|
33
|
+
}
|
package/lib.wasm
ADDED
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wasm-fmt/gofmt",
|
|
3
|
+
"author": "magic-akari <akari.ccino@gamil.com>",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"description": "wasm based gofmt",
|
|
6
|
+
"main": "lib.js",
|
|
7
|
+
"types": "lib.d.ts",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"go_wasm": "cp $(tinygo env TINYGOROOT)/targets/wasm_exec.js ./go_wasm.js",
|
|
11
|
+
"patch": "git apply ./go_wasm.patch",
|
|
12
|
+
"build": "tinygo build -o=lib.wasm -target=wasm -no-debug -stack-size=24kb ./src/lib.go",
|
|
13
|
+
"test": "node --test"
|
|
14
|
+
},
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=16.17.0"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [],
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
}
|
|
23
|
+
}
|
package/src/lib.go
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import "go/format"
|
|
4
|
+
|
|
5
|
+
const buf_len = 8192
|
|
6
|
+
|
|
7
|
+
var buf [buf_len]byte
|
|
8
|
+
|
|
9
|
+
//go:export getBuffer
|
|
10
|
+
func GetBuffer() *byte {
|
|
11
|
+
return &buf[0]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
//go:export format
|
|
15
|
+
func Format(input_len uint) int {
|
|
16
|
+
input := buf[:input_len]
|
|
17
|
+
output, err := format.Source(input)
|
|
18
|
+
if err != nil {
|
|
19
|
+
return -copy(buf[:], []byte(err.Error()))
|
|
20
|
+
}
|
|
21
|
+
result := len(output)
|
|
22
|
+
|
|
23
|
+
if result > buf_len {
|
|
24
|
+
return -copy(buf[:], []byte("Buffer out of memory"))
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
copy(buf[:], output)
|
|
28
|
+
return result
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
func main() {}
|
package/test.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import test from "node:test";
|
|
4
|
+
import { format } from "./lib.js";
|
|
5
|
+
|
|
6
|
+
const files = (await fs.readdir("testdata"))
|
|
7
|
+
.filter((f) => f.endsWith(".input"))
|
|
8
|
+
.map((f) => {
|
|
9
|
+
return {
|
|
10
|
+
input_name: f,
|
|
11
|
+
golden_name: f.replace(".input", ".golden"),
|
|
12
|
+
};
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
for (const { input_name, golden_name } of files) {
|
|
16
|
+
await test(
|
|
17
|
+
`format ${input_name}`,
|
|
18
|
+
{ skip: input_name[0] === "." },
|
|
19
|
+
async () => {
|
|
20
|
+
const [input, expected] = await Promise.all(
|
|
21
|
+
[input_name, golden_name].map((f) =>
|
|
22
|
+
fs.readFile(`testdata/${f}`, "utf-8")
|
|
23
|
+
)
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const actual = await format(input);
|
|
27
|
+
|
|
28
|
+
assert.strictEqual(actual, expected);
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
}
|