# Core API reference

> Exported wakaru-core functions (decompile, unpack, unpack_files, unpack_raw, trace_rules), DecompileOptions fields, DceMode, UnpackOutput warnings, and RewriteLevel defaults.

- 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

- `crates/core/src/lib.rs`
- `crates/core/src/driver/types.rs`
- `crates/core/src/driver.rs`
- `crates/core/src/rules/mod.rs`

---

---
title: Core API reference
description: Exported wakaru-core functions (decompile, unpack, unpack_files, unpack_raw, trace_rules), DecompileOptions fields, DceMode, UnpackOutput warnings, and RewriteLevel defaults.
---

The `wakaru-core` crate (`wakaru_core` in Rust) is the programmatic entry point for Wakaru. It exposes single-file decompilation, bundle unpacking, raw extraction, and rule-pipeline tracing. All primary functions return `anyhow::Result` and share configuration through `DecompileOptions`.

Add the dependency from the workspace root:

```toml
[dependencies]
wakaru-core = { path = "crates/core" }
```

## Entry points

Wakaru exposes five driver functions for the main workflows. Each takes JavaScript source (or structured inputs) plus `DecompileOptions`, and returns typed output with optional warnings.

| Function | Signature | Purpose |
| --- | --- | --- |
| `decompile` | `(&str, DecompileOptions) -> Result<DecompileOutput>` | Parse one file, run the full rule pipeline, emit code |
| `unpack` | `(&str, DecompileOptions) -> Result<UnpackOutput>` | Detect and unpack a bundle; decompile extracted modules |
| `unpack_files` | `(Vec<UnpackInput>, DecompileOptions) -> Result<UnpackOutput>` | Multi-file unpack (entry + chunks, or directory scan results) |
| `unpack_raw` | `(&str, &DecompileOptions) -> Result<UnpackOutput>` | Extract modules without the decompile rule pipeline |
| `unpack_files_raw` | `(Vec<UnpackInput>, &DecompileOptions) -> Result<UnpackOutput>` | Multi-file raw extraction |
| `trace_rules` | `(&str, DecompileOptions, RuleTraceOptions) -> Result<Vec<RuleTraceEvent>>` | Per-rule before/after snapshots for single-file debugging |

### `decompile`

Runs the complete single-file pipeline: parse (with recovery), resolver marks, staged rule application, optional source-map rename passes, fixer, and emit.

```rust
use wakaru_core::{decompile, DecompileOptions};

let output = decompile(
    source,
    DecompileOptions {
        filename: "input.js".into(),
        ..Default::default()
    },
)?;
println!("{}", output.code);
```

When `DecompileOptions::sourcemap` is set, Wakaru runs `ImportDedup` and source-map-driven identifier rename after the main rule pipeline. When `emit_source_map` is set, `DecompileOutput::source_map` contains v3 source map JSON mapping decompiled output back to the input.

### `unpack`

Detects a structural bundle format, optionally applies scope-hoist splitting, then decompiles every extracted module in parallel (two-phase unpack with a cross-module facts barrier). Behavior when no bundle is detected:

- **`heuristic_split: false`** — falls back to `decompile`, returning a single module named `module.js`.
- **`heuristic_split: true`** — attempts scope-hoisted splitting; on success runs full unpack, otherwise falls back to `decompile`.

`UnpackOutput::detected_formats` records which `BundleFormat` variants were recognized (for example `webpack5`, `esbuild`, `scope-hoisted`).

### `unpack_files`

Accepts multiple `UnpackInput { filename, source }` values. A single input delegates to `unpack`. Multiple inputs merge detected modules, run cross-chunk numeric rewrite planning, and execute the parallel Phase 2 decompile pipeline.

Returns `Err` when `inputs` is empty or no modules could be extracted.

### `unpack_raw` and `unpack_files_raw`

Skip the decompile rule pipeline and cross-module fact collection. Output is detector-specific extraction plus bundler-coupled normalization only.

- No `source_maps` are emitted (always empty).
- Heuristic scope-hoisted fallback may run narrow runnable normalization; failures produce `raw_normalization_failed` warnings when `diagnostics` is enabled.
- When no bundle is detected, `unpack_raw` returns the input unchanged as a single `module.js` entry.

Use raw extraction when you need structural module boundaries without readability rewrites. Use `unpack` when you want decompiled, idiomatic source.

### `trace_rules`

Records per-rule rendered output for bisecting single-file regressions. Rejects bundle inputs with an explicit error — use `decompile` or `unpack` for bundles.

Pair with `format_trace_events` to render a git-style unified diff log:

```rust
use wakaru_core::{
    trace_rules, format_trace_events, DecompileOptions, RuleTraceOptions,
};

let events = trace_rules(
    source,
    DecompileOptions { filename: "input.js".into(), ..Default::default() },
    RuleTraceOptions {
        start_from: Some("un_esm".into()),
        stop_after: None,
        only_changed: true,
    },
)?;
println!("{}", format_trace_events(&events));
```

<ParamField body="start_from" type="Option<String>">
First rule name to trace. Must appear in `rule_names()`. When omitted, tracing starts at the beginning of the pipeline.
</ParamField>

