This package offers a comprehensive set of transformation rules designed to unminify and enhance the readability of code.
It covers most of the patterns that are used by the following tools:
- Terser (Check the Terser Progress)
- Babel (Check the Babel Progress)
- SWC (Check the SWC Progress)
- TypeScript
-
Readability
un-boolean
un-undefined
un-infinity
un-numeric-literal
un-typeof
un-sequence-expression
un-variable-merging
un-assignment-expression
un-bracket-notation
un-while-loop
un-flip-comparisons
un-conditionals
un-return
un-indirect-call
un-type-constructor
(Unsafe)un-builtin-prototype
un-import-rename
smart-rename
un-iife
- Syntax Upgrade
- Clean Up
- Style
- Extra
- TODO
Converts minified boolean
to simple true
/false
.
- !0
+ true
- !1
+ false
Converts void 0
to undefined
.
- if(input === void 0) {}
+ if(input === undefined) {}
Converts 1 / 0
to Infinity
.
- 1 / 0
+ Infinity
- -1 / 0
+ -Infinity
Converts numeric literal to its decimal representation.
A comment will be added to indicate the original value.
- 1e3
+ 1000 /* 1e3 */
- 0b101010
+ 42 /* 0b101010 */
- 0x123
+ 291 /* 0x123 */
Converts minified typeof
to its long form.
- typeof x > "u"
+ typeof x === "undefined"
- typeof x < "u"
+ typeof x !== "undefined"
Separate sequence expressions into multiple statements.
- a(), b(), c()
+ a()
+ b()
+ c()
- return a(), b()
+ a()
+ return b()
- while (a(), b(), c++ > 0) {}
+ a()
+ b()
+ while (c++ > 0) {}
Separate variable declarators into multiple statements.
- var a = 1, b = true, c = func(d):
+ var a = 1;
+ var b = true;
+ var c = func(d);
Separate variable declarators that are not used in for statements.
- for (var i = 0, j = 0, k = 0; j < 10; k++) {}
+ var i = 0
+ for (var j = 0, k = 0; j < 10; k++) {}
Separate chained assignment into multiple statements.
- a = b = c = 1
+ a = 1
+ b = 1
+ c = 1
Simplify bracket notation.
- obj['prop']
+ obj.prop
- obj['var']
+ obj['var']
Converts for loop without init and update to while loops.
- for (;;) {}
+ while (true) {}
- for (; i < 10;) {
- console.log(i);
- }
+ while (i < 10) {
+ console.log(i);
+ }
Flips comparisons that are in the form of "literal comes first" to "literal comes second".
- if ("dark" === theme) {}
+ if (theme === "dark") {}
- while (10 < count) {}
+ while (count > 10) {}
Unwraps nested ternary expressions and binary expression into if-else statements or switch statements.
- a ? b() : c ? d() : e()
+ if (a) {
+ b();
+ } else if (c) {
+ d();
+ } else {
+ e();
+ }
This rule will try to adopt the Early Exit
strategy if possible.
function fn () {
- return a ? b() : c ? d() : e()
+ if (a) {
+ return b();
+ }
+ if (c) {
+ return d();
+ }
+ return e();
}
- foo == 'bar' ? bar() : foo == 'baz' ? baz() : foo == 'qux' || foo == 'quux' ? qux() : quux()
+ switch (foo) {
+ case 'bar':
+ bar()
+ break
+ case 'baz':
+ baz()
+ break
+ case 'qux':
+ case 'quux':
+ qux()
+ break
+ default:
+ quux()
+ }
Simplify the last return statements.
function foo() {
const a = 1
if (a) {
return a;
}
- return void 0;
}
const bar = () => {
- return void foo();
+ foo();
}
Converts indirect call expressions to direct call expressions.
- import s from 'react'
- (0, s.useRef)(0);
+ import { useRef } from 'react'
+ useRef(0);
var s = require('react')
- (0, s.useRef)(0);
+ const { useRef } = s
+ useRef(0);
Restore type constructors from minified code.
- +x;
+ Number(x);
- x + "";
+ String(x);
- [,,,];
+ Array(3);
Unsafe:
- BigInt:
+1n
will throwTypeError
- Symbol:
Symbol('foo') + ""
will throwTypeError
Convert function calls on instances of built-in objects to equivalent calls on their prototypes.
- [].splice.apply(a, [1, 2, b, c]);
+ Array.prototype.splice.apply(a, [1, 2, b, c]);
- (function() {}).call.apply(console.log, console, ["foo"]),
+ Function.prototype.call.apply(console.log, console, ["foo"]),
- 0..toFixed.call(Math.PI, 2);
+ Number.prototype.toFixed.call(Math.PI, 2);
- ({}).hasOwnProperty.call(d, "foo");
+ Object.prototype.hasOwnProperty.call(d, "foo");
- /t/.test.call(/foo/, "bar");
+ RegExp.prototype.test.call(/foo/, "bar");
- "".indexOf.call(e, "bar");
+ String.prototype.indexOf.call(e, "bar");
Rename import specifier back to the original name
-import { foo as a } from 'bar';
- a();
+import { foo } from 'bar';
+ foo();
Rename minified identifiers with heuristic rules.
- const {
- gql: t,
- dispatchers: o,
- listener: i
- } = n;
- o.delete(t, i);
+ const {
+ gql,
+ dispatchers,
+ listener
+ } = n;
+ dispatchers.delete(gql, listener);
React Hooks:
- const th = createContext('light');
+ const ThContext = createContext('light');
- const [e, f] = useState(0);
+ const [e, setE] = useState(0);
- const g = useRef(null);
+ const gRef = useRef(null);
- const [e, f] = o.useReducer(reducer, initialArg, init?);
+ const [eState, fDispatch] = o.useReducer(reducer, initialArg, init?);
- const Z = o.forwardRef((e, t) => { ... })
+ const Z = o.forwardRef((props, ref) => { ... })
Improve the readability of code inside IIFE. Useful for short code snippets / userscripts.
Rename the parameters and move the passed-in arguments to the top.
- (function(i, s, o, g, r, a, m) {
- i['GoogleAnalyticsObject'] = r;
- i[r].l = 1 * new Date();
- a = s.createElement(o);
- m = s.getElementsByTagName(o)[0];
- a.async = 1;
- a.src = g;
- m.parentNode.insertBefore(a, m);
- })(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');
+ (function(window, document, a, m) {
+ const o = 'script';
+ const g = 'https://www.google-analytics.com/analytics.js';
+ const r = 'ga';
+ window['GoogleAnalyticsObject'] = r;
+ window[r].l = 1 * new Date();
+ a = document.createElement(o);
+ m = document.getElementsByTagName(o)[0];
+ a.async = 1;
+ a.src = g;
+ m.parentNode.insertBefore(a, m);
+ })(window, document);
Restore template literal syntax from string concatenation.
- "the ".concat(first, " take the ").concat(second, " and ").concat(third);
+ `the ${first} take the ${second} and ${third}`
Restore parameters. Support normal parameters and default parameters.
- function foo() {
- var a = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "foo";
- var b = arguments.length > 1 ? arguments[1] : undefined;
- if (c === void 0) c = "bar";
- }
+ function foo(a = "foo", b, c = "bar") {}
- function foo() {
- console.log(arguments);
- }
+ function foo(...args) {
+ console.log(args);
+ }
Transform fn.apply
calls to spread operator.
- fn.apply(void 0, arr);
+ fn(...arr);
- obj.fn.apply(obj, arr);
+ obj.fn(...arr);
Restore TypeScript enum syntax.
- var Direction;
- (function (Direction) {
- Direction["Up"] = "UP";
- Direction[Direction["Down"] = 2] = "Down";
- })(Direction || (Direction = {}));
+ var Direction = {
+ Up: "UP",
+ Down: 2,
+ // reverse mapping
+ 2: "Down"
+ }
Converts object property accesses and array index accesses to destructuring.
- const t = e.x;
- const n = e.y;
- const r = e.color;
- console.log(t, n, r)
+ const { x, y, color } = e;
+ console.log(x, y, color)
- const t = e[0];
- const n = e[1];
- const r = e[2];
- console.log(t, n, r);
+ const [t, n, r] = e;
+ console.log(t, n, r);
Inline reassigned temp variables.
- const a = d;
- const b = a;
- const c = b;
+ const c = d;
Inline common global variable references.
- const d = document;
- const c = d.createElement('canvas');
+ const c = document.createElement('canvas');
Rename variables based on object property access.
- const t = s.target;
- const p = t.parent;
- const v = p.value;
+ const s_target = s.target;
+ const s_target_parent = s_target.parent;
+ const s_target_parent_value = s_target_parent.value;
Restore optional chaining syntax.
Support output from TypeScript, Babel and SWC.
- (_foo = foo) === null || _foo === void 0 ? void 0 : _foo.bar;
+ foo?.bar;
- (_foo = foo) === null || _foo === void 0 ? void 0 : (_foo_bar = _foo.bar) === null || _foo_bar === void 0 ? void 0 : _foo_bar.baz;
+ foo?.bar?.baz;
Restore nullish coalescing syntax.
Support output from TypeScript, Babel and SWC.
- (_ref = foo !== null && foo !== void 0 ? foo : bar) !== null && _ref !== void 0 ? _ref : "quz";
+ foo ?? bar ?? "quz";
Converts CommonJS's require
and module.exports
to ES6's import
and export
.
- const foo = require('foo')
- var { bar } = require('bar')
- var baz = require('baz').baz
- require('side-effect')
+ import foo from 'foo'
+ import { bar } from 'bar'
+ import { baz } from 'baz'
+ import 'side-effect'
- module.exports.foo = 1
- exports.bar = bar
+ export const foo = 1
+ export { bar }
- module.exports.default = foo
+ export default foo
[!WARNING] Please aware that CJS and ESM are not fully compatible, and this transformation is not perfect. We have a comprehensive test suite to ensure the correctness, but there are still some edge cases that are not covered. Feel free to open an issue if you find any bugs.
Limitations:
-
require(dynamic)
is not supported as ESM does not support dynamic imports. Convert it toawait import()
is not appropriate as it require the whole execution context to be async. - Some packages require
import * as name from 'package'
instead ofimport name from 'package'
. We cannot detect this automatically, so you might need to fix it manually. - Currently, it won't aware the exports format of other files generated by the
unpacker
.
Restore Class
definition from the constructor and the prototype.
Currently, this transformation only supports output from TypeScript.
Supported features:
- constructor
- instance properties
- instance methods
- static methods
- static properties
- getters and setters
- async method (share the same limitations from
un-async-await
)
Unsupported features:
- inheritance
- decorators
- private flag(#)
- var Foo = (function() {
- function t(name) {
- this.name = name;
- this.age = 18;
- }
- t.prototype.hi = function logger() {
- console.log("Hello", this.name);
- };
- t.staticMethod = function staticMethod() {
- console.log("static");
- };
- t.instance = new t("foo");
- return t;
- })();
+ class Foo {
+ constructor(name) {
+ this.name = name;
+ this.age = 18;
+ }
+ hi() {
+ console.log("Hello", this.name);
+ }
+ static staticMethod() {
+ console.log("static");
+ }
+ static instance = new Foo("foo");
+ }
Restore async/await from helper __awaiter
and __generator
.
Currently, this transformation only supports output from TypeScript.
And it does not handle control flow properly, as it needs graph analysis.
Please aware there are tons of edge cases that are not covered by this rule.
-function func() {
- return __awaiter(this, void 0, void 0, function () {
- var result, json;
- return __generator(this, function (_a) {
- switch (_a.label) {
- case 0:
- console.log('Before sleep');
- return [4 /*yield*/, sleep(1000)];
- case 1:
- _a.sent();
- return [4 /*yield*/, fetch('')];
- case 2:
- result = _a.sent();
- return [4 /*yield*/, result.json()];
- case 3:
- json = _a.sent();
- return [2 /*return*/, json];
- }
- });
- });
-}
+async function func() {
+ var result, json;
+ console.log('Before sleep');
+ await sleep(1000);
+ result = await fetch('');
+ json = await result.json();
+ return json;
+}
Converts React.createElement
and jsxRuntime.jsx
back to JSX.
- React.createElement("div", { className: "title" }, "Hello World");
+ <div className="title">Hello World</div>
Built-in pragma: jsx
, jsxs
, _jsx
, _jsxs
, jsxDEV
, jsxsDEV
and h
Pass pragma
option to specify the JSX pragma.
Pass pragmaFrag
option to specify the JSX fragment pragma.
// pragma: "jsx", pragmaFrag: "Fragment"
- jsx(React.Fragment, null, jsx("span", { className: "title" }, "Hello"), jsx("span", null, "World"));
+ <>
+ <span className="title">Hello</span>
+ <span>World</span>
+ </>
Component name will be guessed from the displayName
property automatically.
- var S = /*#__PURE__*/React.createElement("div", null);
- S.displayName = "Foo-Bar";
- var Bar = () => (
- <div>
- <S />
- </div>
- )
+ var FooBar = <div />;
+ FooBar.displayName = "Foo-Bar";
+ var Bar = () => (
+ <div>
+ <FooBar />
+ </div>
+ )
Removes the __esModule
flag from the module.
- Object.defineProperty(exports, "__esModule", { value: true });
Removes the "use strict"
directive.
- "use strict";
Formats the code with prettier.
Lebab transpiles your ES5 code to ES6/ES7. It does exactly the opposite of what Babel does.
We integrated part of rules from Lebab to unminify the code.
By utilizing Lebab, we can save the repetitive work of writing the same transformations ourselves.
- [ ]
un-string-literal
to decode printable unicode - [ ] Terser loops contains several useful patterns
- [ ]
let a; a = 1;
tolet a = 1;
- [ ] Support for Logical Assignment Operators (
a ||= b
,a &&= b
,a ??= b
) [ES2021]