1 | [![Build Status](https://img.shields.io/travis/lebab/lebab.svg)](https://travis-ci.org/lebab/lebab)
|
2 | [![Coverage Status](https://img.shields.io/codecov/c/github/lebab/lebab/master.svg)](https://codecov.io/github/lebab/lebab)
|
3 | [![Dependencies](https://img.shields.io/librariesio/github/lebab/lebab.svg)](https://libraries.io/npm/lebab)
|
4 | [![License](https://img.shields.io/:license-mit-brightgreen.svg)](https://mohebifar.mit-license.org)
|
5 | [![Version](https://img.shields.io/npm/v/lebab.svg)](https://www.npmjs.com/package/lebab)
|
6 |
|
7 | # Lebab
|
8 |
|
9 | ![Lebab](https://raw.githubusercontent.com/mohebifar/lebab-logo/master/logo.png)
|
10 |
|
11 | **Lebab** transpiles your ES5 code to ES6/ES7.
|
12 | It does exactly the opposite of what [Babel](https://babeljs.io/) does.
|
13 | If you want to understand what Lebab exactly does, **[try the live demo](https://lebab.github.io/).**
|
14 |
|
15 |
|
16 | ## Install
|
17 |
|
18 | Install it using npm:
|
19 |
|
20 | ```bash
|
21 | $ npm install -g lebab
|
22 | ```
|
23 |
|
24 | Full build:
|
25 |
|
26 | - [latest Browserified version of Lebab](https://wzrd.in/standalone/lebab@latest)
|
27 | - [the same, using cdn.rawgit](https://umdfied.herokuapp.com/umdfied/lebab/latest)
|
28 |
|
29 | ## Usage
|
30 |
|
31 | Convert your old-fashioned code using the `lebab` cli tool,
|
32 | enabling a specific transformation:
|
33 |
|
34 | ```bash
|
35 | $ lebab es5.js -o es6.js --transform let
|
36 | ```
|
37 |
|
38 | Or transform an entire directory of files in-place:
|
39 |
|
40 | ```bash
|
41 | # .js files only
|
42 | $ lebab --replace src/js/ --transform arrow
|
43 | # For other file extensions, use explicit globbing
|
44 | $ lebab --replace 'src/js/**/*.jsx' --transform arrow
|
45 | ```
|
46 |
|
47 | For all the possible values for `--transform` option
|
48 | see the detailed docs below or use `--help` from command line.
|
49 |
|
50 |
|
51 | ## Features and known limitations
|
52 |
|
53 | The recommended way of using Lebab is to apply one transform at a time,
|
54 | read what exactly the transform does and what are its limitations,
|
55 | apply it for your code and inspect the diff carefully.
|
56 |
|
57 | ### Safe transforms
|
58 |
|
59 | These transforms can be applied with relatively high confidence.
|
60 | They use pretty straight-forward and strict rules for changing the code.
|
61 | The resulting code should be almost 100% equivalent of the original code.
|
62 |
|
63 | - [x] **arrow** - callbacks to arrow functions
|
64 | - [x] Converts bound functions like `function(){}.bind(this)`
|
65 | - [x] not applied to unbound functions that use `this`
|
66 | - [x] not applied to functions that use `arguments`
|
67 | - [x] not applied to object properties (use `obj-method` transform)
|
68 | - [ ] does not remove `that = this` assignments
|
69 | - [x] **arrow-return** - drop return statements in arrow functions
|
70 | - [x] converts immediate return `{ return x; }` to `=> x`
|
71 | - [x] applies to arrow functions and nested arrow functions
|
72 | - [ ] LIMITATION only applies to arrow functions (run the `arrow` transform first)
|
73 | - [x] **for-of** - for loop to for-of loop
|
74 | - [x] uses name `item` for loop variable when loop body begins with `var item = array[i];`
|
75 | - [ ] [does not work when no such alias defined at the start of loop body][166]
|
76 | - [ ] LIMITATION requires let/const variables (run the `let` transform first)
|
77 | - [x] **for-each** - for loop to `Array.forEach()`
|
78 | - [x] uses name `item` for forEach parameter when loop body begins with `var item = array[i];`
|
79 | - [ ] [does not work when no such alias defined at the start of loop body][166]
|
80 | - [x] adds index parameter when loop body makes use of the index variable.
|
81 | - [ ] LIMITATION requires let/const variables (run the `let` transform first)
|
82 | - [x] **arg-rest** - use of arguments to function(...args)
|
83 | - [x] does not perform the transform when `args` variable already exists
|
84 | - [ ] always names the rest-parameter to `args`
|
85 | - [ ] LIMITATION [does not transform functions with formal parameters][191]
|
86 | - [ ] LIMITATION [does not remove uses of `Array.slice.call(arguments)`][191]
|
87 | - [x] **arg-spread** - use of apply() to spread operator
|
88 | - [x] recognizes `obj.method.apply(obj, args)`
|
89 | - [x] recognizes `func.apply(undefined, args)`
|
90 | - [x] **obj-method** - function values in object to methods
|
91 | - [ ] LIMITATION [does not convert named function expressions][127]
|
92 | - [ ] does not convert arrow-functions
|
93 | - [x] **obj-shorthand** - `{foo: foo}` to `{foo}`
|
94 | - [x] ignores numeric and `NaN` properties
|
95 | - [ ] does not convert string properties
|
96 | - [x] **no-strict** - removal of `"use strict"` directives
|
97 | - [x] does not touch stuff like `x = "use strict";`
|
98 | - [x] **exponent** - `Math.pow()` to `**` operator (**ES7**)
|
99 | - [x] Full support for all new syntax from ES7
|
100 | - [x] **multi-var** - single `var x,y;` declaration to multiple `var x; var y;` (**refactor**)
|
101 | - [x] Not related to any new syntax feature
|
102 | - [x] EXPERIMENT [to see if Lebab could be a more generic refactoring helper][158]
|
103 |
|
104 | ### Unsafe transforms
|
105 |
|
106 | These transforms should be applied with caution.
|
107 | They either use heuristics which can't guarantee that the resulting code is equivalent of the original code,
|
108 | or they have significant bugs which can result in breaking your code.
|
109 |
|
110 | - [x] **let** - `var` to `let`/`const`
|
111 | - [x] never modified variables are converted to `const`
|
112 | - [x] properly recognizes block-scoping
|
113 | - [x] splits single var declaration to multiple `let`/`const` declarations if needed
|
114 | - [x] recognizes vars defined/assigned using destructuring
|
115 | - [x] vars that conflict with block-scoping are not converted
|
116 | - [x] repeated declarations of the same var are not converted
|
117 | - [x] existing `let`/`const` are not converted
|
118 | - [ ] BUG [fails with repeated variable definitions that use destructuring][131]
|
119 | - [ ] BUG [fails with closure over a loop variable][145]
|
120 | - [ ] BUG [fails when function closes over variable declared after function is called][168]
|
121 | - [x] **class** - function/prototypes to classes
|
122 | - [x] recognizes `Foo.prototype.method = function(){ ... };`
|
123 | - [x] recognizes `Foo.prototype = { ...methods... };`
|
124 | - [x] recognizes static methods like `Foo.method = function(){ ... };`
|
125 | - [x] recognizes getters/setters defined with `Object.defineProperty()`
|
126 | - [x] recognizes inheritance with `Child.prototype = new Parent()`
|
127 | - [x] recognizes inheritance with `util.inherits(Child, Parent);`
|
128 | - [x] converts superclass constructor calls to `super()`
|
129 | - [x] converts superclass method calls to `super.method()`
|
130 | - [ ] LIMITATION [does not require super() call in subclass constructor][186]
|
131 | - [ ] LIMITATION [does not enforce super() call position in subclass constructor][186]
|
132 | - [ ] LIMITATION [does not support namespaced classes][113]
|
133 | - [x] **commonjs** - CommonJS module definition to ES6 modules
|
134 | - [x] converts `var foo = require("foo")` to `import foo from "foo"`
|
135 | - [x] converts `var bar = require("foo").bar` to `import {bar} from "foo"`
|
136 | - [x] converts `var {bar} = require("foo")` to `import {bar} from "foo"`
|
137 | - [x] converts `module.exports = <anything>` to `export default <anything>`
|
138 | - [x] converts `exports.foo = function(){}` to `export function foo(){}`
|
139 | - [x] converts `exports.Foo = class {}` to `export class Foo {}`
|
140 | - [x] converts `exports.foo = 123` to `export var foo = 123`
|
141 | - [x] converts `exports.foo = bar` to `export {bar as foo}`
|
142 | - [ ] LIMITATION does not check if named export conflicts with existing variable names
|
143 | - [ ] LIMITATION Ignores imports/exports inside nested blocks/functions
|
144 | - [ ] LIMITATION only handles `require()` calls in `var` declarations
|
145 | - [ ] LIMITATION does not ensure that imported variable is treated as `const`
|
146 | - [ ] LIMITATION [does not ensure named exports are imported with correct ES6 syntax][215]
|
147 | - [x] **template** - string concatenation to template strings
|
148 | - [x] converts variables and arbitrary expressions to `${...}`
|
149 | - [ ] BUG [removes indentation of multi-line strings][88]
|
150 | - [ ] LIMITATION [ignores difference between `.toString()` and `.valueOf()`][107]
|
151 | - [x] **default-param** - default parameters instead of `a = a || 2`
|
152 | - [x] recognizes `a = a || 2`
|
153 | - [x] recognizes `a = a ? a : 2`
|
154 | - [x] recognizes `a = a === undefined ? 2 : a`
|
155 | - [x] recognizes `a = typeof a === 'undefined' ? 2 : a`
|
156 | - [ ] LIMITATION [transforming `a = a || 2` does not produce strictly equivalent code][125]
|
157 | - [x] **destruct-param** - use destructuring for objects in function parameters
|
158 | - [x] converts `(obj) => obj.a + obj.b` to `({a, b}) => a + b`
|
159 | - [x] does not transform when conflicts with existing variables
|
160 | - [x] does not transform when object properties are modified
|
161 | - [ ] LIMITATION Only objects with maximum of 4 properties are transformed
|
162 | - [ ] BUG [Can conflict with variables introduced by the transform itself][200]
|
163 | - [x] **includes** - `array.indexOf(foo) !== -1` to `array.includes(foo)` (**ES7**)
|
164 | - [x] works for both strings and arrays
|
165 | - [x] converts `!== -1` to `array.includes(foo)`
|
166 | - [x] converts `=== -1` to `!array.includes(foo)`
|
167 | - [x] recognizes all kinds of comparisons `>= 0`, `> -1`, etc
|
168 | - [x] recognizes both `indexOf() != -1` and `-1 != indexOf()`
|
169 | - [ ] LIMITATION does not detect that indexOf() is called on an actual Array or String.
|
170 |
|
171 |
|
172 | ## Programming API
|
173 |
|
174 | Simply import and call the `transform()` function:
|
175 |
|
176 | ```js
|
177 | import {transform} from 'lebab';
|
178 | const {code, warnings} = transform(
|
179 | 'var f = function(a) { return a; };', // code to transform
|
180 | ['let', 'arrow', 'arrow-return'] // transforms to apply
|
181 | );
|
182 | console.log(code); // -> "const f = a => a;"
|
183 | ```
|
184 |
|
185 | The warnings will be an array of objects like:
|
186 |
|
187 | ```js
|
188 | [
|
189 | {line: 12, msg: 'Unable to transform var', type: 'let'},
|
190 | {line: 45, msg: 'Can not use arguments in arrow function', type: 'arrow'},
|
191 | ]
|
192 | ```
|
193 |
|
194 | Most of the time there won't be any warnings and the array will be empty.
|
195 |
|
196 |
|
197 | ## Editor plugins
|
198 |
|
199 | Alternatively one can use Lebab through plugins in the following editors:
|
200 |
|
201 | - Atom: [atom-lebab](https://github.com/ga2mer/atom-lebab)
|
202 | - Sublime: [lebab-sublime](https://github.com/inkless/lebab-sublime) or [Lebab ES6 Transform](https://packagecontrol.io/packages/Lebab%20ES6%20Transform)
|
203 | - VSCode: [vscode-lebab](https://marketplace.visualstudio.com/items?itemName=mrmlnc.vscode-lebab)
|
204 |
|
205 |
|
206 | ## What's next?
|
207 |
|
208 | Which feature should Lebab implement next?
|
209 | Let us know by [creating an issue](https://github.com/mohebifar/lebab/issues)
|
210 | or voicing your opinion in existing one.
|
211 |
|
212 | Want to contribute? [Read how Lebab looks for patterns in syntax trees.][pattern-matching]
|
213 |
|
214 | [pattern-matching]: http://nene.github.io/2016/04/02/matches-ast
|
215 | [88]: https://github.com/lebab/lebab/issues/88
|
216 | [107]: https://github.com/lebab/lebab/issues/107
|
217 | [113]: https://github.com/lebab/lebab/issues/113
|
218 | [125]: https://github.com/lebab/lebab/issues/125
|
219 | [127]: https://github.com/lebab/lebab/issues/127
|
220 | [131]: https://github.com/lebab/lebab/issues/131
|
221 | [145]: https://github.com/lebab/lebab/issues/145
|
222 | [158]: https://github.com/lebab/lebab/issues/158
|
223 | [166]: https://github.com/lebab/lebab/issues/166
|
224 | [168]: https://github.com/lebab/lebab/issues/168
|
225 | [186]: https://github.com/lebab/lebab/issues/186
|
226 | [191]: https://github.com/lebab/lebab/issues/191
|
227 | [200]: https://github.com/lebab/lebab/issues/200
|
228 | [215]: https://github.com/lebab/lebab/issues/215
|