<ParamField body="stop_after" type="Option<String>">
Last rule name to trace. When omitted, tracing runs through the end of the pipeline.
</ParamField>

<ParamField body="only_changed" type="bool" default="true">
When `true`, only emit events whose rendered output changed. Set `false` to include unchanged rules.
</ParamField>

## `DecompileOptions`

Shared configuration for all driver entry points.

<ParamField body="filename" type="String" default='""'>
Logical filename for parse diagnostics, source-map paths, and provenance-based filename recovery during unpack.
</ParamField>

<ParamField body="sourcemap" type="Option<Vec<u8>>" default="None">
Raw bytes of a v3 source map. Enables import deduplication and source-map-driven identifier rename. Multi-file unpack with source maps requires reparsing in Phase 2.
</ParamField>

<ParamField body="dce_mode" type="DceMode" default="Off">
Controls late dead-code elimination (`DeadImports`, `DeadDecls`) and dead helper-module elimination during unpack.
</ParamField>

<ParamField body="level" type="RewriteLevel" default="Standard">
How aggressively rules recover likely original source patterns. Gates filename recovery, dead-module elimination, nested scope splitting, and several rule-specific heuristics.
</ParamField>

<ParamField body="heuristic_split" type="bool" default="false">
When `true`, attempt heuristic splitting of top-level scope-hoisted bundles when no structural bundle is detected. At `Aggressive` level, also retry scope-hoist splitting inside modules extracted by a structural detector.
</ParamField>

<ParamField body="diagnostics" type="bool" default="false">
Run post-transform checks: input parse recovery, TDZ violations, duplicate declarations, and output parse verification. Results appear in `warnings`; no warnings are collected when `false`.
</ParamField>

<ParamField body="emit_source_map" type="bool" default="false">
Generate v3 source maps mapping decompiled output to the input. Populates `DecompileOutput::source_map` or `UnpackOutput::source_maps`.
</ParamField>

### API defaults vs CLI and WASM

The Rust API defaults are conservative. Edge integrations often override fields:

| Field | `DecompileOptions::default()` | CLI | WASM `decompile` | WASM `unpack` |
| --- | --- | --- | --- | --- |
| `dce_mode` | `Off` | `TransformOnly` (`Full` with `--dce`) | `TransformOnly` | `Off` (via `..Default::default()`) |
| `level` | `Standard` | `standard` | parsed from arg | parsed from arg |
| `heuristic_split` | `false` | `true` for `--unpack` / `--unpack=auto`; `false` for `--unpack=strict` | `false` | `true` |
| `diagnostics` | `false` | `--diagnostics` flag | arg, default `false` | arg, default `false` |

When building integrations, set fields explicitly rather than relying on `Default` if you want CLI-equivalent behavior.

## `DceMode`

Controls dead-code elimination in the rule pipeline and unpack cleanup.

| Variant | Behavior |
| --- | --- |
| `Off` | No dead-code cleanup |
| `TransformOnly` | Remove only transform-induced dead code; pre-existing dead input code is preserved |
| `Full` | Full reachability sweep — remove all unreachable code |

`DceMode::is_enabled()` returns `true` for `TransformOnly` and `Full`. During unpack, dead helper-module elimination requires both `dce_mode.is_enabled()` and `level` at least `Standard`.

## `RewriteLevel`

```rust
pub enum RewriteLevel {
    Minimal,
    Standard,  // #[default]
    Aggressive,
}
```

`RewriteLevel` is `PartialOrd`: higher levels enable more speculative recovery. Parse from strings with `RewriteLevel::from_str_or_default(level)` — accepts `"minimal"`, `"standard"`, `"aggressive"`; any other value falls back to `Standard`.

Each level maps to `RewriteAssumptions` via `RewriteAssumptions::from_level`:

| Level | `no_document_all` | `pure_getters` | `stable_builtins` |
| --- | --- | --- | --- |
| `Minimal` | `false` | `false` | `false` |
| `Standard` | `true` | `false` | `false` |
| `Aggressive` | `true` | `true` | `true` |

`RewritePolicy::from_level` bundles the level with its assumptions for rules that need both.

## Return types

### `DecompileOutput`

<ResponseField name="code" type="String">
Decompiled JavaScript source.
</ResponseField>

<ResponseField name="warnings" type="Vec<UnpackWarning>">
Non-fatal warnings from diagnostics and parse recovery.
</ResponseField>

<ResponseField name="source_map" type="Option<String>">
v3 source map JSON when `emit_source_map` is set.
</ResponseField>

`DecompileOutput::has_errors()` returns `true` when any warning has `kind.is_error()`.

### `UnpackOutput`

<ResponseField name="modules" type="Vec<(String, String)>">
Extracted modules as `(filename, code)` pairs.
</ResponseField>

<ResponseField name="warnings" type="Vec<UnpackWarning>">
Per-module warnings accumulated across extraction, fact collection, and decompile.
</ResponseField>

