@wasm-fmt/shfmt 0.0.0 → 0.1.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.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@wasm-fmt/shfmt",
3
3
  "description": "A wasm based shell script formatter",
4
4
  "author": "magic-akari <akari.ccino@gmail.com>",
5
- "version": "0.0.0",
5
+ "version": "0.1.0",
6
6
  "license": "MIT",
7
7
  "keywords": [
8
8
  "wasm",
@@ -20,17 +20,14 @@
20
20
  "url": "https://github.com/wasm-fmt/shfmt/issues"
21
21
  },
22
22
  "type": "module",
23
- "main": "shfmt.js",
24
- "module": "shfmt.js",
25
- "types": "shfmt.d.ts",
26
23
  "exports": {
27
24
  ".": {
28
- "types": "./shfmt.d.ts",
25
+ "types": "./shfmt_entry.d.ts",
29
26
  "node": "./shfmt_node.js",
30
- "default": "./shfmt.js"
27
+ "default": "./shfmt_web.js"
31
28
  },
32
29
  "./vite": {
33
- "types": "./shfmt.d.ts",
30
+ "types": "./shfmt_entry.d.ts",
34
31
  "default": "./shfmt_vite.js"
35
32
  },
36
33
  "./package.json": "./package.json",
@@ -48,8 +45,5 @@
48
45
  },
49
46
  "publishConfig": {
50
47
  "access": "public"
51
- },
52
- "devDependencies": {
53
- "@ast-grep/napi": "0.40.3"
54
48
  }
55
49
  }
