UNPKG

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
# 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](https://github.com/coderaiser/putout/blob/master/images/putout-logo.svg) 🐊**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: [![putout](https://asciinema.org/a/0akg9gkJdbmbGl6BbpaycgKZm.svg)](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