# Contributing

> Fork-and-branch workflow, required cargo fmt/clippy/test checks, conventional commits, areas where contributions are most valuable, and links to architecture and testing docs.

- 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

- `CONTRIBUTING.md`
- `AGENTS.md`
- `README.md`
- `.github/workflows/rust-ci.yml`
- `docs/releasing.md`

---

---
title: "Contributing"
description: "Fork-and-branch workflow, required cargo fmt/clippy/test checks, conventional commits, areas where contributions are most valuable, and links to architecture and testing docs."
---

Wakaru is a Rust Cargo workspace with three crates — `wakaru-core` (`crates/core/`), `wakaru-cli` (`crates/cli/`), and `wakaru-wasm` (`crates/wasm/`) — where nearly all code contributions land in `wakaru-core`: `VisitMut` transformation rules under `src/rules/`, bundle unpackers under `src/unpacker/`, pipeline orchestration in `src/driver.rs`, and per-rule plus integration tests under `tests/`. Pull requests are validated by the `rust-ci` workflow (`cargo fmt --check`, `cargo clippy -- -D warnings`, `cargo nextest run --workspace --profile ci`, and `cargo test --workspace --doc`) on Ubuntu, macOS, and Windows.

## Fork-and-branch workflow

<Steps>
<Step title="Fork and branch">