@@ -0,0 +1,9 @@
1
+ export declare const memory: WebAssembly.Memory;
2
+ export declare function _initialize(): void;
3
+ export declare function alloc(size: number): number;
4
+ export declare function dispose(): void;
5
+ export declare function format(): 0 | 1 | 2;
6
+ export declare function output_ptr(): number;
7
+ export declare function output_len(): number;
8
+ export declare function set_options(): void;
9
+ export declare function set_path(): void;
package/shfmt.js CHANGED
@@ -1,434 +1,61 @@
1
- /* @ts-self-types="./shfmt.d.ts" */
2
- // Copyright 2018 The Go Authors. All rights reserved.
3
- // Use of this source code is governed by a BSD-style
4
- // license that can be found in the LICENSE file.
5
- //
6
- // This file has been modified for use by the TinyGo compiler.
7
-
8
- // End of polyfills for common API.
9
-
10
- const encoder = new TextEncoder("utf-8");
11
- const decoder = new TextDecoder("utf-8");
12
- let reinterpretBuf = new DataView(new ArrayBuffer(8));
13
- var logLine = [];
14
- const wasmExit = {}; // thrown to exit via proc_exit (not an error)
15
-
16
- class Go {
17
- constructor() {
18
- this._callbackTimeouts = new Map();
19
- this._nextCallbackTimeoutID = 1;
20
-
21
- const mem = () => {
22
- // The buffer may change when requesting more memory.
23
- return new DataView(this._inst.exports.memory.buffer);
24
- }
25
-
26
- const unboxValue = (v_ref) => {
27
- reinterpretBuf.setBigInt64(0, v_ref, true);
28
- const f = reinterpretBuf.getFloat64(0, true);
29
- if (f === 0) {
30
- return undefined;
31
- }
32
- if (!isNaN(f)) {
33
- return f;
34
- }
35
-
36
- const id = v_ref & 0xffffffffn;
37
- return this._values[id];
38
- }
39
-
40
-
41
- const loadValue = (addr) => {
42
- let v_ref = mem().getBigUint64(addr, true);
43
- return unboxValue(v_ref);
44
- }
45
-
46
- const boxValue = (v) => {
47
- const nanHead = 0x7FF80000n;
48
-
49
- if (typeof v === "number") {
50
- if (isNaN(v)) {
51
- return nanHead << 32n;
52
- }
53
- if (v === 0) {
54
- return (nanHead << 32n) | 1n;
55
- }
56
- reinterpretBuf.setFloat64(0, v, true);
57
- return reinterpretBuf.getBigInt64(0, true);
58
- }
59
-
60
- switch (v) {
61
- case undefined:
62
- return 0n;
63
- case null:
64
- return (nanHead << 32n) | 2n;
65
- case true:
66
- return (nanHead << 32n) | 3n;
67
- case false:
68
- return (nanHead << 32n) | 4n;
69
- }
70
-
71
- let id = this._ids.get(v);
72
- if (id === undefined) {
73
- id = this._idPool.pop();
74
- if (id === undefined) {
75
- id = BigInt(this._values.length);
76
- }
77
- this._values[id] = v;
78
- this._goRefCounts[id] = 0;
79
- this._ids.set(v, id);
80
- }
81
- this._goRefCounts[id]++;
82
- let typeFlag = 1n;
83
- switch (typeof v) {
84
- case "string":
85
- typeFlag = 2n;
86
- break;
87
- case "symbol":
88
- typeFlag = 3n;
89
- break;
90
- case "function":
91
- typeFlag = 4n;
92
- break;
93
- }
94
- return id | ((nanHead | typeFlag) << 32n);
95
- }
96
-
97
- const storeValue = (addr, v) => {
98
- let v_ref = boxValue(v);
99
- mem().setBigUint64(addr, v_ref, true);
100
- }
101
-
102
- const loadSlice = (array, len, cap) => {
103
- return new Uint8Array(this._inst.exports.memory.buffer, array, len);
104
- }
105
-
106
- const loadSliceOfValues = (array, len, cap) => {
107
- const a = new Array(len);
108
- for (let i = 0; i < len; i++) {
109
- a[i] = loadValue(array + i * 8);
110
- }
111
- return a;
112
- }
113
-
114
- const loadString = (ptr, len) => {
115
- return decoder.decode(new DataView(this._inst.exports.memory.buffer, ptr, len));
116
- }
117
-
118
- const timeOrigin = Date.now() - performance.now();
119
- this.importObject = {
120
- wasi_snapshot_preview1: {
121
- // https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#fd_write
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
- },
163
- },
164
- gojs: {
165
- // func ticks() int64
166
- "runtime.ticks": () => {
167
- return BigInt((timeOrigin + performance.now()) * 1e6);
168
- },
169
-
170
- // func sleepTicks(timeout int64)
171
- /* removed runtime.sleepTicks */
172
-
173
- // func finalizeRef(v ref)
174
- "syscall/js.finalizeRef": (v_ref) => {
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.
177
- const id = v_ref & 0xffffffffn;
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);
188
- }
189
- },
190
-
191
- // func stringVal(value string) ref
192
- "syscall/js.stringVal": (value_ptr, value_len) => {
193
- value_ptr >>>= 0;
194
- const s = loadString(value_ptr, value_len);
195
- return boxValue(s);
196
- },
197
-
198
- // func valueGet(v ref, p string) ref
199
- "syscall/js.valueGet": (v_ref, p_ptr, p_len) => {
200
- let prop = loadString(p_ptr, p_len);
201
- let v = unboxValue(v_ref);
202
- let result = Reflect.get(v, prop);
203
- return boxValue(result);
204
- },
205
-
206
- // func valueSet(v ref, p string, x ref)
207
- "syscall/js.valueSet": (v_ref, p_ptr, p_len, x_ref) => {
208
- const v = unboxValue(v_ref);
209
- const p = loadString(p_ptr, p_len);
210
- const x = unboxValue(x_ref);
211
- Reflect.set(v, p, x);
212
- },
213
-
214
- // func valueDelete(v ref, p string)
215
- /* removed syscall/js.valueDelete */
216
-
217
- // func valueIndex(v ref, i int) ref
218
- "syscall/js.valueIndex": (v_ref, i) => {
219
- return boxValue(Reflect.get(unboxValue(v_ref), i));
220
- },
221
-
222
- // valueSetIndex(v ref, i int, x ref)
223
- "syscall/js.valueSetIndex": (v_ref, i, x_ref) => {
224
- Reflect.set(unboxValue(v_ref), i, unboxValue(x_ref));
225
- },
226
-
227
- // func valueCall(v ref, m string, args []ref) (ref, bool)
228
- "syscall/js.valueCall": (ret_addr, v_ref, m_ptr, m_len, args_ptr, args_len, args_cap) => {
229
- const v = unboxValue(v_ref);
230
- const name = loadString(m_ptr, m_len);
231
- const args = loadSliceOfValues(args_ptr, args_len, args_cap);
232
- try {
233
- const m = Reflect.get(v, name);
234
- storeValue(ret_addr, Reflect.apply(m, v, args));
235
- mem().setUint8(ret_addr + 8, 1);
236
- } catch (err) {
237
- storeValue(ret_addr, err);
238
- mem().setUint8(ret_addr + 8, 0);
239
- }
240
- },
241
-
242
- // func valueInvoke(v ref, args []ref) (ref, bool)
243
- /* removed syscall/js.valueInvoke */
244
-
245
- // func valueNew(v ref, args []ref) (ref, bool)
246
- "syscall/js.valueNew": (ret_addr, v_ref, args_ptr, args_len, args_cap) => {
247
- const v = unboxValue(v_ref);
248
- const args = loadSliceOfValues(args_ptr, args_len, args_cap);
249
- try {
250
- storeValue(ret_addr, Reflect.construct(v, args));
251
- mem().setUint8(ret_addr + 8, 1);
252
- } catch (err) {
253
- storeValue(ret_addr, err);
254
- mem().setUint8(ret_addr+ 8, 0);
255
- }
256
- },
257
-
258
- // func valueLength(v ref) int
259
- "syscall/js.valueLength": (v_ref) => {
260
- return unboxValue(v_ref).length;
261
- },
262
-
263
- // valuePrepareString(v ref) (ref, int)
264
- "syscall/js.valuePrepareString": (ret_addr, v_ref) => {
265
- const s = String(unboxValue(v_ref));
266
- const str = encoder.encode(s);
267
- storeValue(ret_addr, str);
268
- mem().setInt32(ret_addr + 8, str.length, true);
269
- },
270
-
271
- // valueLoadString(v ref, b []byte)
272
- "syscall/js.valueLoadString": (v_ref, slice_ptr, slice_len, slice_cap) => {
273
- const str = unboxValue(v_ref);
274
- loadSlice(slice_ptr, slice_len, slice_cap).set(str);
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 */
287
- }
288
- };
1
+ /**
2
+ * @import * as WASM from "./shfmt.wasm"
3
+ */
289
4
 
