# Overview

> What Wakaru decompiles and unpacks, the three-crate workspace layout (core, CLI, WASM), primary entry points, and the shortest path from input JavaScript to readable output.

- Repository: pionxzh/wakaru
- GitHub: https://github.com/pionxzh/wakaru
- Human docs: https://grok-wiki.com/public/docs/pionxzh-wakaru-77a438a6cc6b
- Complete Markdown: https://grok-wiki.com/public/docs/pionxzh-wakaru-77a438a6cc6b/llms-full.txt

## Source Files

- `README.md`
- `docs/architecture.md`
- `crates/core/src/lib.rs`
- `crates/core/src/driver.rs`
- `crates/cli/src/main.rs`
- `crates/wasm/src/lib.rs`

---

---
title: "Overview"
description: "What Wakaru decompiles and unpacks, the three-crate workspace layout (core, CLI, WASM), primary entry points, and the shortest path from input JavaScript to readable output."
---

Wakaru is a Rust/SWC-based JavaScript decompiler and bundle splitter: `wakaru-core` owns parsing, format detection, ~60 AST rewrite rules, and emission; `wakaru-cli` and `wakaru-wasm` are thin frontends over the same `decompile` and `unpack` APIs.

## What Wakaru transforms

Production JavaScript often passes through three layers before it reaches Wakaru:

| Layer | Typical tools | What Wakaru reverses |
|-------|---------------|----------------------|
| Bundlers | webpack 4/5, Browserify, SystemJS, esbuild, Bun, Rollup/Vite | Splits collapsed modules, removes runtime wrappers, recovers `import`/`export` |
| Transpilers | Babel, TypeScript/tslib, SWC | Unwraps helper functions (`__extends`, `__awaiter`, tslib imports, etc.) and restores modern syntax |
| Minifiers | Terser and bundler-integrated minification | Expands booleans, template literals, control flow, and identifier patterns |

Wakaru handles all three in one pass. Feed it a minified module or a production bundle; it returns readable, modern ESNext-shaped JavaScript.

## Two operations

| Operation | Input | Output | Core API |
|-----------|-------|--------|----------|
| **Decompile** | One `.js`/`.mjs`/`.cjs` file (or stdin) | One readable file (or stdout) | `decompile(source, DecompileOptions)` |
| **Unpack + decompile** | One or more bundle/chunk files, or a directory scan | Many module files under an output directory | `unpack`, `unpack_files`, `unpack_raw`, `unpack_files_raw` |

Unpackers detect the bundle format and extract raw module code strings. The driver then runs the decompile rule pipeline on each module. With `--raw`, extraction stops before readability rules run.

<Note>
Directory inputs require `--unpack`. Wakaru recursively scans `.js`, `.mjs`, and `.cjs` files, skips hidden paths and `node_modules`, and includes only files detected as bundles or chunks. Explicit file inputs fall back to single-file decompile when no bundle format matches.
</Note>

## Supported bundle formats

Detection runs in fixed order; first match wins. `BundleFormat` variants:

| Order | Format | Identifier |
|-------|--------|------------|
| 1 | webpack 5 entry/runtime | `webpack5` |
| 2 | webpack 4 | `webpack4` |
| 3 | webpack 5 JSONP chunk | `webpack5` |
| 4 | Browserify standalone | `browserify` |
| 5 | SystemJS `System.register` | `systemjs` |
| 6 | esbuild / Bun (CJS helpers) | `esbuild` |
| 7 | AMD `define` | `amd` |
| — | Scope-hoisted ESM (heuristic, `--unpack=auto`) | `scope-hoisted` |

Pure ESM scope-hoisted output without `__export` or `__commonJS` markers may not structurally unpack; it falls through to single-file decompile unless heuristic splitting is enabled.

## Workspace layout

The Cargo workspace (`members = ["crates/*"]`) centers on three publishable surfaces plus a shared formatter:

:::files
crates/
  core/          # wakaru-core — parser, unpackers, rules, driver, facts
    src/
      lib.rs           — public API re-exports
      driver/          — decompile, unpack, trace orchestration
      rules/           — ~60 VisitMut transformation rules
      unpacker/        — per-format bundle splitters
      facts.rs         — cross-module import/export facts
  cli/           # wakaru-cli — `wakaru` binary (clap + rayon I/O)
    src/main.rs
  wasm/          # wakaru-wasm — wasm-bindgen bindings for browser playground
    src/lib.rs
  formatter/     # wakaru-formatter — optional oxc post-format pass (CLI + WASM)