<ResponseField name="detected_formats" type="Vec<BundleFormat>">
Bundle formats recognized during detection (`webpack4`, `webpack5`, `browserify`, `systemjs`, `esbuild`, `amd`, `scope-hoisted`).
</ResponseField>

<ResponseField name="source_maps" type="Vec<(String, String)>">
Per-module source map JSON when `emit_source_map` is set.
</ResponseField>

`UnpackOutput::has_errors()` mirrors `DecompileOutput::has_errors()`.

### `UnpackInput`

```rust
pub struct UnpackInput {
    pub filename: String,
    pub source: String,
}
```

Used by `unpack_files` and `unpack_files_raw` for multi-file operations.

## Warnings

Warnings are non-fatal. Operations return `Ok` with warnings attached unless a hard error (parse failure, I/O, etc.) occurs.

```rust
pub struct UnpackWarning {
    pub filename: String,
    pub kind: UnpackWarningKind,
    pub message: String,
}
```

### Warning kinds

| `UnpackWarningKind` | `as_str()` | `is_error()` | Typical cause |
| --- | --- | --- | --- |
| `RawNormalizationFailed` | `raw_normalization_failed` | yes | Raw heuristic normalization failed; unparsed code preserved |
| `FactCollectionParseFailed` | `fact_collection_parse_failed` | yes | Module parse failed during Phase 1 fact collection |
| `DecompileFailed` | `decompile_failed` | yes | Per-module decompile error during unpack |
| `InputParseRecovered` | `input_parse_recovered` | no (diagnostic) | Parser recovered from input syntax errors |
| `TdzViolation` | `tdz_violation` | no (diagnostic) | Lexical use-before-declaration detected |
| `DuplicateDeclaration` | `duplicate_declaration` | yes | Duplicate lexical binding in output |
| `ImportCycle` | `import_cycle` | no (diagnostic) | Circular import dependency detected |
| `OutputParseRecovered` | `output_parse_recovered` | yes | Output failed strict parse but recovered |
| `OutputParseFailed` | `output_parse_failed` | yes | Output is not parseable JavaScript |

`UnpackWarningKind::is_diagnostic()` is `true` for `InputParseRecovered`, `TdzViolation`, and `ImportCycle`. Diagnostic warnings signal potential transform issues but do not indicate data loss. `is_error()` returns `!is_diagnostic()`.

For machine-readable output, the CLI maps warnings to JSON with `kind`, `is_error`, `filename`, and `message` fields via `JsonWarning::from_core`.

## Additional exports

Beyond the driver entry points, `wakaru_core` re-exports utilities useful for custom integrations:

- **Rules** — `apply_rules`, `rule_names`, `rule_descriptors`, `RulePipelineOptions`, `RuleStage`, `RewritePolicy`
- **Facts** — `ModuleFacts`, `ModuleFactsMap`, `collect_module_facts`, import/export fact types
- **Source maps** — `parse_sourcemap`, `extract_source_entries`, `resolve_source_path`
- **Diagnostics** — `check_tdz`, `TdzViolation`
- **Unpacker** — `BundleFormat`, `unpack_webpack4`, `scope_hoist`, `unpack_webpack4_raw`
- **I/O helpers** — `normalize`, `is_detected_unpack_input`, `deduplicate_path`, `safe_relative_module_path`

Low-level rule development typically imports individual rule types from `wakaru_core::rules`.

## Example: unpack with diagnostics

```rust
use wakaru_core::{
    unpack, DecompileOptions, DceMode, RewriteLevel,
};

let output = unpack(
    bundle_source,
    DecompileOptions {
        filename: "dist/bundle.js".into(),
        level: RewriteLevel::Standard,
        dce_mode: DceMode::TransformOnly,
        heuristic_split: true,
        diagnostics: true,
        ..Default::default()
    },
)?;

for (filename, code) in &output.modules {
    std::fs::write(format!("out/{filename}"), code)?;
}

if output.has_errors() {
    for w in &output.warnings {
        if w.kind.is_error() {
            eprintln!("[{}] {}: {}", w.kind.as_str(), w.filename, w.message);
        }
    }
}
```

## Related pages

<CardGroup>
<Card title="Decompile pipeline" href="/decompile-pipeline">
Single-file parse → rules → fixer → emit flow and `unresolved_mark` scope gating.
</Card>
<Card title="Rewrite levels and assumptions" href="/rewrite-levels-and-assumptions">
How `RewriteLevel` and `DceMode` affect rule behavior and CLI flags.
</Card>
<Card title="Bundle formats and unpacking" href="/bundle-formats-and-unpacking">
Detection order, `BundleFormat` variants, and raw vs full unpack semantics.
</Card>
<Card title="Trace the rule pipeline" href="/trace-rule-pipeline">
Using `trace_rules` and `format_trace_events` for regression bisection.
</Card>
<Card title="JSON output and CI" href="/json-output-and-ci">
Machine-readable warning schemas with `kind` and `is_error` for automation.
</Card>
<Card title="WASM API reference" href="/wasm-api-reference">
Browser bindings that wrap the same core types with JSON result shapes.
</Card>
</CardGroup>
