# Lebab: converting ES5 back to ES6, one transform at a time

> Lebab runs the Babel pipeline in reverse, rewriting var declarations, prototype methods and CommonJS requires into modern syntax. Its README is unusually candid about which transforms are safe and which are heuristics.

**lebab/lebab** — Turn your ES5 code into readable ES6. Lebab does the opposite of what Babel does.

- Repository: https://github.com/lebab/lebab
- Website: https://lebab.github.io
- Stars: 5,633 · Forks: 150
- Language: JavaScript
- License: MIT
- Published: 2026-09-22 · Updated: 2026-09-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/lebab-lebab

## Who Lebab is for, and the direction it runs

Most JavaScript tooling moves code forward: ES6 or TypeScript in, ES5 out, so that older runtimes can execute it. Lebab points the other way. The README states it "transpiles your ES5 code to ES6/ES7" and does "exactly the opposite of what Babel does." The audience is therefore narrow and specific: teams with a working ES5 codebase who want the source itself to read as modern JavaScript, not teams who need to ship to old browsers.

That distinction decides whether the tool is useful at all. If your build already runs Babel, adding Lebab does not change what executes; it changes what a human reads in the repository. If you have no build step and your ES5 files run directly in a browser or in Node, Lebab is a one-time migration aid rather than a permanent part of the pipeline. The README recommends applying one transform at a time and inspecting the diff, which tells you the intended workflow is a supervised rewrite, not an automated conversion.

## How the transforms work and why they are split into safe and unsafe

The repository layout shows the architecture plainly: src/ holds the transform implementations, bin/ holds the CLI entry point, index.js is the package main, and types/ carries index.d.ts. The dependency list explains the mechanism. espree parses JavaScript into an AST, estraverse walks it, escope resolves variable scope, f-matches handles pattern matching against node shapes, and recast prints the modified tree back to source. Lebab therefore never works on text; every transform is a tree rewrite, and recast is what lets untouched code keep its original formatting.

The README sorts transforms into two groups and explains the split. Safe transforms "use pretty straight-forward and strict rules" and the result "should be almost 100% equivalent of the original code." Unsafe transforms "either use heuristics which can't guarantee that the resulting code is equivalent" or "have significant bugs which can result in breaking your code." That is an honest classification, and it is the single most useful thing in the documentation.

The safe list includes arrow, arrow-return, for-of, for-each, arg-rest, arg-spread, obj-method, obj-shorthand, no-strict, exponent and multi-var. Even here the README records limits. The arrow transform does not apply to unbound functions that use this, does not apply to functions using arguments, and does not remove that = this assignments. The arg-rest transform always names the rest parameter args and does not transform functions with formal parameters. The unsafe list is where the real risk sits: let, class and commonjs. For let, the README lists open bugs including failure with repeated variable definitions that use destructuring, failure with a closure over a loop variable, and failure when a function closes over a variable declared after the function is called. For class, it notes that super() is neither required nor positionally enforced in subclass constructors, and that namespaced classes are unsupported.

## Installing Lebab and running a first transform

The README gives a global npm install as the installation path, and package.json declares a bin entry named lebab pointing at bin/index.js, so the command is available on your PATH after installation. The package requires Node >=6 per the engines field.

```bash
$ npm install -g lebab
```

The first real use is a single file with a single transform. The README's own example writes the converted output to a new file rather than overwriting the input, which is the right habit to copy while you are still evaluating the tool.

```bash
$ lebab es5.js -o es6.js --transform let
```

After that command you should have es6.js containing the rewritten source and es5.js untouched. Read the diff before going further, because let is on the unsafe list.

For a whole tree, the README documents --replace. Note that it only picks up .js files by default; other extensions need explicit globbing, and the README shows the pattern quoted so the shell does not expand it first.

```bash
$ lebab --replace src/js/ --transform arrow
$ lebab --replace 'src/js/**/*.jsx' --transform arrow
```

The README points to --help for the full list of values accepted by --transform. It does not document a dry-run flag, so the safe way to preview a directory-wide change is to copy the directory first, or to run the transform on one file with -o and compare by hand.

## Transform ordering is a real constraint, not a footnote

Several limitations in the README are really instructions about sequence. The arrow transform "can mess up prototype-based classes" and the README says to run the class transform first to prevent this. The for-of and for-each transforms require let or const variables, so the let transform has to run before them. The arrow-return transform only applies to arrow functions, so arrow has to run first.

That creates a dependency graph you have to respect, and it collides with the safety classification. The class transform is unsafe, yet it is supposed to run before arrow, which is safe. The let transform is unsafe and carries three documented bugs, yet for-of and for-each depend on it. In practice this means the recommended order pushes you through the risky transforms early, and the README's advice to apply one transform at a time and inspect the diff is doing a lot of work to compensate. If you were hoping to run only the safe transforms and skip the rest, expect to leave prototype-based classes and var declarations alone, because the safe transforms will either skip them or handle them worse.

