unmin-js
v1.0.0
Published
JavaScript formatter and deobfuscation engine - transform minified code into readable, formatted JavaScript
Maintainers
Readme
unmin
Transform minified JavaScript into readable code. One simple function, multiple power levels.
import unmin from "unmin-js";
const result = await unmin(code); // Full deobfuscation by default
console.log(result.code);Install
npm install -g unmin-js # CLI + Library (all-in-one)API
Single Function, Multiple Modes
// Full deobfuscation (default)
await unmin(code);
// Fast format only
await unmin(code, { mode: "format" });
// Quick deobfuscation (skip expensive transforms)
await unmin(code, { fast: true });
// Customize any option
await unmin(code, {
mode: "full" | "format", // default: "full"
fast: boolean, // default: false
jsx: boolean, // default: true
});Result:
{
code: string; // Transformed output
parseError?: string; // Error if parse failed
stats?: { // Transformation stats (mode: "full" only)
stringsResolved?: number;
guardsRemoved?: number;
cffReversed?: boolean;
jsxReconstructed?: number;
};
}CLI
unmin app.min.js # Full deobfuscation → app.min.unmin.js
unmin app.min.js --format # Fast format only
unmin app.min.js --fast # Quick deobfuscation
cat bundle.js | unmin # Stdin → stdout
unmin app.min.js -o app.js # Custom output
unmin app.min.js --no-jsx # Keep runnable (don't convert to JSX)
unmin app.min.js --quiet # Suppress outputNote: Full mode with JSX produces readable JSX syntax. To run the output:
- Option 1: Use
--no-jsxto keep createElement calls (runnable in Node.js) - Option 2: Rebundle JSX output with esbuild:
esbuild index.js --bundle --loader:.js=jsx - Option 3: Use
--formatmode for guaranteed Node.js compatibility
What It Does
Default Mode (Full Power)
- Parse with error recovery, full syntax support
- Detect obfuscation types (string tables, CFF, guards)
- Remove anti-debugging guards
- Resolve string tables via VM sandbox
- Reverse control-flow flattening (CFG-based IR)
- Reconstruct JSX from createElement calls ⚠️ makes output unrunnable
- Normalize:
!0→true,void 0→undefined, bracket → dot - Modernize:
var→const/let,function→ arrow (safe) - Rename: semantic variable naming from context
- Format: oxfmt (30× faster than prettier)
Tradeoff: JSX reconstruction makes code more readable. Output can be made runnable by:
- Using
--no-jsxflag (keeps createElement, runs in Node.js) - Rebundling with
esbuild --loader:.js=jsx(transpiles JSX → createElement) - Using
--formatmode (no JSX conversion)
Format Mode (Fast & Safe & Runnable)
- Parse
- Normalize
- Modernize
- Format
No string decoding, no CFF reversal, no JSX conversion, no semantic changes. Output is always runnable in Node.js.
Rebundle Test
The test suite includes rebundle tests that verify unbundled output can be:
- Rebundled with esbuild (with JSX support via
--loader:.js=jsx) - Executed successfully with expected output
- Used in real-world workflows
Examples
Input (Minified)
var x = !0,
y = !1;
if (typeof w !== "undefined") console["log"](w);Output (Full Mode)
const x = true;
const y = false;
if (typeof w !== "undefined") console.log(w);String Table Decoding
Before:
function a() {
const x = ["log", "Hello"];
return (a = function () {
return x;
});
}
console[b(0)](b(1));After:
console.log("Hello");JSX Reconstruction
Before:
React.createElement("div", { className: "x" }, React.createElement("h1", null, "Hello"));After:
<div className="x">
<h1>Hello</h1>
</div>Development
pnpm install
pnpm build
pnpm test # 97 tests
pnpm check # lint + formatDesign Philosophy
One function. Clear options. Predictable behavior.
mode: "full"(default): Full power, all transformsmode: "format": Fast & safe, no semantic analysisfast: true: Skip expensive transforms in any mode- Boolean flags: explicit control over each transform
No confusion about which function to call. Just unmin(code, options).
License
MIT
