Lebab
Lebab transpiles your ES5 code to ES6/ES7. It does exactly the opposite of what Babel does. If you want to understand what Lebab exactly does, try the live demo.
Install
Install it using npm:
$ npm install -g lebab
Usage
Convert your old-fashioned code using the lebab
cli tool,
enabling a specific transformation:
$ lebab es5.js -o es6.js --transform let
Or transform an entire directory of files in-place:
# .js files only
$ lebab --replace src/js/ --transform arrow
# For other file extensions, use explicit globbing
$ lebab --replace 'src/js/**/*.jsx' --transform arrow
For all the possible values for --transform
option
see the detailed docs below or use --help
from command line.
Features and known limitations
The recommended way of using Lebab is to apply one transform at a time, read what exactly the transform does and what are its limitations, apply it for your code and inspect the diff carefully.
Safe transforms
These transforms can be applied with relatively high confidence. They use pretty straight-forward and strict rules for changing the code. The resulting code should be almost 100% equivalent of the original code.
- <input checked="" disabled="" type="checkbox"> arrow - callbacks to arrow functions
- <input checked="" disabled="" type="checkbox"> Converts bound functions like
function(){}.bind(this)
- <input checked="" disabled="" type="checkbox"> not applied to unbound functions that use
this
- <input checked="" disabled="" type="checkbox"> not applied to functions that use
arguments
- <input checked="" disabled="" type="checkbox"> not applied to object properties (use
obj-method
transform) - <input disabled="" type="checkbox"> does not remove
that = this
assignments - <input disabled="" type="checkbox"> LIMITATION: can mess up prototype-based classes, run the
class
transform first to prevent this.
- <input checked="" disabled="" type="checkbox"> Converts bound functions like
- <input checked="" disabled="" type="checkbox"> arrow-return - drop return statements in arrow functions
- <input checked="" disabled="" type="checkbox"> converts immediate return
{ return x; }
to=> x
- <input checked="" disabled="" type="checkbox"> applies to arrow functions and nested arrow functions
- <input disabled="" type="checkbox"> LIMITATION only applies to arrow functions (run the
arrow
transform first)
- <input checked="" disabled="" type="checkbox"> converts immediate return
- <input checked="" disabled="" type="checkbox"> for-of - for loop to for-of loop
- <input checked="" disabled="" type="checkbox"> uses name
item
for loop variable when loop body begins withvar item = array[i];
- <input disabled="" type="checkbox"> does not work when no such alias defined at the start of loop body
- <input disabled="" type="checkbox"> LIMITATION requires let/const variables (run the
let
transform first)
- <input checked="" disabled="" type="checkbox"> uses name
- <input checked="" disabled="" type="checkbox"> for-each - for loop to
Array.forEach()
- <input checked="" disabled="" type="checkbox"> uses name
item
for forEach parameter when loop body begins withvar item = array[i];
- <input disabled="" type="checkbox"> does not work when no such alias defined at the start of loop body
- <input checked="" disabled="" type="checkbox"> adds index parameter when loop body makes use of the index variable.
- <input disabled="" type="checkbox"> LIMITATION requires let/const variables (run the
let
transform first)
- <input checked="" disabled="" type="checkbox"> uses name
- <input checked="" disabled="" type="checkbox"> arg-rest - use of arguments to function(...args)
- <input checked="" disabled="" type="checkbox"> does not perform the transform when
args
variable already exists - <input disabled="" type="checkbox"> always names the rest-parameter to
args
- <input disabled="" type="checkbox"> LIMITATION does not transform functions with formal parameters
- <input disabled="" type="checkbox"> LIMITATION does not remove uses of
Array.slice.call(arguments)
- <input checked="" disabled="" type="checkbox"> does not perform the transform when
- <input checked="" disabled="" type="checkbox"> arg-spread - use of apply() to spread operator
- <input checked="" disabled="" type="checkbox"> recognizes
obj.method.apply(obj, args)
- <input checked="" disabled="" type="checkbox"> recognizes
func.apply(undefined, args)
- <input checked="" disabled="" type="checkbox"> recognizes
- <input checked="" disabled="" type="checkbox"> obj-method - function values in object to methods
- <input disabled="" type="checkbox"> LIMITATION does not convert named function expressions
- <input disabled="" type="checkbox"> does not convert arrow-functions
- <input checked="" disabled="" type="checkbox"> obj-shorthand -
{foo: foo}
to{foo}
- <input checked="" disabled="" type="checkbox"> ignores numeric and
NaN
properties - <input disabled="" type="checkbox"> does not convert string properties
- <input checked="" disabled="" type="checkbox"> ignores numeric and
- <input checked="" disabled="" type="checkbox"> no-strict - removal of
"use strict"
directives- <input checked="" disabled="" type="checkbox"> does not touch stuff like
x = "use strict";
- <input checked="" disabled="" type="checkbox"> does not touch stuff like
- <input checked="" disabled="" type="checkbox"> exponent -
Math.pow()
to**
operator (ES7)- <input checked="" disabled="" type="checkbox"> Full support for all new syntax from ES7
- <input checked="" disabled="" type="checkbox"> multi-var - single
var x,y;
declaration to multiplevar x; var y;
(refactor)- <input checked="" disabled="" type="checkbox"> Not related to any new syntax feature
- <input checked="" disabled="" type="checkbox"> EXPERIMENT to see if Lebab could be a more generic refactoring helper
Unsafe transforms
These transforms should be applied with caution. They either use heuristics which can't guarantee that the resulting code is equivalent of the original code, or they have significant bugs which can result in breaking your code.
- <input checked="" disabled="" type="checkbox"> let -
var
tolet
/const
- <input checked="" disabled="" type="checkbox"> never modified variables are converted to
const
- <input checked="" disabled="" type="checkbox"> properly recognizes block-scoping
- <input checked="" disabled="" type="checkbox"> splits single var declaration to multiple
let
/const
declarations if needed - <input checked="" disabled="" type="checkbox"> recognizes vars defined/assigned using destructuring
- <input checked="" disabled="" type="checkbox"> vars that conflict with block-scoping are not converted
- <input checked="" disabled="" type="checkbox"> repeated declarations of the same var are not converted
- <input checked="" disabled="" type="checkbox"> existing
let
/const
are not converted - <input disabled="" type="checkbox"> BUG fails with repeated variable definitions that use destructuring
- <input disabled="" type="checkbox"> BUG fails with closure over a loop variable
- <input disabled="" type="checkbox"> BUG fails when function closes over variable declared after function is called
- <input checked="" disabled="" type="checkbox"> never modified variables are converted to
- <input checked="" disabled="" type="checkbox"> class - function/prototypes to classes
- <input checked="" disabled="" type="checkbox"> recognizes
Foo.prototype.method = function(){ ... };
- <input checked="" disabled="" type="checkbox"> recognizes
Foo.prototype = { ...methods... };
- <input checked="" disabled="" type="checkbox"> recognizes static methods like
Foo.method = function(){ ... };
- <input checked="" disabled="" type="checkbox"> recognizes getters/setters defined with
Object.defineProperty()
- <input checked="" disabled="" type="checkbox"> recognizes getters/setters defined with
Object.defineProperties()
- <input checked="" disabled="" type="checkbox"> recognizes inheritance with
Child.prototype = new Parent()
- <input checked="" disabled="" type="checkbox"> recognizes inheritance with
util.inherits(Child, Parent);
- <input checked="" disabled="" type="checkbox"> converts superclass constructor calls to
super()
- <input checked="" disabled="" type="checkbox"> converts superclass method calls to
super.method()
- <input disabled="" type="checkbox"> LIMITATION does not require super() call in subclass constructor
- <input disabled="" type="checkbox"> LIMITATION does not enforce super() call position in subclass constructor
- <input disabled="" type="checkbox"> LIMITATION does not support namespaced classes
- <input checked="" disabled="" type="checkbox"> recognizes
- <input checked="" disabled="" type="checkbox"> commonjs - CommonJS module definition to ES6 modules
- <input checked="" disabled="" type="checkbox"> converts
var foo = require("foo")
toimport foo from "foo"
- <input checked="" disabled="" type="checkbox"> converts
var bar = require("foo").bar
toimport {bar} from "foo"
- <input checked="" disabled="" type="checkbox"> converts
var {bar} = require("foo")
toimport {bar} from "foo"
- <input checked="" disabled="" type="checkbox"> converts
module.exports = <anything>
toexport default <anything>
- <input checked="" disabled="" type="checkbox"> converts
exports.foo = function(){}
toexport function foo(){}
- <input checked="" disabled="" type="checkbox"> converts
exports.Foo = class {}
toexport class Foo {}
- <input checked="" disabled="" type="checkbox"> converts
exports.foo = 123
toexport var foo = 123
- <input checked="" disabled="" type="checkbox"> converts
exports.foo = bar
toexport {bar as foo}
- <input disabled="" type="checkbox"> LIMITATION does not check if named export conflicts with existing variable names
- <input disabled="" type="checkbox"> LIMITATION Ignores imports/exports inside nested blocks/functions
- <input disabled="" type="checkbox"> LIMITATION only handles
require()
calls invar
declarations - <input disabled="" type="checkbox"> LIMITATION does not ensure that imported variable is treated as
const
- <input disabled="" type="checkbox"> LIMITATION does not ensure named exports are imported with correct ES6 syntax
- <input checked="" disabled="" type="checkbox"> converts
- <input checked="" disabled="" type="checkbox"> template - string concatenation to template strings
- <input checked="" disabled="" type="checkbox"> converts variables and arbitrary expressions to
${...}
- <input disabled="" type="checkbox"> BUG removes indentation of multi-line strings
- <input disabled="" type="checkbox"> LIMITATION ignores difference between
.toString()
and.valueOf()
- <input checked="" disabled="" type="checkbox"> converts variables and arbitrary expressions to
- <input checked="" disabled="" type="checkbox"> default-param - default parameters instead of
a = a || 2
- <input checked="" disabled="" type="checkbox"> recognizes
a = a || 2
- <input checked="" disabled="" type="checkbox"> recognizes
a = a ? a : 2
- <input checked="" disabled="" type="checkbox"> recognizes
a = a === undefined ? 2 : a
- <input checked="" disabled="" type="checkbox"> recognizes
a = typeof a === 'undefined' ? 2 : a
- <input disabled="" type="checkbox"> LIMITATION transforming
a = a || 2
does not produce strictly equivalent code
- <input checked="" disabled="" type="checkbox"> recognizes
- <input checked="" disabled="" type="checkbox"> destruct-param - use destructuring for objects in function parameters
- <input checked="" disabled="" type="checkbox"> converts
(obj) => obj.a + obj.b
to({a, b}) => a + b
- <input checked="" disabled="" type="checkbox"> does not transform when conflicts with existing variables
- <input checked="" disabled="" type="checkbox"> does not transform when object properties are modified
- <input disabled="" type="checkbox"> LIMITATION Only objects with maximum of 4 properties are transformed
- <input disabled="" type="checkbox"> BUG Can conflict with variables introduced by the transform itself
- <input checked="" disabled="" type="checkbox"> converts
- <input checked="" disabled="" type="checkbox"> includes -
array.indexOf(foo) !== -1
toarray.includes(foo)
(ES7)- <input checked="" disabled="" type="checkbox"> works for both strings and arrays
- <input checked="" disabled="" type="checkbox"> converts
!== -1
toarray.includes(foo)
- <input checked="" disabled="" type="checkbox"> converts
=== -1
to!array.includes(foo)
- <input checked="" disabled="" type="checkbox"> recognizes all kinds of comparisons
>= 0
,> -1
, etc - <input checked="" disabled="" type="checkbox"> recognizes both
indexOf() != -1
and-1 != indexOf()
- <input disabled="" type="checkbox"> LIMITATION does not detect that indexOf() is called on an actual Array or String.
Programming API
Simply import and call the transform()
function:
import {transform} from 'lebab';
const {code, warnings} = transform(
'var f = function(a) { return a; };', // code to transform
['let', 'arrow', 'arrow-return'] // transforms to apply
);
console.log(code); // -> "const f = a => a;"
The warnings will be an array of objects like:
[
{line: 12, msg: 'Unable to transform var', type: 'let'},
{line: 45, msg: 'Can not use arguments in arrow function', type: 'arrow'},
]
Most of the time there won't be any warnings and the array will be empty.
Editor plugins
Alternatively one can use Lebab through plugins in the following editors:
- Atom: atom-lebab
- Sublime: lebab-sublime or Lebab ES6 Transform
- VSCode: vscode-lebab
What's next?
Which feature should Lebab implement next? Let us know by creating an issue or voicing your opinion in existing one.
Want to contribute? Read how Lebab looks for patterns in syntax trees.