:::

| Crate | Package | Role |
|-------|---------|------|
| `core` | `wakaru-core` | All transformation logic; consumed by CLI, WASM, and tests |
| `cli` | `wakaru-cli` / `@wakaru/cli` on npm | Command-line entry, file I/O, JSON output, profiling |
| `wasm` | `wakaru-wasm` | Browser bindings: `decompile`, `unpack`, `ruleNames` |
| `formatter` | `wakaru-formatter` | Optional `--formatter` pass after decompilation |

## Architecture

```mermaid
flowchart TB
    subgraph inputs [Inputs]
        SF[single file]
        BD[bundle / chunk / directory]
    end

    subgraph cli_wasm [Frontends]
        CLI[wakaru-cli]
        WASM[wakaru-wasm]
    end

    subgraph core [wakaru-core]
        DRV[driver]
        UNP[unpacker]
        RUL[rules pipeline]
        FAC[facts + cross-module pass]
    end

    SF --> CLI
    BD --> CLI
    SF --> WASM
    BD --> WASM
    CLI --> DRV
    WASM --> DRV

    BD --> UNP
    UNP -->|module strings| DRV
    SF --> DRV

    DRV -->|parse → resolver → rules| RUL
    RUL -->|unpack only| FAC
    FAC --> RUL
    RUL -->|fixer → emit| OUT[readable JS]
```

**Single-file decompile** (`driver/single_file.rs`):

```
parse → resolver(unresolved_mark) → apply_rules → [optional source-map rename] → fixer → print
```

**Unpack + decompile** (`driver/unpack.rs`) adds a two-phase parallel pipeline after `unpack_bundle`:

1. **Phase 1** — parse each module, run rules through `UnEsm`, collect cross-module facts.
2. **Phase 2** — re-parse, cross-module late pass (namespace decomposition, re-export consolidation), run remaining rules, emit.

Phase 1 and Phase 2 each parse modules independently so `SyntaxContext` stays continuous within the emitted pipeline.

## Primary entry points

### CLI (`wakaru`)

The `wakaru` binary in `crates/cli/src/main.rs` routes three top-level paths:

| Path | Trigger | Behavior |
|------|---------|----------|
| Default | `wakaru input.js` | Single-file decompile |
| Unpack | `wakaru bundle.js --unpack -o out/` | Bundle split + per-module decompile |
| Subcommands | `wakaru extract`, `wakaru debug trace` | Source-map extraction; rule-pipeline debugging |

<ParamField body="--unpack" type="auto | strict">
`auto` (default): structural detection plus heuristic scope-hoisted fallback. `strict`: structural detectors only, no heuristic fallback.
</ParamField>

<ParamField body="--level" type="minimal | standard | aggressive" default="standard">
Controls rewrite aggressiveness. Rules gate risky subpatterns internally rather than skipping entire rules.
</ParamField>

<ParamField body="--raw" type="flag">
With `--unpack`, write extractor output before the decompile rule pipeline.
</ParamField>

### Core API (`wakaru-core`)

Public exports from `crates/core/src/lib.rs`:

<ResponseField name="decompile" type="(source, DecompileOptions) → DecompileOutput">
Single-file transformation. Options include `sourcemap`, `dce_mode`, `level`, `diagnostics`, `emit_source_map`.
</ResponseField>

<ResponseField name="unpack" type="(source, DecompileOptions) → UnpackOutput">
Detect bundle format, split modules, run two-phase decompile pipeline.
</ResponseField>

<ResponseField name="unpack_files" type="(Vec&lt;UnpackInput&gt;, DecompileOptions) → UnpackOutput">
Multi-source unpack (entry + chunks). Merges module sets and stabilizes webpack numeric IDs across files.
</ResponseField>

<ResponseField name="trace_rules" type="(source, options, RuleTraceOptions) → Vec&lt;RuleTraceEvent&gt;">
Per-rule before/after snapshots for single-file bisection.
</ResponseField>

