Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:

strategy:
matrix:
node-version: [18, 20, 22]
node-version: [22, 24]

steps:
- uses: actions/checkout@v4
Expand All @@ -24,5 +24,11 @@ jobs:
cache: npm

- run: npm ci
- run: npm run build
- run: npm test
- run: npm run build:release

- name: Upload build artifacts
if: always() && matrix.node-version == 22
uses: actions/upload-artifact@v4
with:
name: build-reports
path: build/
53 changes: 53 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Publish to npm

on:
workflow_dispatch:

permissions:
contents: write
id-token: write

jobs:
publish:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Use Node.js 22
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
registry-url: https://registry.npmjs.org

- run: npm ci

- name: Compute version
id: version
run: |
BASE=$(node -p "const p = require('./package.json'); p.version.split('.').slice(0,2).join('.')")
VERSION="${BASE}.${{ github.run_number }}"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "tag=v${VERSION}" >> "$GITHUB_OUTPUT"
echo "Publishing version: ${VERSION}"

- name: Set version
run: npm version ${{ steps.version.outputs.version }} --no-git-tag-version

- run: npm run build:release

- name: Publish
run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- name: Create tag and release
env:
GH_TOKEN: ${{ github.token }}
run: |
git tag ${{ steps.version.outputs.tag }}
git push origin ${{ steps.version.outputs.tag }}
gh release create ${{ steps.version.outputs.tag }} \
--title "${{ steps.version.outputs.tag }}" \
--generate-notes
29 changes: 21 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,20 @@ TypeScript library for programmatically generating WebAssembly modules. Build WA
## Features

- Fluent builder pattern for constructing WASM modules
- Full instruction set — arithmetic, control flow, memory, tables, globals
- i32, i64, f32, f64 value types with BigInt support for i64
- **531 instructions** — arithmetic, control flow, memory, tables, globals, SIMD, atomics, exception handling
- **Target system** — `mvp`, `2.0`, `3.0`, `latest` with automatic feature gating
- i32, i64, f32, f64, v128 value types with BigInt support for i64
- **128-bit SIMD** — 236 vector instructions + 20 relaxed SIMD
- **Threads & atomics** — shared memory, 67 atomic operations
- **Exception handling** — tags, throw, try/catch/rethrow
- **Memory64** — 64-bit addressed memory
- Tail calls, multi-value returns, bulk memory, reference types
- Function imports/exports with host interop
- Memory and table management with import/export
- WAT text format output via `TextModuleWriter`
- WAT text format parsing via `parseWat()`
- WAT text format output and parsing
- Binary reader for inspecting compiled modules
- Compile-time verification (control flow + operand stack)
- Debug name section generation
- Data-driven — opcodes generated from `generator/opcodes.json`
- Zero production dependencies

## Install
Expand Down Expand Up @@ -53,6 +58,8 @@ The entry point for building a module. Create an instance, define functions/memo

```typescript
const mod = new ModuleBuilder('myModule', {
target: 'latest', // 'mvp' | '2.0' | '3.0' | 'latest'
features: [], // additional features beyond target
generateNameSection: true,
disableVerification: false,
});
Expand Down Expand Up @@ -120,10 +127,16 @@ const instance = await mod.instantiate({
### Memory

```typescript
const mem = mod.defineMemory(1, 4); // 1 page initial, 4 max (64KB per page)
const mem = mod.defineMemory(1, 4); // 1 page initial, 4 max (64KB per page)
mod.exportMemory(mem, 'memory');

// Or import memory
// Shared memory (for threads/atomics — requires maximum size)
const shared = mod.defineMemory(1, 10, true); // shared = true

// 64-bit addressed memory
const mem64 = mod.defineMemory(1, 100, false, true); // memory64 = true

// Import memory
mod.importMemory('env', 'mem', 1, 4);
```

Expand Down Expand Up @@ -152,7 +165,7 @@ See the [API Reference](docs/api.md) for complete documentation.

## Playground

Try webasmjs in the browser with the [interactive playground](https://devnamedzed.github.io/webasmjs/). It includes examples for arithmetic, control flow, memory, tables, imports, floating point, i64/BigInt, algorithms, and WAT parsing.
Try webasmjs in the browser with the [interactive playground](https://devnamedzed.github.io/webasmjs/). It includes 40+ examples covering arithmetic, control flow, memory, tables, imports, floating point, i64/BigInt, SIMD, algorithms, WAT parsing, and post-MVP features.

To run the playground locally:

Expand Down
91 changes: 89 additions & 2 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ new ModuleBuilder(name: string, options?: ModuleBuilderOptions)
|--------|------|---------|-------------|
| `generateNameSection` | `boolean` | `true` | Include debug name section in output |
| `disableVerification` | `boolean` | `false` | Skip control flow and operand stack verification |
| `target` | `WasmTarget` | `'latest'` | WebAssembly target: `'mvp'`, `'2.0'`, `'3.0'`, or `'latest'` |
| `features` | `WasmFeature[]` | `[]` | Additional feature flags beyond those included by the target |

### Methods

Expand Down Expand Up @@ -49,7 +51,7 @@ importFunction(
): ImportBuilder

// Import memory
importMemory(module: string, name: string, initial: number, maximum?: number): void
importMemory(module: string, name: string, initial: number, maximum?: number, shared?: boolean): ImportBuilder

// Import a table
importTable(
Expand All @@ -69,6 +71,13 @@ importGlobal(
): ImportBuilder
```

