putout
Version:
π Pluggable and configurable code transformer with built-in ESLint, Babel and support of js, jsx, typescript, flow, markdown, yaml and json
344 lines (271 loc) β’ 12.3 kB
Markdown
# Putout [![NPM version][NPMIMGURL]][NPMURL] [![Build Status][BuildStatusIMGURL]][BuildStatusURL] [![Coverage Status][CoverageIMGURL]][CoverageURL]
[NPMIMGURL]: https://img.shields.io/npm/v/putout.svg?style=flat&longCache=true
[BuildStatusIMGURL]: https://github.com/coderaiser/putout/workflows/Node%20CI/badge.svg
[NPMURL]: https://npmjs.org/package/putout "npm"
[BuildStatusURL]: https://github.com/coderaiser/putout/actions?query=workflow%3A%22Node+CI%22 "Build Status"
[CoverageURL]: https://coveralls.io/github/coderaiser/putout?branch=master
[CoverageIMGURL]: https://coveralls.io/repos/coderaiser/putout/badge.svg?branch=master&service=github
> **Perfection is finally attained not when there is no longer anything to add,
> but when there is no longer anything to take away.**
>
> **(c) Antoine de Saint ExupΓ©ry**

π**Putout** is a JavaScript Linter, pluggable and configurable code transformer, drop-in **ESLint** replacement with built-in [code printer](https://github.com/putoutjs/printer#readme) and ability to [fix syntax errors](https://github.com/coderaiser/putout/blob/master/docs/syntax-errors#%EF%B8%8F-syntax-errors). It has [a lot of transformations](https://github.com/coderaiser/putout#-built-in-transformations) that keeps your codebase in a clean state, removing any code smell and making code readable according to best practices.
The main target is **JavaScript**, but:
- β
JSX;
- β
TypeScript;
- β
Yaml;
- β
Markdown;
- β
JSON;
- β
Ignore;
are also supported. Here is how it looks like:
[](https://asciinema.org/a/0akg9gkJdbmbGl6BbpaycgKZm)
## π€·βοΈ In doubt about using πPutout?
Check out couple variants of plugins that does the same: [**linting debugger statement**](https://putout.cloudcmd.io/#/gist/f61ba31fe534868d49eba9b946f3ed4b/5ef6863d9cf4826666782ae0eea5cb5def266bbd):
- β SWCLint [no-debugger](https://github.com/swc-project/swc/blob/v1.2.138/crates/swc_ecma_lints/src/rules/no_debugger.rs): **49** lines;
- β RSLint [no-debugger](https://github.com/rslint/rslint/blob/v0.3.0/crates/rslint_core/src/groups/errors/no_debugger.rs): **48** lines;
- β ESLint [no-debugger](https://github.com/eslint/eslint/blob/2dc38aa653f1d5137a9abf82024c67a11620bb7c/lib/rules/no-debugger.js): **43** lines;
- β Rome [no-debugger](https://github.com/rome/tools/blob/4d5a99ce98e987cbd03f3ab6b38fa22d00bbfe27/packages/%40romejs/js-compiler/transforms/lint/noDebugger.ts): **28** lines;
- β
π**Putout** [remove-debugger](https://github.com/coderaiser/putout/blob/v24.6.0/packages/plugin-remove-debugger/lib/remove-debugger.js): **7** lines:
```js
'use strict';
module.exports.report = () => 'Unexpected "debugger" statement';
module.exports.replace = () => ({
debugger: '',
});
```
*Choose wisely, competitors cannot even fixβ¦* π€«
## π Whom should I thank for this project exist?
> **If I have seen further, it is by standing upon the shoulders of giants.**
>
> **(c) Isaak Newton**
- πͺ [**ESLint**](https://eslint.org) for stable releases and future proof `API`.
- πͺ [**Babel**](https://babeljs.io) for amazing `API` documented in [`Handbook`](https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md#babel-plugin-handbook) and responsiveness of a team.
- πͺ [**Prettier**](https://github.com/prettier/prettier) for minimalistic options and uniform codestyle.
- πͺ [**jscodeshift**](https://github.com/facebook/jscodeshift) for making codemods simple and popular.
## π€· Why does this project exist?
- β [**ESLint**](https://eslint.org) avoids [fixes that could change the runtime behavior](https://eslint.org/docs/developer-guide/working-with-rules#applying-fixes).
- β [**Babel**](https://babeljs.io) produces [throw-away code](https://github.com/babel/babel/issues/5139).
- β [**Prettier**](https://github.com/prettier/prettier) is a formatter.
- β [**jscodeshift**](https://github.com/facebook/jscodeshift) has no `config` and `plugins` support.
βοΈ *π**Putout** on the other hand can make more drastic code transformations that directly affects your codebase making it a better place to code π».*
[It can](https://github.com/coderaiser/putout#-built-in-transformations):
- β
remove unused `variables`;
- β
remove unused `for-of variables`;
- β
remove unused `typescripts` types;
- β
remove unreferenced `variables`;
- β
remove unused `private fields`;
- β
remove unused `expressions`;
- β
remove useless `variables`;
- β
remove useless `Object.assign()`;
- β
remove useless `replace()`;
- β
remove useless `map`;
- β
remove useless `mapped types`;
- β
remove useless `mapping modifiers`;
- β
remove useless `continue`;
- β
remove useless `operand`;
- β
remove useless `array constructor`;
- β
remove useless `conditions`;
- β
remove useless `type conversion`;
- β
remove useless `functions`;
- β
remove useless `Array.from`;
- β
remove useless `spread`;
- β
remove useless `arguments`;
- β
remove useless `escape`;
- β
remove useless `async`;
- β
remove useless `await`;
- β
remove useless `typeof`;
- β
remove useless `template expressions`;
- β
remove useless `for-of`;
- β
remove useless `array.entries()`;
- β
remove `debugger` statement;
- β
remove `iife`;
- β
remove nested blocks;
- β
remove `process.exit` call;
- β
remove `console.log` calls;
- β
remove `empty block statements`;
- β
remove `empty patterns`;
- β
remove `strict mode` directive from `esm`;
- β
remove `constant conditions`;
- β
remove `boolean` from `assertion`;
- β
remove `boolean` from `logical expressions`;
- β
remove `duplicates` from TypeScript `Union`;
- β
remove `unreachable code`;
- β
remove `duplicate keys`;
- β
remove useless `typescripts` types;
- β
remove duplicate `typescripts` interface keys;
- β
replace `test.only` to `test` calls;
- β
replace `test.skip` to `test` calls;
- β
reuse duplicate `init`;
- β
split `variable declarations`;
- β
split `nested destructuring`;
- β
simplify `assignment`;
- β
simplify `ternary`;
- β
simplify `logical expressions`;
- β
if absent `strict mode` directive in `commonjs` add it;
- β
convert `const` to `let` (when needed to avoid `TypeError`);
- β
convert `apply` to `spread`;
- β
convert `bitwise` to `logical` operator;
- β
convert `concat` to `flat`;
- β
convert `esm` to `commonjs` (enabled for `*.cjs`);
- β
convert `commonjs` to `esm` (enabled for `*.mjs`);
- β
convert `template` with one `expression` to `string`;
- β
convert `equal` to `strict equal`;
- β
convert `indexOf` to `includes`;
- β
convert `replace` to `replaceAll`;
- β
convert `assignment` to `arrow function`;
- β
convert `forEach` to `for...of`;
- β
convert `map` to `for...of`;
- β
convert `reduce` to `for...of`;
- β
convert `Math.sqrt()` to `Math.hypot()`;
- β
extract sequence expressions;
- β
extract object properties;
- β
add `return await`;
- β
remove useless `Promise.resolve`;
- β
convert `Promise.reject` to `throw`;
- β
declare before `reference`;
- β
declare `undefined variables`;
- β
declare `imports` first;
- β
apply `as` type assertions;
- β
apply `utility types`;
- β
apply `array.at`;
- β
apply `filter(Boolean)`;
- β
apply [isArray](https://web.mit.edu/jwalden/www/isArray.html);
- β
apply `if condition`;
- β
apply `await import`;
- β
apply comparison order;
- β
apply `flatMap()`;
- β
apply `template literals`;
- β
merge duplicate `imports`;
- β
merge duplicate `functions`;
## Install
```
npm i putout -D
```
## Usage
```
Usage: putout [options] [path]
Options:
-h, --help display this help and exit
-v, --version output version information and exit
-f, --format [formatter] use a specific output format, the default is: 'progress-bar' locally and 'dump' on CI
-s, --staged add staged files when in git repository
-i, --interactive set lint options using interactive menu
--fix apply fixes of errors to code
--fix-count [count = 10] count of fixes rounds
--rulesdir use additional rules from directory
--transform [replacer] apply Replacer, for example 'var __a = __b -> const __a = __b', read about Replacer https://git.io/JqcMn
--plugins [plugins] a comma-separated list of plugins to use
--enable [rule] enable the rule and save it to '.putout.json' walking up parent directories
--disable [rule] disable the rule and save it to '.putout.json' walking up parent directories
--enable-all enable all found rules and save them to '.putout.json' walking up parent directories
--disable-all disable all found rules (set baseline) and save them to '.putout.json' walking up parent directories
--match [pattern] read '.putout.json' and convert 'rules' to 'match' according to 'pattern'
--fresh generate a fresh cache
--no-config avoid reading '.putout.json'
--no-ci disable the CI detection
--no-cache disable the cache
--no-worker disable worker thread
```
To find errors:
```
putout lib test
```
To fix errors:
```
putout lib test --fix
```
## Plugins
By default π**Putout** uses all enabled by default plugins, anyways it can be run with a couple mentioned plugins (split with ","):
```sh
putout lib --plugins remove-debugger,remove-unused-variables
```
## Environment variables
π**Putout** supports next `environment variables`:
- `PUTOUT_FILES` - files that should be processed by putout, divided by ",";
- `PUTOUT_CONFIG_FILE` - path to π**Putout** config file;
- `ESLINT_CONFIG_FILE` - path to **ESLint** config file;
- `NO_ESLINT` - do not run **ESLint** after π**Putout**;
- `NO_ESLINT_WARNINGS` - do not show **ESLint** warnings;
```sh
PUTOUT_FILES=lib,test putout --fix
```
## Configuration
To configure create `.putout.json` file and override any of [default options](/packages/putout/putout.json).
### Match
When you need to match paths to rules you can use `match` section for this purpose in `.putout.json`:
```json
{
"match": {
"server": {
"remove-process-exit": true
}
}
}
```
### Ignore
When you need to ignore some routes no metter what, you can use `ignore` section in `.putout.json`:
```json
{
"ignore": ["test/fixture"]
}
```
## Plugins
π**Putout** supports two types of `plugins`, prefix with:
- β
`@putout/plugin-`;
- β
`putout-plugin-`;
To use your plugin create`npm` package with keywords `putout`, `putout-plugin` and add it to `.putout.json`.
For example if you need to `remove-something` create π[**Putout**](https://github.com/coderaiser/putout) plugin with name `putout-plugin-remove-something` and it to `package.json`:
```json
{
"plugins": ["remove-something"]
}
```
## Codemods
π**Putout** supports `codemodes` in the similar to plugins way, just create a directory `~/.putout` and put your plugins there. Here is example: [convert-tape-to-supertape](https://github.com/coderaiser/putout/tree/master/codemods/plugin-convert-tape-to-supertape) and [this is examples of work](https://github.com/coderaiser/putout/commit/ad02cebc344ce73cdee668cffc5078bf08830d52).
## API
All examples works both in **ESM** and **CommonJS**.
**CommonJS**:
```js
const putout = require('putout');
```
**ESM**:
```js
import {putout} from 'putout';
```
### putout(source, options)
```js
import {putout} from 'putout';
const source = `
const t = 'hello';
const m = t + '!';
console.log(t);
`;
putout(source, {
plugins: ['remove-unused-variables'],
});
// returns
`
const t = 'hello';
console.log(t);
`;
```
### putoutAsync(source, options)
```js
import {putoutAsync} from 'putout';
const source = `
const t = 'hello';
const m = t + '!';
console.log(t);
`;
await putoutAsync(source, {
plugins: ['remove-unused-variables'],
});
// returns
`
const t = 'hello';
console.log(t);
`;
```
## License
MIT