Skip to main content

wakaru/
lib.rs

1//! Wakaru: a JavaScript decompiler exposed as a compiler-like service.
2//!
3//! The stable crate root offers two end-to-end operations:
4//!
5//! - [`decompile`] — rewrite one minified/transpiled source into readable,
6//!   modern JavaScript.
7//! - [`unpack`] — split one or more bundle/chunk inputs into modules and
8//!   decompile each; [`UnpackJob`] is the incremental intake form of the same
9//!   operation for directory walkers.
10//!
11//! Optional workflows live in cohesive namespaces: [`bun`] (single-file
12//! executable extraction), [`debug`] (normalization, rule tracing, rule
13//! metadata), [`sourcemap`] (embedded-source extraction), and [`vue`]
14//! (experimental standalone SFC recovery).
15//!
16//! The API is deliberately not an SWC transformation toolkit: it never exposes
17//! SWC AST types, individual rewrite visitors, detector objects, prepared
18//! ASTs, or cross-module fact structures. Partial recovery is represented
19//! structurally ([`ModuleStatus`], [`Diagnostic`]) instead of being hidden in
20//! warning strings.
21//!
22//! Design decisions, compatibility boundaries, and the internal processing
23//! invariants behind this surface are recorded in `docs/public-api.md`.
24//!
25//! # Publishing model
26//!
27//! The façade is published as `wakaru`. Cargo cannot package a façade with an
28//! unpublished path dependency, so `wakaru-core` is also published as a
29//! lockstep, exact-version implementation dependency. It remains explicitly
30//! unsupported as an integration surface and may change whenever the façade
31//! version changes.
32//!
33//! # Examples
34//!
35//! Single-file decompile:
36//!
37//! ```no_run
38//! use wakaru::{decompile, DecompileOptions, Source};
39//!
40//! # fn main() -> wakaru::Result<()> {
41//! let minified = String::from("var a=!0;");
42//! let output = decompile(Source::new("input.js", minified), DecompileOptions::default())?;
43//!
44//! println!("{}", output.module.code);
45//! for diagnostic in output.diagnostics {
46//!     eprintln!("{}", diagnostic.message);
47//! }
48//! # Ok(())
49//! # }
50//! ```
51//!
52//! Bundle/chunk set:
53//!
54//! ```no_run
55//! use wakaru::{
56//!     unpack, DceMode, ModuleMode, RewriteLevel, RewriteOptions, Source, UnmatchedInput,
57//!     UnpackMode, UnpackOptions,
58//! };
59//!
60//! # fn main() -> wakaru::Result<()> {
61//! # let (entry, chunk) = (String::new(), String::new());
62//! let output = unpack(
63//!     vec![Source::new("entry.js", entry), Source::new("chunk.js", chunk)],
64//!     UnpackOptions::default()
65//!         .with_modules(ModuleMode::Decompile(
66//!             RewriteOptions::default()
67//!                 .with_level(RewriteLevel::Standard)
68//!                 .with_dce(DceMode::TransformOnly),
69//!         ))
70//!         .with_mode(UnpackMode::Auto)
71//!         .with_unmatched(UnmatchedInput::Process)
72//!         .with_diagnostics(true),
73//! )?;
74//!
75//! for module in output.modules {
76//!     println!("{}: {} bytes", module.filename, module.code.len());
77//! }
78//! # Ok(())
79//! # }
80//! ```
81//!
82//! Directory-style detected-only processing with bounded intake memory:
83//!
84//! ```no_run
85//! use wakaru::{InputAction, Source, UnmatchedInput, UnpackJob, UnpackOptions};
86//!
87//! # fn main() -> anyhow::Result<()> {
88//! # let javascript_candidate_paths: Vec<std::path::PathBuf> = Vec::new();
89//! let mut job = UnpackJob::new(UnpackOptions::default().with_unmatched(UnmatchedInput::Skip))?;
90//!
91//! for path in javascript_candidate_paths {
92//!     let code = std::fs::read_to_string(&path)?;
93//!     job.push(Source::new(path.to_string_lossy(), code))?;
94//! }
95//!
96//! let output = job.finish()?;
97//! let skipped = output
98//!     .inputs
99//!     .iter()
100//!     .filter(|input| input.action == InputAction::Skipped)
101//!     .count();
102//! # let _ = skipped;
103//! # Ok(())
104//! # }
105//! ```
106
107pub mod bun;
108pub mod debug;
109mod decompile;
110mod error;
111mod options;
112mod output;
113mod source;
114pub mod sourcemap;
115mod unpack;
116pub mod vue;
117
118pub use decompile::decompile;
119pub use error::{Error, ErrorKind, Result};
120pub use options::{
121    DceMode, DecompileOptions, ModuleMode, RewriteLevel, RewriteOptions, UnmatchedInput,
122    UnpackMode, UnpackOptions,
123};
124pub use output::{
125    BundleFormat, DecompileOutput, Diagnostic, DiagnosticCode, DiagnosticSeverity, EntryStatus,
126    InputAction, InputDetection, InputId, InputReceipt, InputReport, ModuleOutput, ModuleStatus,
127    OutputSafety, SourceSpan, UnpackOutput,
128};
129pub use source::{Source, SourceParts};
130pub use unpack::{unpack, UnpackJob};