#### Tags

```typescript
// Define an exception tag
defineTag(parameters: ValueType[]): TagBuilder
```

#### Exports

```typescript
Expand All @@ -81,7 +90,7 @@ exportGlobal(global: GlobalBuilder, name: string): void
#### Memory

```typescript
defineMemory(initial: number, maximum?: number): MemoryBuilder
defineMemory(initial: number, maximum?: number, shared?: boolean, memory64?: boolean): MemoryBuilder
defineData(data: Uint8Array, offset: number): DataSegmentBuilder
```

Expand All @@ -96,6 +105,13 @@ defineTableSegment(
): ElementSegmentBuilder
```

#### Passive Element Segments

```typescript
// Define a passive element segment (for use with table.init)
definePassiveElementSegment(elements: FunctionBuilder[]): ElementSegmentBuilder
```

#### Globals

```typescript
Expand All @@ -121,6 +137,13 @@ instantiate(imports?: WebAssembly.Imports): Promise<WebAssembly.WebAssemblyInsta
toString(): string
```

#### Feature Checking

```typescript
// Check if a feature is enabled for this module
hasFeature(feature: WasmFeature): boolean
```

---

## FunctionBuilder
Expand Down Expand Up @@ -281,6 +304,50 @@ select(): void
nop(): void
```

### Tail Calls

```typescript
return_call(target: FunctionBuilder | ImportBuilder): void
return_call_indirect(funcType: FuncTypeBuilder): void
```

### Atomic Operations

```typescript
// Load/store (alignment and offset immediates)
atomic_load_i32(align: number, offset: number): void
atomic_load_i64(align: number, offset: number): void
atomic_store_i32(align: number, offset: number): void
atomic_store_i64(align: number, offset: number): void

// Read-modify-write
atomic_rmw_add_i32(align: number, offset: number): void
atomic_rmw_sub_i32(align: number, offset: number): void
atomic_rmw_and_i32(align: number, offset: number): void
atomic_rmw_or_i32(align: number, offset: number): void
atomic_rmw_xor_i32(align: number, offset: number): void
atomic_rmw_xchg_i32(align: number, offset: number): void
atomic_rmw_cmpxchg_i32(align: number, offset: number): void
// Same patterns for i64 variants

// Synchronization
atomic_fence(flags: number): void
atomic_notify(align: number, offset: number): void
atomic_wait32(align: number, offset: number): void
atomic_wait64(align: number, offset: number): void
```

### Exception Handling

```typescript
throw(tagIndex: number): void
try(blockType: BlockType): void
catch(tagIndex: number): void
catch_all(): void
rethrow(depth: number): void
delegate(depth: number): void
```

---

## GlobalBuilder
Expand Down Expand Up @@ -378,6 +445,7 @@ ValueType.Int32 // i32
ValueType.Int64 // i64
ValueType.Float32 // f32
ValueType.Float64 // f64
ValueType.V128 // v128 (128-bit SIMD vector)
```

### BlockType
Expand All @@ -388,6 +456,7 @@ BlockType.Int32 // block produces an i32
BlockType.Int64 // block produces an i64
BlockType.Float32 // block produces an f32
BlockType.Float64 // block produces an f64
BlockType.V128 // block produces a v128
```

### ElementType
Expand All @@ -404,3 +473,21 @@ ExternalKind.Table
ExternalKind.Memory
ExternalKind.Global
```

### WasmTarget

```typescript
'mvp' // WebAssembly 1.0 — no extensions
'2.0' // WebAssembly 2.0 — widely deployed post-MVP features
'3.0' // WebAssembly 3.0 — all standardized features
'latest' // Everything in 3.0 + newly standardized extensions (default)
```

### WasmFeature

```typescript
'sign-extend' | 'sat-trunc' | 'bulk-memory' | 'reference-types' | 'simd'
| 'multi-value' | 'mutable-globals' | 'tail-call' | 'extended-const'
| 'threads' | 'exception-handling' | 'multi-memory' | 'multi-table'
| 'relaxed-simd' | 'memory64' | 'gc'
```
Loading