290
- // Go 1.20 uses 'env'. Go 1.21 uses 'gojs'.
291
- // For compatibility, we use both as long as Go 1.20 is supported.
292
- this.importObject.env = this.importObject.gojs;
5
+ /**
6
+ * @param {WASM} wasm
7
+ * @param {string} source
8
+ * @param {string} [path]
9
+ * @param {object} [options]
10
+ * @return {string}
11
+ */
12
+ export function format(wasm, source, path, options) {
13
+ try {
14
+ if (options) {
15
+ writeStringToWasmMemory(wasm, JSON.stringify(options));
16
+ wasm.set_options();
293
17
  }
294
18
 
295
- async run(instance) {
296
- this._inst = instance;
297
- this._values = [ // JS values that Go currently has references to, indexed by reference id
298
- NaN,
299
- 0,
300
- null,
301
- true,
302
- false,
303
- /* fake global */ { set format(fn) { _format = fn }, Array, Object},
304
- this,
305
- ];
306
- this._goRefCounts = []; // number of references that Go has to a JS value, indexed by reference id
307
- this._ids = new Map(); // mapping from JS values to reference ids
308
- this._idPool = []; // unused ids that have been garbage collected
309
- this.exited = false; // whether the Go program has exited
310
- this.exitCode = 0;
311
-
312
- if (this._inst.exports._start) {
313
- let exitPromise = new Promise((resolve, reject) => {
314
- this._resolveExitPromise = resolve;
315
- });
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;
323
- }
324
-
325
- await exitPromise;
326
- return this.exitCode;
327
- } else {
328
- this._inst.exports._initialize();
329
- }
19
+ if (path) {
20
+ writeStringToWasmMemory(wasm, path);
21
+ wasm.set_path();
330
22
  }
331
23
 
332
- _resume() {
333
- if (this.exited) {
334
- throw new Error("Go program has already exited");
335
- }
336
- try {
337
- this._inst.exports.resume();
338
- } catch (e) {
339
- if (e !== wasmExit) throw e;
340
- }
341
- if (this.exited) {
342
- this._resolveExitPromise();
343
- }
24
+ writeStringToWasmMemory(wasm, source);
25
+ const result = wasm.format();
26
+ if (result === 0) {
27
+ return source;
344
28
  }
345
29
 
346
- _makeFuncWrapper(id) {
347
- const go = this;
348
- return function () {
349
- const event = { id: id, this: this, args: arguments };
350
- go._pendingEvent = event;
351
- go._resume();
352
- return event.result;
353
- };
30
+ const ptr = wasm.output_ptr();
31
+ const length = wasm.output_len();
32
+ const text = readStringFromWasmMemory(wasm, ptr, length);
33
+
34
+ if (result === 1) {
35
+ return text;
354
36
  }
37
+
38
+ throw new Error(text);
39
+ } finally {
40
+ wasm.dispose();
355
41
  }
42
+ }
43
+
356
44
  /**
357
- * ================== End of wasm_exec.js ==================
45
+ * @param {WASM} wasm
46
+ * @param {string} str
358
47
  */
359
- let wasm, wasmModule;
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
- }
48
+ function writeStringToWasmMemory(wasm, str) {
49
+ const bytes = encoder.encode(str);
50
+ const ptr = wasm.alloc(bytes.length);
51
+ const memory = new Uint8Array(wasm.memory.buffer, ptr, bytes.length);
52
+ memory.set(bytes);
384
53
  }
385
- function __finalize_init(instance, module) {
386
- (wasm = instance.exports), (wasmModule = module);
387
- return wasm;
388
- }
389
-
390
- export function initSync(module) {
391
- if (wasm !== void 0) return wasm;
392
54
 
393
- const go = new Go();
394
- const imports = go.importObject;
395
-
396
- if (!(module instanceof WebAssembly.Module))
397
- module = new WebAssembly.Module(module);
398
-
399
- const instance = new WebAssembly.Instance(module, imports);
400
-
401
- go.run(instance);
402
- return __finalize_init(instance, module);
55
+ function readStringFromWasmMemory(wasm, ptr, length) {
56
+ const memory = new Uint8Array(wasm.memory.buffer, ptr, length);
57
+ return decoder.decode(memory);
403
58
  }
404
- export default async function initAsync(input) {
405
- if (wasm !== void 0) return wasm;
406
-
407
- if (input === void 0) input = new URL("shfmt.wasm", import.meta.url);
408
59
 
409
- const go = new Go();
410
- const imports = go.importObject;
411
-
412
- if (
413
- typeof input === "string" ||
414
- (typeof Request === "function" && input instanceof Request) ||
415
- (typeof URL === "function" && input instanceof URL)
416
- ) {
417
- input = fetch(input);
418
- }
419
-
420
- const { instance, module } = await __load(await input, imports);
421
-
422
- go.run(instance);
423
- return __finalize_init(instance, module);
424
- }
425
- var _format = function () {
426
- throw new Error("wasm not initialized.");
427
- };
428
- export function format(input, path, options) {
429
- const [result, err] = _format(input, path, options);
430
- if (err) {
431
- throw new Error(result);
432
- }
433
- return result;
434
- }
60
+ const encoder = new TextEncoder();
61
+ const decoder = new TextDecoder();
package/shfmt.wasm CHANGED
Binary file
@@ -0,0 +1,16 @@
1
+ import wasm from "./shfmt.wasm";
2
+ import { format as _format } from "./shfmt.js";
3
+
4
+ wasm._initialize();
5
+
6
+ export function initSync() {
7
+ return wasm;
8
+ }
9
+
10
+ export default async function initAsync() {
11
+ return wasm;
12
+ }
13
+
14
+ export function format(source, path, options) {
15
+ return _format(wasm, source, path, options);
16
+ }
@@ -0,0 +1,28 @@
1
+ export type InitInput =
2
+ | RequestInfo
3
+ | URL
4
+ | Response
5
+ | BufferSource
6
+ | WebAssembly.Module;
7
+ export type SyncInitInput = BufferSource | WebAssembly.Module;
8
+ import type * as InitOutput from "./shfmt.d.wasm.ts";
9
+
10
+ export default function initAsync(
11
+ init_input?: InitInput | Promise<InitInput>,
12
+ ): Promise<InitOutput>;
13
+ export declare function initSync(buffer_or_module: SyncInitInput): InitOutput;
14
+ export interface FormatOptions {
15
+ indent?: number;
16
+ binaryNextLine?: boolean;
17
+ switchCaseIndent?: boolean;
18
+ spaceRedirects?: boolean;
19
+ funcNextLine?: boolean;
20
+ minify?: boolean;
21
+ singleLine?: boolean;
22
+ simplify?: boolean;
23
+ }
24
+ export declare function format(
25
+ input: string,
26
+ path?: string,
27
+ options?: FormatOptions,
28
+ ): string;
package/shfmt_esm.js ADDED
@@ -0,0 +1,25 @@
1
+ import source wasmModule from "./shfmt.wasm";
2
+ import { format as _format } from "./shfmt.js";
3
+ /**
4
+ * @import * as WASM from "./shfmt.wasm"
5
+ */
6
+
7
+ const instance = new WebAssembly.Instance(wasmModule);
8
+
9
+ /**
10
+ * @type {WASM}
11
+ */
12
+ let wasm = instance.exports;
13
+ wasm._initialize();
14
+
15
+ export function initSync() {
16
+ return wasm;
17
+ }
18
+
19
+ export default async function initAsync() {
20
+ return wasm;
21
+ }
22
+
23
+ export function format(source, path, options) {
24
+ return _format(wasm, source, path, options);
25
+ }
package/shfmt_node.js CHANGED
@@ -1,10 +1,101 @@
1
- import fs from "node:fs/promises";
2
- import initAsync from "./shfmt.js";
1
+ /* @ts-self-types="./shfmt_entry.d.ts" */
2
+ import { format as _format } from "./shfmt.js";
3
+ let wasm, wasmModule;
3
4
 
4
- const wasm = new URL("./shfmt.wasm", import.meta.url);
5
+ async function load(module, imports) {
6
+ if (typeof Response === "function" && module instanceof Response) {
7
+ if (typeof WebAssembly.instantiateStreaming === "function") {
8
+ try {
9
+ return await WebAssembly.instantiateStreaming(module, imports);
10
+ } catch (e) {
11
+ const validResponse =
12
+ module.ok && expectedResponseType(module.type);
5
13
 
6
- export default function (init = fs.readFile(wasm)) {
7
- return initAsync(init);
14
+ if (
15
+ validResponse &&
16
+ module.headers.get("Content-Type") !== "application/wasm"
17
+ ) {
18
+ console.warn(
19
+ "`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",
20
+ e,
21
+ );
22
+ } else {
23
+ throw e;
24
+ }
25
+ }
26
+ }
27
+
28
+ const bytes = await module.arrayBuffer();
29
+ return await WebAssembly.instantiate(bytes, imports);
30
+ } else {
31
+ const instance = await WebAssembly.instantiate(module, imports);
32
+
33
+ if (instance instanceof WebAssembly.Instance) {
34
+ return { instance, module };
35
+ } else {
36
+ return instance;
37
+ }
38
+ }
39
+
40
+ function expectedResponseType(type) {
41
+ switch (type) {
42
+ case "basic":
43
+ case "cors":
44
+ case "default":
45
+ return true;
46
+ }
47
+ return false;
48
+ }
49
+ }
50
+
51
+ function finalize_init(instance, module) {
52
+ wasm = instance.exports, wasmModule = module;
53
+ wasm._initialize();
54
+ return wasm;
55
+ }
56
+
57
+ export function initSync(buffer_or_module) {
58
+ if (wasm !== void 0) return wasm;
59
+
60
+ if (!(buffer_or_module instanceof WebAssembly.Module)) {
61
+ buffer_or_module = new WebAssembly.Module(buffer_or_module);
62
+ }
63
+
64
+ return finalize_init(
65
+ new WebAssembly.Instance(buffer_or_module),
66
+ buffer_or_module,
67
+ );
8
68
  }
9
69
 
10
- export * from "./shfmt.js";
70
+ export default async function initAsync(init_input) {
71
+ if (wasm !== void 0) return wasm;
72
+
73
+ if (init_input === void 0) {
74
+ init_input = new URL("shfmt.wasm", import.meta.url);
75
+ }
76
+
77
+ if (typeof init_input === "string") {
78
+ init_input = new URL(init_input);
79
+ }
80
+
81
+ if (init_input instanceof URL && init_input.protocol === "file:") {
82
+ const [{ readFile }, { fileURLToPath }] = await Promise.all([
83
+ import("fs/promises"),
84
+ import("url"),
85
+ ]);
86
+ init_input = readFile(fileURLToPath(init_input));
87
+ } else if (
88
+ (typeof Request === "function" && init_input instanceof Request) ||
89
+ init_input instanceof URL
90
+ ) {
91
+ init_input = fetch(init_input);
92
+ }
93
+
94
+ const { instance, module } = await load(await init_input);
95
+
96
+ return finalize_init(instance, module);
97
+ }
98
+
99
+ export function format(source, path, options) {
100
+ return _format(wasm, source, path, options);
101
+ }
package/shfmt_vite.js CHANGED
@@ -1,8 +1,9 @@
1
- import initAsync from "./shfmt.js";
1
+ /* @ts-self-types="./shfmt_entry.d.ts" */
2
+ import initAsync from "./shfmt_web.js";
2
3
  import wasm_url from "./shfmt.wasm?url";
3
4
 
4
5
  export default function (input = wasm_url) {
5
6
  return initAsync(input);
6
7
  }
7
8
 
8
- export * from "./shfmt.js";
9
+ export * from "./shfmt_web.js";
package/shfmt_web.js ADDED
@@ -0,0 +1,89 @@
1
+ /* @ts-self-types="./shfmt_entry.d.ts" */
2
+ import { format as _format } from "./shfmt.js";
3
+ let wasm, wasmModule;
4
+
5
+ async function load(module, imports) {
6
+ if (typeof Response === "function" && module instanceof Response) {
7
+ if (typeof WebAssembly.instantiateStreaming === "function") {
8
+ try {
9
+ return await WebAssembly.instantiateStreaming(module, imports);
10
+ } catch (e) {
11
+ const validResponse =
12
+ module.ok && expectedResponseType(module.type);
13
+
14
+ if (
15
+ validResponse &&
16
+ module.headers.get("Content-Type") !== "application/wasm"
17
+ ) {
18
+ console.warn(
19
+ "`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",
20
+ e,
21
+ );
22
+ } else {
23
+ throw e;
24
+ }
25
+ }
26
+ }
27
+
28
+ const bytes = await module.arrayBuffer();
29
+ return await WebAssembly.instantiate(bytes, imports);
30
+ } else {
31
+ const instance = await WebAssembly.instantiate(module, imports);
32
+
33
+ if (instance instanceof WebAssembly.Instance) {
34
+ return { instance, module };
35
+ } else {
36
+ return instance;
37
+ }
38
+ }
39
+
40
+ function expectedResponseType(type) {
41
+ switch (type) {
42
+ case "basic":
43
+ case "cors":
44
+ case "default":
45
+ return true;
46
+ }
47
+ return false;
48
+ }
49
+ }
50
+
51
+ function finalize_init(instance, module) {
52
+ wasm = instance.exports, wasmModule = module;
53
+ wasm._initialize();
54
+ return wasm;
55
+ }
56
+
57
+ export function initSync(module) {
58
+ if (wasm !== void 0) return wasm;
59
+
60
+ if (!(module instanceof WebAssembly.Module)) {
61
+ module = new WebAssembly.Module(module);
62
+ }
63
+ const instance = new WebAssembly.Instance(module);
64
+ return finalize_init(instance, module);
65
+ }
66
+
67
+ export default async function initAsync(module_or_path) {
68
+ if (wasm !== void 0) return wasm;
69
+
70
+ if (module_or_path === void 0) {
71
+ module_or_path = new URL("shfmt.wasm", import.meta.url);
72
+ }
73
+
74
+ if (
75
+ typeof module_or_path === "string" ||
76
+ (typeof Request === "function" && module_or_path instanceof Request) ||
77
+ (typeof URL === "function" && module_or_path instanceof URL)
78
+ ) {
79
+ module_or_path = fetch(module_or_path);
80
+ }
81
+
82
+ const { instance, module } = await load(await module_or_path);
83
+
84
+ return finalize_init(instance, module);
85
+ }
86
+
87
+ export function format(source, path, options) {
88
+ return _format(wasm, source, path, options);
89
+ }
package/shfmt.d.ts DELETED
@@ -1,56 +0,0 @@
1
- export type InitInput =
2
- | RequestInfo
3
- | URL
4
- | Response
5
- | BufferSource
6
- | WebAssembly.Module;
7
-
8
- /**
9
- * Initializes the WASM module asynchronously.
10
- * @param wasm_url - Optional URL/path to the WASM file, or any valid InitInput
11
- */
12
- export default function initAsync(wasm_url?: InitInput): Promise<void>;
13
- /**
14
- * Initializes the WASM module synchronously.
15
- * @param module - The WASM module or buffer source
16
- */
17
- export declare function initSync(
18
- module: BufferSource | WebAssembly.Module,
19
- ): void;
20
-
21
- /**
22
- * Formats a shell script source code.
23
- * @param source - The shell script source code to format
24
- * @param path - Optional file path for language detection (e.g., ".bash", ".sh")
25
- * @param options - Formatting options
26
- * @returns The formatted shell script
27
- */
28
- export declare function format(
29
- source: string,
30
- path?: string,
31
- options?: FormatOptions,
32
- ): string;
33
-
34
- /**
35
- * Options for formatting shell scripts.
36
- * These options correspond to shfmt's command-line flags.
37
- * @see https://pkg.go.dev/mvdan.cc/sh/v3/syntax#PrinterOption
38
- */
39
- export type FormatOptions = {
40
- /** Indent sets the number of spaces used for indentation. If set to 0, tabs will be used instead. */
41
- indent?: number;
42
- /** BinaryNextLine will make binary operators appear on the next line when a binary command, such as a pipe, spans multiple lines. A backslash will be used. */
43
- binaryNextLine?: boolean;
44
- /** SwitchCaseIndent will make switch cases be indented. As such, switch case bodies will be two levels deeper than the switch itself. */
45
- switchCaseIndent?: boolean;
46
- /** SpaceRedirects will put a space after most redirection operators. The exceptions are '>&', '<&', '>(', and '<('. */
47
- spaceRedirects?: boolean;
48
- /** FunctionNextLine will place a function's opening braces on the next line. */
49
- funcNextLine?: boolean;
50
- /** Minify will print programs in a way to save the most bytes possible. For example, indentation and comments are skipped, and extra whitespace is avoided when possible. */
51
- minify?: boolean;
52
- /** SingleLine will attempt to print programs in one line. For example, lists of commands or nested blocks do not use newlines in this mode. Note that some newlines must still appear, such as those following comments or around here-documents. */
53
- singleLine?: boolean;
54
- /** Simplify will perform a series of simplifications on the AST, to prepare it for printing. */
55
- simplify?: boolean;
56
- };