### WASM API (`wakaru-wasm`)

`wasm_bindgen` exports mirror the core driver:

- `decompile(source, level?, sourcemap?, diagnostics?, formatter?, emitSourceMap?)` → `WakaruDecompileResult`
- `unpack(source, level?, heuristicSplit?, diagnostics?, formatter?, emitSourceMap?)` → `WakaruUnpackResult`
- `ruleNames()` → `string[]`

These power the [online playground](https://wakaru.vercel.app/playground).

## Shortest path to readable output

<Steps>
<Step title="Install or run without install">

<CodeGroup>
```bash title="npx (no install)"
npx @wakaru/cli input.js -o output.js
```

```bash title="global npm"
npm install -g @wakaru/cli@latest
wakaru input.js -o output.js
```

```bash title="cargo (from source)"
cargo run -p wakaru-cli -- input.js -o output.js
```
</CodeGroup>

</Step>

<Step title="Decompile a single file">

```bash
wakaru input.js -o output.js
```

Without `-o`, output goes to stdout. Stdin works via pipe or `-`:

```bash
cat input.js | wakaru > output.js
```

**Verification:** stderr shows warnings (if any); output file contains expanded syntax, restored helpers, and readable identifiers at `standard` level.

</Step>

<Step title="Unpack a production bundle">

```bash
wakaru bundle.js --unpack -o out/
```

For a build output directory:

```bash
wakaru dist/ --unpack -o out/
```

**Verification:** stderr reports `detected: webpack5` (or matching format) and `total: N module(s)`. `out/` contains one file per recovered module.

</Step>

<Step title="Optional enhancements">

```bash
# Recover original names from a source map
wakaru input.js --source-map input.js.map -o output.js

# Stronger readability (may alter edge-case behavior)
wakaru input.js --level aggressive -o output.js

# Machine-readable summary for CI
wakaru bundle.js --unpack --json -o out/
```

</Step>
</Steps>

## Rule pipeline at a glance

`apply_rules` in `crates/core/src/rules/pipeline.rs` runs ~60 `VisitMut` rules in a fixed order across six stages:

1. Syntax normalization (sequences, booleans, bracket notation)
2. Transpiler helper unwrapping + module reconstruction (`UnEsm`, webpack interop)
3. Structural restoration (template literals, spread, optional chaining)
4. Complex patterns (IIFEs, classes, JSX, regenerator, async/await)
5. Modernization (`let`/`const`, arrow functions, `for..of`)
6. Cleanup (import dedup, smart inline/rename, optional dead-code removal)

Rules that match identifiers by name **must** gate on `unresolved_mark` from the SWC resolver to avoid renaming inner-scope bindings. See the decompile pipeline page for stage detail and the cross-module barrier during unpack.

<Info>
Default dead-code behavior (`DceMode::TransformOnly`) removes only transform-induced dead code. Pass `--dce` for a full reachability sweep.
</Info>

## Distribution surfaces

| Surface | Package / artifact | Typical use |
|---------|-------------------|-------------|
| npm | `@wakaru/cli` | Local CLI via `npx` or global install |
| GitHub Releases | Pre-built binaries | CI or environments without Node |
| WASM | Built from `crates/wasm` | Browser playground and JS integrations |
| Rust crate | `wakaru-core` (path dep) | Custom tooling, tests, rule development |

## Related pages

<CardGroup>
<Card title="Quickstart" href="/quickstart">
First successful runs for decompile and unpack modes with expected success signals.
</Card>
<Card title="Installation" href="/installation">
npm optional platform packages, release binaries, and Rust toolchain for source builds.
</Card>
<Card title="Decompile pipeline" href="/decompile-pipeline">
Parse, resolver marks, staged rules, source-map rename ordering, and `unresolved_mark` gating.
</Card>
<Card title="Bundle formats and unpacking" href="/bundle-formats-and-unpacking">
Detection order, raw vs full unpack, multi-file and directory scan semantics.
</Card>
<Card title="CLI reference" href="/cli-reference">
Complete `wakaru` command surface, flags, and subcommands.
</Card>
<Card title="Core API reference" href="/core-api-reference">
`DecompileOptions`, `UnpackOutput`, warning kinds, and exported driver functions.
</Card>
</CardGroup>
