@wasm-fmt/shfmt 0.1.0 → 0.2.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/README.md CHANGED
@@ -16,10 +16,10 @@ npx jsr add @fmt/shfmt
16
16
 
17
17
  # Usage
18
18
 
19
- ```JavaScript
20
- import init, { format } from "@wasm-fmt/shfmt";
19
+ ## Node.js / Deno / Bun / Bundler
21
20
 
22
- await init();
21
+ ```javascript
22
+ import { format } from "@wasm-fmt/shfmt";
23
23
 
24
24
  const source = `#!/bin/bash
25
25
  echo "hello world"
@@ -31,20 +31,55 @@ console.log(formatted);
31
31
 
32
32
  With options:
33
33
 
34
- ```JavaScript
34
+ ```javascript
35
35
  const formatted = format(source, "script.sh", {
36
- indent: 2,
37
- binaryNextLine: true,
38
- switchCaseIndent: false,
39
- spaceRedirects: true,
40
- keepPadding: false,
41
- funcNextLine: false,
42
- minify: false,
43
- simplify: true
36
+ indent: 2,
37
+ binaryNextLine: true,
38
+ switchCaseIndent: false,
39
+ spaceRedirects: true,
40
+ funcNextLine: false,
41
+ minify: false,
42
+ singleLine: false,
43
+ simplify: true,
44
44
  });
45
45
  ```
46
46
 
47
- # Build from source
47
+ ## Web
48
+
49
+ For web environments, you need to initialize WASM module manually:
50
+
51
+ ```javascript
52
+ import init, { format } from "@wasm-fmt/shfmt/web";
53
+
54
+ await init();
55
+
56
+ const source = `#!/bin/bash
57
+ echo "hello world"
58
+ `;
59
+
60
+ const formatted = format(source);
61
+ console.log(formatted);
62
+ ```
63
+
64
+ ### Vite
65
+
66
+ ```JavaScript
67
+ import init, { format } from "@wasm-fmt/shfmt/vite";
68
+
69
+ await init();
70
+ // ...
71
+ ```
72
+
73
+ ## Entry Points
74
+
75
+ - `.` - Auto-detects environment (Node.js uses node, Webpack uses bundler, default is ESM)
76
+ - `./node` - Node.js environment (no init required)
77
+ - `./esm` - ESM environments like Deno (no init required)
78
+ - `./bundler` - Bundlers like Webpack (no init required)
79
+ - `./web` - Web browsers (requires manual init)
80
+ - `./vite` - Vite bundler (requires manual init)
81
+
82
+ ## Build from source
48
83
 
49
84
  ```bash
50
85
  # 1. install Go https://go.dev/doc/install
@@ -63,3 +98,9 @@ npm run build
63
98
  # 6. test
64
99
  npm run test:node
65
100
  ```