Fork [pionxzh/wakaru](https://github.com/pionxzh/wakaru) and create a feature branch from `main`.

</Step>
<Step title="Verify the baseline">

From the workspace root, confirm the tree builds and tests pass:

```bash
cargo test
```

</Step>
<Step title="Implement with tests">

Add or update behavior in the relevant crate. Rule and bugfix changes require a focused unit test in `crates/core/tests/` — pipeline snapshot updates alone do not satisfy coverage for an individual rule change.

</Step>
<Step title="Run local checks">

Run the full pre-PR checklist (see [Required checks](#required-checks)).

</Step>
<Step title="Open a pull request">

Push the branch and open a PR against `main`. Use [Conventional Commits](#commit-message-format) and reference the related issue number in the commit message or PR description.

</Step>
</Steps>

<Note>
The `rust-ci` workflow ignores changes under `playground/**`, `website/**`, `*.md`, and `docs/**`. Documentation-only edits do not trigger Rust CI; code changes always do.
</Note>

## Development setup

| Requirement | Details |
|---|---|
| Rust toolchain | Stable Rust via [rustup](https://rustup.rs/) |
| Workspace root | All `cargo` commands run from the repository root |
| Optional: `cargo-insta` | `cargo install cargo-insta` for interactive snapshot review |
| Optional: faster tests | `cargo install cargo-nextest --locked` (CI uses nextest; local runs are ~25× faster than plain `cargo test` for the core suite) |

Build and exercise the CLI during development:

```bash
cargo build
cargo run -p wakaru-cli -- input.js -o output.js
cargo run -p wakaru-cli -- --unpack bundle.js -o unpacked/
cargo run -p wakaru-cli -- debug trace path/to/module.js
```

### Optional shallow git dependencies

The formatter depends on pinned OXC crates from git. On a cold Cargo cache, fetches can be slow. With nightly Cargo:

```bash
cargo +nightly fetch -Zgit=shallow-deps
```

Stable Cargo works without this step.

## Workspace layout

| Crate | Path | Role |
|---|---|---|
| `wakaru-core` | `crates/core/` | Decompile pipeline, ~60 transformation rules, unpackers, public API |
| `wakaru-cli` | `crates/cli/` | `wakaru` binary (`clap`) |
| `wakaru-wasm` | `crates/wasm/` | WASM bindings for the browser playground |

Within `wakaru-core`:

```text
crates/core/
├── src/rules/          # one file per rule; pipeline.rs holds RuleDescriptor order
├── src/unpacker/       # bundle format detection and module extraction
├── src/driver.rs       # decompile and unpack orchestration
└── tests/              # per-rule tests, pipeline integration tests, snapshot fixtures
```

## Required checks

Run these before opening a PR. CI enforces the same gates (with nextest instead of plain `cargo test`).

```bash
cargo fmt --check
cargo clippy -- -D warnings
cargo test
```

For day-to-day core development, prefer nextest and scoped clippy:

```bash
cargo nextest run -p wakaru-core
cargo nextest run --workspace
cargo clippy -p wakaru-core --all-targets -- -D warnings
```

When touching `wakaru-cli`, `wakaru-wasm`, or shared workspace code:

```bash
cargo clippy --workspace --all-targets -- -D warnings
```

### Snapshot workflow

`.cargo/config.toml` sets `INSTA_UPDATE=new`: a changed snapshot **fails** the test and writes a `.snap.new` file. CI sets `INSTA_UPDATE=no`.

1. Review the `.snap.new` diff.
2. Accept intentional changes: `cargo insta accept` (or `INSTA_UPDATE=always cargo test` for a one-off bulk accept).
3. Confirm `git status --short` shows no stale `.snap.new` files.

<Warning>
Snapshot drift that is merely different — not semantically better — is a regression. Inspect every snapshot change before accepting.
</Warning>

### Definition of done for rule changes

1. Focused rule tests for the touched behavior.
2. Pipeline integration tests:

```bash
cargo test -p wakaru-core --test noop_pipeline
cargo test -p wakaru-core --test webpack4_unpack
cargo test -p wakaru-core --test webpack4_unpack_raw
cargo test -p wakaru-core --test bundle_unpack
cargo test -p wakaru-core --test esbuild_unpack
```

3. `cargo fmt --check` and scoped or workspace `cargo clippy`.
4. Snapshot diffs reviewed; no unrelated changes in `git status --short`.

## Invariants for code changes

These constraints apply to every rule or rename contribution:

| Rule | Requirement |
|---|---|
| Unit tests | No code change ships without a corresponding unit test |
| Identifier matching | Rules matching identifiers by name must take `unresolved_mark: Mark` and gate with `id.ctxt.outer() != self.unresolved_mark` |
| Renames | Use `rename_utils::BindingRenamer` (`rename_bindings_in_module` / `rename_bindings`); never rename by `sym` alone |
| Pipeline placement | New rules register in `crates/core/src/rules/pipeline.rs` at a position that satisfies upstream dependencies (e.g. after `UnBracketNotation` for `["default"]` → `.default`; before `UnEsm` when `require()` must still exist; before the second `UnIife` pass when creating IIFEs) |
| Formatting | Run `cargo fmt --check`; limit `cargo fmt` to files you intentionally changed |

## High-value contribution areas

| Area | What helps |
|---|---|
| Real-world bundles | Samples Wakaru fails to unpack or decompile (webpack 4/5, esbuild, Bun, Browserify, SystemJS, AMD) |
| Helper detection | Missing transpiler helpers (Babel, TypeScript/tslib, SWC) or false-positive matches |
| Correctness | Semantic bugs, TDZ issues, incorrect rewrite output at any `RewriteLevel` |
| New rules | `VisitMut` rules that recover idiomatic ESNext from minified patterns |
| Unpackers | New or improved bundle-format detection in `src/unpacker/` |

The most common code contribution is adding or extending a transformation rule. That workflow is documented on the develop-rules page; pipeline ordering dependencies are listed in `docs/rule-dependency-inventory.md`.

## Bug reports

Use the GitHub **Decompiler Bug Report** issue template. Include:

| Field | Content |
|---|---|
| Input code | Minimal reproduction (playground link, gist, or inline sample) |
| Command | Full `wakaru` invocation (add `--diagnostics` when warnings help) |
| Version | Output of `wakaru --version` or npm package version |
| Expected vs actual | What output you expected and what Wakaru produced |

For quick triage from the README: input code, command run, current output, and expected output.

## Commit message format

Wakaru follows [Conventional Commits](https://www.conventionalcommits.org/):

```
feat: add UnNullishCoalescing rule
fix: handle nested ternary in UnConditionals
test: add edge case for arrow function with rest params
refactor: extract shared helper into babel_helper_utils
docs: update architecture diagram for two-phase pipeline
```

Mention the issue number in the commit message or PR description.

## Architecture and testing references

Read these before changing pipeline behavior:

| Document | Topic |
|---|---|
| `docs/architecture.md` | Pipeline flow, components, `unresolved_mark` scope gating |
| `docs/testing.md` | Test helpers (`render`, `render_rule`, `render_pipeline_until`), verification matrix |
| `docs/helper-detection.md` | Transpiler helper matching by AST body shape |
| `docs/debugging.md` | Rule trace CLI, snapshot layers, fixture workflow |

Repository agents and maintainers also reference `AGENTS.md` for the canonical definition-of-done checklist and code-review self-check prompts.

## Related pages

<CardGroup>
<Card title="Develop transformation rules" href="/develop-rules">
Test-first workflow for adding `VisitMut` rules, pipeline placement, and the verification checklist.
</Card>
<Card title="Testing and snapshots" href="/testing-and-snapshots">
`cargo nextest` vs `cargo test`, insta workflow, pipeline test binaries, and pre-commit matrix.
</Card>
<Card title="Helper detection" href="/helper-detection">
How Babel, TypeScript, and SWC helpers are matched across imported, inlined, hoisted, and minified forms.
</Card>
<Card title="Trace the rule pipeline" href="/trace-rule-pipeline">
`debug trace` for per-rule diffs, `--from`/`--until` ranges, and regression bisection.
</Card>
<Card title="Debug regressions" href="/debugging-regressions">
Snapshot drift investigation, early-rule cascades, and `unresolved_mark` symptom mapping.
</Card>
</CardGroup>