## Where Lebab is the wrong tool

The commonjs transform is the clearest case of a rewrite that changes semantics rather than syntax. It converts var foo = require("foo") to import foo from "foo" and module.exports = <anything> to export default <anything>. ES modules and CommonJS modules do not share the same loading behaviour, and the README's own framing of the transform as unsafe acknowledges that the output is not guaranteed equivalent. Converting a Node package this way without also changing how it is consumed is a decision worth making deliberately.

There is also a class of codebase where Lebab simply should not run. Generated files, bundled output, and vendored dependencies are ES5 by construction; rewriting them produces diffs nobody reviews and code nobody maintains. The same applies to any file where the original formatting is load-bearing, such as source maps you intend to keep valid.

Finally, consider the maintenance signal. The last push to the repository was on 2026-04-01, and the most recent release listed is v3.2.7 from 2025-05-25. That is a project that still receives changes, but the release cadence is slow, and the open bugs listed in the README for the let transform are described as known limitations rather than fixed behaviour. Treat Lebab as a migration utility you run and then stop running, not as a dependency you build a pipeline around.

## How Lebab differs from Babel and from codemod tools

Babel is the obvious comparison and the README makes it directly: Lebab does the opposite. The difference is more than direction. Babel takes modern syntax and emits compatible output, which means it can afford to be conservative because the input is well-specified and the output is machine-readable. Lebab takes ES5, which is a superset of what older JavaScript could express, and has to guess which modern construct the author would have written. That guess is why the transforms are graded rather than uniform.

The closer alternative is a general-purpose codemod runner built on jscodeshift or a similar AST toolkit. Those give you a framework for writing your own transforms against your own codebase's conventions, at the cost of writing and testing the transforms yourself. Lebab ships a fixed set of transforms maintained by someone else, which is less work up front and less control over edge cases. If your ES5 code follows unusual patterns, the fixed set will either skip them or rewrite them in a way you would not have chosen, and the README's documented limitations are the places where that is most likely.

## Licence and the cost of keeping it around

Lebab is MIT licensed, per both the README badge and the license field in package.json. MIT permits use, modification and redistribution with the licence text retained, including in proprietary codebases. That is a permissive arrangement and, in a migration tool, it mostly matters if you fork the transforms to fix a documented bug yourself.

The upgrade cost is low in the ordinary sense because the package has few dependencies and they are long-established ones: commander, escope, espree, estraverse, f-matches, glob, lodash and recast. The hidden cost is different. Every transform you apply changes source that other people then maintain, and the README's unsafe transforms can introduce behaviour changes that no test suite will catch unless it already covers the affected paths. Budget review time proportional to the size of the diff, not to the size of the install.

## Conclusion

Adopt Lebab for codebases you own and can review file by file, and run the safe transforms first because the README treats arrow, for-of, arg-rest and obj-shorthand as near-equivalent rewrites. Do not point it at generated output, vendored dependencies or a repository you cannot diff carefully, and do not chain unsafe transforms such as let, class and commonjs in one pass. Before you commit anything, verify the transform order your code needs (the README says the class transform should run before arrow, and let before for-of), check the Node engine requirement of >=6, and confirm the diff on one file before running --replace over a directory.

## FAQ

### What does Lebab do to my JavaScript?

It transpiles ES5 code to ES6/ES7 syntax, doing the opposite of what Babel does. Transforms are applied individually with the --transform option, and the README recommends running one at a time and inspecting the diff.

### How do I install Lebab?

The README gives npm install -g lebab as the installation command. The package declares a bin entry named lebab and requires Node >=6.

### Which Lebab transforms are safe to run?

The README groups arrow, arrow-return, for-of, for-each, arg-rest, arg-spread, obj-method, obj-shorthand, no-strict, exponent and multi-var as safe, saying the result should be almost 100% equivalent. The let, class and commonjs transforms are listed as unsafe because they use heuristics or have known bugs.

### Can I run Lebab over a whole directory?

Yes. The README documents lebab --replace src/js/ --transform arrow for .js files, and notes that other extensions need explicit globbing such as 'src/js/**/*.jsx'. The README does not document a dry-run flag.

## Sources

- [lebab/lebab on GitHub](https://github.com/lebab/lebab)
- [License: MIT](https://github.com/lebab/lebab/blob/master/LICENSE)
- [Project website](https://lebab.github.io)
- [README](https://github.com/lebab/lebab/blob/master/README.md)
- [Releases](https://github.com/lebab/lebab/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/lebab-lebab