101
+
102
+ # Credits
103
+
104
+ Thanks to:
105
+
106
+ - The [shfmt](https://github.com/mvdan/sh) project created by [Daniel Martí](https://github.com/mvdan)
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.1.0",
5
+ "version": "0.2.0",
6
6
  "license": "MIT",
7
7
  "keywords": [
8
8
  "wasm",
@@ -23,18 +23,37 @@
23
23
  "exports": {
24
24
  ".": {
25
25
  "types": "./shfmt_entry.d.ts",
26
+ "webpack": "./shfmt_bundle.js",
26
27
  "node": "./shfmt_node.js",
28
+ "default": "./shfmt_esm.js"
29
+ },
30
+ "./esm": {
31
+ "types": "./shfmt_entry.d.ts",
32
+ "default": "./shfmt_esm.js"
33
+ },
34
+ "./node": {
35
+ "types": "./shfmt_entry.d.ts",
36
+ "default": "./shfmt_node.js"
37
+ },
38
+ "./bundler": {
39
+ "types": "./shfmt_entry.d.ts",
40
+ "default": "./shfmt_bundle.js"
41
+ },
42
+ "./web": {
43
+ "types": "./shfmt_web.d.ts",
27
44
  "default": "./shfmt_web.js"
28
45
  },
29
46
  "./vite": {
30
- "types": "./shfmt_entry.d.ts",
47
+ "types": "./shfmt_web.d.ts",
31
48
  "default": "./shfmt_vite.js"
32
49
  },
50
+ "./wasm": "./shfmt.wasm",
33
51
  "./package.json": "./package.json",
34
52
  "./*": "./*"
35
53
  },
36
54
  "scripts": {
37
55
  "build": "./scripts/build.sh",
56
+ "fmt": "dprint fmt",
38
57
  "test:go": "go test -C src -v",
39
58
  "test:node": "node --test test_node/shfmt.test.js",
40
59
  "test:deno": "deno test test_deno --allow-read",
package/shfmt_bundle.js CHANGED
@@ -1,16 +1,9 @@
1
+ /* @ts-self-types="./shfmt_entry.d.ts" */
1
2
  import wasm from "./shfmt.wasm";
2
3
  import { format as _format } from "./shfmt.js";
3
4
 
4
5
  wasm._initialize();
5
6
 
6
- export function initSync() {
7
- return wasm;
8
- }
9
-
10
- export default async function initAsync() {
11
- return wasm;
12
- }
13
-
14
7
  export function format(source, path, options) {
15
8
  return _format(wasm, source, path, options);
16
9
  }
package/shfmt_entry.d.ts CHANGED
@@ -1,28 +1,32 @@
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";
1
+ /**
2
+ * Formats a shell script source code.
3
+ * @param source - The shell script source code to format
4
+ * @param path - Optional file path for language detection (e.g., ".bash", ".sh")
5
+ * @param options - Formatting options
6
+ * @returns The formatted shell script
7
+ */
8
+ export declare function format(source: string, path?: string, options?: FormatOptions): string;
9
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 {
10
+ /**
11
+ * Options for formatting shell scripts.
12
+ * These options correspond to shfmt's command-line flags.
13
+ * @see https://pkg.go.dev/mvdan.cc/sh/v3/syntax#PrinterOption
14
+ */
15
+ export type FormatOptions = {
16
+ /** Indent sets the number of spaces used for indentation. If set to 0, tabs will be used instead. */
15
17
  indent?: number;
18
+ /** 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. */
16
19
  binaryNextLine?: boolean;
20
+ /** SwitchCaseIndent will make switch cases be indented. As such, switch case bodies will be two levels deeper than the switch itself. */
17
21
  switchCaseIndent?: boolean;
22
+ /** SpaceRedirects will put a space after most redirection operators. The exceptions are '>&', '<&', '>(', and '<('. */
18
23
  spaceRedirects?: boolean;
24
+ /** FunctionNextLine will place a function's opening braces on the next line. */
19
25
  funcNextLine?: boolean;
26
+ /** 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. */
20
27
  minify?: boolean;
28
+ /** 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. */
21
29
  singleLine?: boolean;
30
+ /** Simplify will perform a series of simplifications on the AST, to prepare it for printing. */
22
31
  simplify?: boolean;
23
- }
24
- export declare function format(
25
- input: string,
26
- path?: string,
27
- options?: FormatOptions,
28
- ): string;
32
+ };
package/shfmt_esm.js CHANGED
@@ -1,3 +1,9 @@
1
+ /* @ts-self-types="./shfmt_entry.d.ts" */
2
+ /**
3
+ * Loads the Wasm module via source phase import.
4
+ * @module
5
+ */
6
+ // prettier-ignore
1
7
  import source wasmModule from "./shfmt.wasm";
2
8
  import { format as _format } from "./shfmt.js";
3
9
  /**
@@ -9,17 +15,9 @@ const instance = new WebAssembly.Instance(wasmModule);
9
15
  /**
10
16
  * @type {WASM}
11
17
  */
12
- let wasm = instance.exports;
18
+ const wasm = instance.exports;
13
19
  wasm._initialize();
14
20
 
15
- export function initSync() {
16
- return wasm;
17
- }
18
-
19
- export default async function initAsync() {
20
- return wasm;
21
- }
22
-
23
21
  export function format(source, path, options) {
24
22
  return _format(wasm, source, path, options);
25
23
  }
package/shfmt_node.js CHANGED
@@ -1,100 +1,26 @@
1
1
  /* @ts-self-types="./shfmt_entry.d.ts" */
2
+ /**
3
+ * Loads the Wasm module using Node's fs API.
4
+ * Consider using `./esm` entry if your environment supports source phase import.
5
+ * @module
6
+ */
7
+ import { readFileSync } from "node:fs";
2
8
  import { format as _format } from "./shfmt.js";
3
- let wasm, wasmModule;
4
9
 
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);
10
+ const wasmUrl = new URL("shfmt.wasm", import.meta.url);
11
+ const wasmBytes = readFileSync(wasmUrl);
12
+ const wasmModule = new WebAssembly.Module(wasmBytes);
13
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
- }
14
+ /**
15
+ * @import * as WASM from "./shfmt.wasm"
16
+ */
27
17
 
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
- );
68
- }
69
-
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
- }
18
+ const instance = new WebAssembly.Instance(wasmModule);
19
+ /**
20
+ * @type {WASM}
21
+ */
22
+ const wasm = instance.exports;
23
+ wasm._initialize();
98
24
 
