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 and ability to fix syntax errors. It has a lot of 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;
- ✅ Flow;
- ✅ Yaml;
- ✅ Markdown;
- ✅ JSON;
- ✅ Ignore;
are also supported. Here is how it looks like:
Check out couple variants of plugins that does the same: linting debugger statement:
- ❌ SWCLint no-debugger: 49 lines;
- ❌ RSLint no-debugger: 48 lines;
- ❌ ESLint no-debugger: 43 lines;
- ❌ Rome no-debugger: 28 lines;
- ✅ 🐊Putout remove-debugger: 7 lines:
'use strict';
module.exports.report = () => 'Unexpected "debugger" statement';
module.exports.replace = () => ({
debugger: '',
});
Choose wisely, competitors cannot even fix… 🤫
If I have seen further, it is by standing upon the shoulders of giants.
(c) Isaak Newton
- 💪 ESLint for stable releases and future proof
API
. - 💪 Babel for amazing
API
documented inHandbook
and responsiveness of a team. - 💪 Prettier for minimalistic options and uniform codestyle.
- 💪 jscodeshift for making codemods simple and popular.
- ❌ ESLint avoids fixes that could change the runtime behavior.
- ❌ Babel produces throw-away code.
- ❌ Prettier is a formatter.
- ❌ jscodeshift has no
config
andplugins
support.
☝️ 🐊Putout on the other hand can make more drastic code transformations that directly affects your codebase making it a better place to code 💻.
- ✅ 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 fromesm
; - ✅ remove
constant conditions
; - ✅ remove
boolean
fromassertion
; - ✅ remove
boolean
fromlogical expressions
; - ✅ remove
duplicates
from TypeScriptUnion
; - ✅ remove
unreachable code
; - ✅ remove
duplicate keys
; - ✅ remove useless
typescripts
types; - ✅ remove duplicate
typescripts
interface keys; - ✅ replace
test.only
totest
calls; - ✅ replace
test.skip
totest
calls; - ✅ reuse duplicate
init
; - ✅ split
variable declarations
; - ✅ split
nested destructuring
; - ✅ simplify
assignment
; - ✅ simplify
ternary
; - ✅ simplify
logical expressions
; - ✅ if absent
strict mode
directive incommonjs
add it; - ✅ convert
const
tolet
(when needed to avoidTypeError
); - ✅ convert
apply
tospread
; - ✅ convert
bitwise
tological
operator; - ✅ convert
concat
toflat
; - ✅ convert
esm
tocommonjs
(enabled for*.cjs
); - ✅ convert
commonjs
toesm
(enabled for*.mjs
); - ✅ convert
template
with oneexpression
tostring
; - ✅ convert
equal
tostrict equal
; - ✅ convert
indexOf
toincludes
; - ✅ convert
replace
toreplaceAll
; - ✅ convert
assignment
toarrow function
; - ✅ convert
forEach
tofor...of
; - ✅ convert
map
tofor...of
; - ✅ convert
reduce
tofor...of
; - ✅ convert
Math.sqrt()
toMath.hypot()
; - ✅ extract sequence expressions;
- ✅ extract object properties;
- ✅ add
return await
; - ✅ remove useless
Promise.resolve
; - ✅ convert
Promise.reject
tothrow
; - ✅ declare before
reference
; - ✅ declare
undefined variables
; - ✅ declare
imports
first; - ✅ apply
as
type assertions; - ✅ apply
utility types
; - ✅ apply
array.at
; - ✅ apply
filter(Boolean)
; - ✅ apply isArray;
- ✅ apply
if condition
; - ✅ apply
await import
; - ✅ apply comparison order;
- ✅ apply
flatMap()
; - ✅ apply
template literals
; - ✅ merge duplicate
imports
; - ✅ merge duplicate
functions
;
npm i putout -D
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'
--flow enable flow
--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
By default 🐊Putout uses all enabled by default plugins, anyways it can be run with a couple mentioned plugins (split with ","):
putout lib --plugins remove-debugger,remove-unused-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;PUTOUT_PRINTER
- force 🐊Putout to use printers likebabel
,putout
andrecast
toparse()
andprint()
, useful for Babel Plugins to make locations output more accurate.
PUTOUT_FILES=lib,test putout --fix
To configure create .putout.json
file and override any of default options.
When you need to match paths to rules you can use match
section for this purpose in .putout.json
:
{
"match": {
"server": {
"remove-process-exit": true
}
}
}
When you need to ignore some routes no metter what, you can use ignore
section in .putout.json
:
{
"ignore": ["test/fixture"]
}
🐊Putout supports two types of plugins
, prefix with:
- ✅
@putout/plugin-
; - ✅
putout-plugin-
;
To use your plugin createnpm
package with keywords putout
, putout-plugin
and add it to .putout.json
.
For example if you need to remove-something
create 🐊Putout plugin with name putout-plugin-remove-something
and it to package.json
:
{
"plugins": ["remove-something"]
}
🐊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 and this is examples of work.
const putout = require('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);
`;
const {putoutAsync} = require('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);
`;
MIT