Skip to content

Commit 6d137e9

Browse files
cursoragentskarim
andcommitted
Add documentation for parsing Swift files with SwiftSyntax via WASI
Co-authored-by: sameenkarim <[email protected]>
1 parent cc177e4 commit 6d137e9

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed

README.md

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,133 @@ See [schema.json](schema.json) for a JSON Schema of the output.
464464
```
465465
</details>
466466

467+
## Parsing Swift files with SwiftSyntax via WebAssembly (WASI)
468+
469+
If your project includes Swift code, you can parse it with full-fidelity **SwiftSyntax** instead of brittle regular expressions. Thanks to the official Swift WASI SDK this works completely inside a Node.js environment—no native Swift toolchain is required at runtime.
470+
471+
Below is a minimal, end-to-end recipe you can drop into your build docs or copy-paste into a README. It turns a tiny SwiftSyntax-based CLI into a `.wasm` module and shows how to execute it from JavaScript.
472+
473+
---
474+
475+
### 1. Set up a Swift toolchain that can target WASM
476+
477+
1. Install the latest Swift **development snapshot** *and* the matching **Swift SDK for WASI** (one-liner provided on the [Swift downloads page](https://www.swift.org/download/)).
478+
2. Verify the SDK ID:
479+
480+
```sh
481+
swift sdk list # e.g. swift-6.2-20250720_wasm
482+
```
483+
3. Whenever you build, pass `--swift-sdk <id>` (or `--triple wasm32-unknown-wasi` if you prefer). The [official guide](https://www.swift.org/getting-started) shows the exact commands.
484+
485+
---
486+
487+
### 2. Create a tiny SwiftSyntax wrapper
488+
489+
```sh
490+
mkdir SwiftSyntaxWasm && cd SwiftSyntaxWasm
491+
swift package init --type executable
492+
```
493+
494+
`Package.swift` (only the interesting bits):
495+
496+
```swift
497+
// swift-tools-version: 6.0
498+
import PackageDescription
499+
500+
let package = Package(
501+
name: "SwiftSyntaxWasm",
502+
dependencies: [
503+
.package(url: "https://github.com/apple/swift-syntax.git", from: "602.0.0")
504+
],
505+
targets: [
506+
.executableTarget(
507+
name: "SwiftSyntaxWasm",
508+
dependencies: [
509+
.product(name: "SwiftParser", package: "swift-syntax")
510+
])
511+
]
512+
)
513+
```
514+
515+
`Sources/SwiftSyntaxWasm/main.swift`:
516+
517+
```swift
518+
import Foundation
519+
import SwiftParser // Light-weight entry point
520+
import SwiftSyntax
521+
522+
@main
523+
struct CLI {
524+
static func main() throws {
525+
guard CommandLine.arguments.count > 1 else {
526+
fputs("usage: <tool> file.swift\n", stderr)
527+
exit(1)
528+
}
529+
let url = URL(fileURLWithPath: CommandLine.arguments[1])
530+
let source = try String(contentsOf: url)
531+
let tree = Parser.parse(source: source)
532+
// TODO: Replace with a custom visitor that emits compact JSON.
533+
print(tree.description)
534+
}
535+
}
536+
```
537+
538+
---
539+
540+
### 3. Compile to WASM
541+
542+
```sh
543+
swift build -c release --swift-sdk swift-6.2-20250720_wasm
544+
# result: .build/wasm32-unknown-wasi/release/SwiftSyntaxWasm.wasm
545+
```
546+
547+
The binary will be large (15-25 MB). If size matters, rebuild with the *Embedded Swift* SDK variant or post-process with `wasm-opt -Oz`.
548+
549+
---
550+
551+
### 4. Call the module from Node
552+
553+
Add a tiny launcher—`runner.js`:
554+
555+
```js
556+
import { readFile } from "node:fs/promises";
557+
import { WASI } from "node:wasi";
558+
import { argv, env } from "node:process";
559+
560+
const wasi = new WASI({
561+
args: ["SwiftSyntaxWasm.wasm", argv[2]], // pass path to .swift file
562+
env,
563+
preopens: { "/": process.cwd() } // expose CWD to WASI FS
564+
});
565+
566+
const wasmBytes = await readFile("./SwiftSyntaxWasm.wasm");
567+
const module = await WebAssembly.compile(wasmBytes);
568+
const instance = await WebAssembly.instantiate(module, wasi.getImportObject());
569+
570+
wasi.start(instance); // prints AST (or your JSON) to stdout
571+
```
572+
573+
Run it:
574+
575+
```sh
576+
node runner.js ./Example.swift > ast.json
577+
```
578+
579+
---
580+
581+
### 5. Consume from your NPM package
582+
583+
Wrap the call above in a helper (e.g. `parseSwift(sourcePath)`), capture `stdout`, and feed the JSON into your existing JS analysis pipeline—exactly like we already do with Pyodide or the Ruby/Python/Go WASM binaries.
584+
585+
---
586+
587+
#### Why this works
588+
* **SwiftSyntax** itself is pure Swift → the Swift WASI SDK compiles it without native Apple frameworks.
589+
* **WASI** provides a portable POSIX-ish layer, so the wasm module runs unchanged on Node, Wasmer, or Wasmtime.
590+
* The approach keeps Swift-side parsing isolated and lets your JS orchestrate everything else.
591+
592+
> **TL;DR** Install the Swift WASI SDK, write a ~30-line SwiftSyntax CLI, `swift build --swift-sdk …`, then load the resulting `.wasm` through Node’s `wasi` API and capture its output.
593+
467594

468595
## Contribute
469596
We're actively improving this package. Found a bug? Have a feature request? Open an issue or submit a pull request!

0 commit comments

Comments
 (0)