99
25
  export function format(source, path, options) {
100
26
  return _format(wasm, source, path, options);
package/shfmt_vite.js CHANGED
@@ -1,9 +1,37 @@
1
- /* @ts-self-types="./shfmt_entry.d.ts" */
1
+ /* @ts-self-types="./shfmt_web.d.ts" */
2
+ /**
3
+ * Loads the Wasm module for Vite and bundlers supporting `?init` imports.
4
+ * @module
5
+ */
6
+ import init from "./shfmt.wasm?init";
2
7
  import initAsync from "./shfmt_web.js";
3
- import wasm_url from "./shfmt.wasm?url";
8
+ import { format as _format } from "./shfmt.js";
4
9
 
5
- export default function (input = wasm_url) {
6
- return initAsync(input);
10
+ let wasm, wasmModule;
11
+
12
+ function finalize_init(instance, module) {
13
+ wasm = instance.exports;
14
+ wasmModule = module;
15
+ wasm._initialize();
16
+ return wasm;
17
+ }
18
+
19
+ export default async function initAsync() {
20
+ if (wasm !== void 0) return wasm;
21
+ const instance = await init();
22
+ return finalize_init(instance);
7
23
  }
8
24
 
9
- export * from "./shfmt_web.js";
25
+ export function initSync(module) {
26
+ if (wasm !== void 0) return wasm;
27
+
28
+ if (!(module instanceof WebAssembly.Module)) {
29
+ module = new WebAssembly.Module(module);
30
+ }
31
+ const instance = new WebAssembly.Instance(module, getImports());
32
+ return finalize_init(instance, module);
33
+ }
34
+
35
+ export function format(source, path, options) {
36
+ return _format(wasm, source, path, options);
37
+ }
package/shfmt_web.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
2
+ export type SyncInitInput = BufferSource | WebAssembly.Module;
3
+ import type * as InitOutput from "./shfmt.wasm";
4
+
5
+ /**
6
+ * Initializes the WASM module asynchronously.
7
+ * @param init_input - Optional URL/path to the WASM file, or any valid InitInput
8
+ */
9
+ export default function initAsync(init_input?: InitInput): Promise<InitOutput>;
10
+ /**
11
+ * Initializes the WASM module synchronously.
12
+ * @param buffer_or_module - The WASM module or buffer source
13
+ */
14
+ export declare function initSync(buffer_or_module: BufferSource | WebAssembly.Module): InitOutput;
15
+
16
+ export * from "shfmt_entry.d.ts";
package/shfmt_web.js CHANGED
@@ -1,4 +1,9 @@
1
- /* @ts-self-types="./shfmt_entry.d.ts" */
1
+ /* @ts-self-types="./shfmt_web.d.ts" */
2
+ /**
3
+ * Loads the Wasm module via Web Fetch API (browsers).
4
+ * Requires calling init().
5
+ * @module
6
+ */
2
7
  import { format as _format } from "./shfmt.js";
3
8
  let wasm, wasmModule;
4
9
 
@@ -8,13 +13,9 @@ async function load(module, imports) {
8
13
  try {
9
14
  return await WebAssembly.instantiateStreaming(module, imports);
10
15
  } catch (e) {
11
- const validResponse =
12
- module.ok && expectedResponseType(module.type);
16
+ const validResponse = module.ok && expectedResponseType(module.type);
13
17
 
14
- if (
15
- validResponse &&
16
- module.headers.get("Content-Type") !== "application/wasm"
17
- ) {
18
+ if (validResponse && module.headers.get("Content-Type") !== "application/wasm") {
18
19
  console.warn(
19
20
  "`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
21
  e,
@@ -49,7 +50,7 @@ async function load(module, imports) {
49
50
  }
50
51
 
51
52
  function finalize_init(instance, module) {
52
- wasm = instance.exports, wasmModule = module;
53
+ ((wasm = instance.exports), (wasmModule = module));
53
54
  wasm._initialize();
54
55
  return wasm;
55
56
  }