"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 pluggable and configurable code transformer with built-in eslint
, babel plugins
and jscodeshift codemods
support for js
, jsx
typescript
and flow
files. It has a lot of transforms that will keep your codebase in a clean state transforming any code smell to readable code according to best practices.
- Why does this project exist?
- Installation
- Usage
- Architecture
- API
- Built-in transformations
- Plugins
- Formatters
- Configuration
- Plugins API
- Using Babel Plugins with Putout
- Using JSCodeshift Codemods with Putout
- Codemods
- Integration with ESLint
- Integration with Babel
- Using Putout as Loader
- Real-world uses
- Versioning policy
- Contributions
- Donations
- License
- because eslint avoids fixes that could change the runtime behavior;
- because babel produces throw-away code;
- because prettier is a formatter;
- because jscodeshift has no
config
andplugins
support;
Putout
on the other hand can make more drastic code transformations that directly alter your code base.
To install Putout
as a development dependency, run:
npm i putout -D
Or, for one-off usage, you can execute Putout
directly with npm's package executor: npx putout
.
Make sure that you are running a relatively recent (โฅ14.8) version of Node.
Usage: putout [options] [path]
Options
-h, --help display this help and exit
-v, --version output version information and exit
-f, --format use a specific output format - default: progress-bar/dump on CI
-s, --staged add staged files when in git repository
--fix apply fixes of errors to code
--fix-count count of fixes rounds (defaults to 10)
--rulesdir use additional rules from directory
--transform apply inline transform
--plugins plugins to use splited by comma
--enable enable rule by name in .putout.json
--disable disable rule by name in .putout.json
--enable-all enable all rules in .putout.json
--disable-all disable all rules in .putout.json
--match read .putout.json and convert "rules" to "match" using pattern
--flow enable flow
--no-flow disable flow (default)
--cache enable cache to speed up processing (default)
--fresh generate a fresh cache
--no-config avoid reading config file (.putout.json)
--no-ci disable CI detection
--no-cache disable cache
To find possible transform places:
npx putout lib test
To apply transforms:
npx putout lib test --fix
Putout
supports the following environment variables:
PUTOUT_FILES
- files that should be processed by putout, divided by ",";
Example:
PUTOUT_FILES=lib,test putout --fix
Putout
consists of a couple simple parts, here is a workflow representation:
And here is a CLI sheme:
Engines
is the heart of putout
: loader
, runner
and parser
run for every processed file. Processor
runs all the processors.
Package | Version | Dependencies |
---|---|---|
@putout/engine-parser |
||
@putout/engine-loader |
||
@putout/engine-runner |
||
@putout/engine-processor |
With help of processors putout
can be extended to read any file format and parse JavaScript
from there.
Here is a list of built-int processors:
Package | Version | Dependencies |
---|---|---|
@putout/processor-javascript |
||
@putout/processor-json |
||
@putout/processor-markdown |
||
@putout/processor-ignore |
||
@putout/processor-yaml |
||
@putout/processor-css |
You can disable any of them with:
{
"processors": [
["markdown", "off"]
]
}
And not bundled processors:
Package | Version | Dependencies |
---|---|---|
@putout/processor-typescript |
||
@putout/processor-html |
To enable it use:
{
"processors": [
["typescript", "on"]
]
}
Processors can be tested using @putout/test/processors.
First things first, require
putout:
const putout = require('putout');
Let's consider next source
with two variables
and one call expression
:
const hello = 'world';
const hi = 'there';
console.log(hello);
We can declare it as source
:
const source = `
const hello = 'world';
const hi = 'there';
console.log(hello);
`;
Putout supports dynamic loading of plugins from node_modules
. Let's consider example of using remove-unused-variables plugin:
putout(source, {
plugins: [
'remove-unused-variables',
],
});
// returns
({
code: "\n const hello = 'world';\n\n console.log(hello);\n",
places: [],
});
As you see places
is empty, but the code is changed: there is no hi
variable.
From the start, putout
was developed with ability to split the main process into two concepts: find
(find places that could be fixed) and fix
(apply the fixes to the files).
It is therefore easy to find sections that could be fixed.
In the following example reduntand variables are found without making changes to the source file:
putout(source, {
fix: false,
plugins: [
'remove-unused-variables',
],
});
// returns
({
code: '\n' +
" const hello = 'world';\n" +
" const hi = 'there';\n" +
' \n' +
' console.log(hello);\n',
places: [{
rule: 'remove-unused-variables',
message: '"hi" is defined but never used',
position: {line: 3, column: 10},
}],
});
remove unused variables
function show() {
- const message = 'hello';
console.log('hello world');
}
remove duplicates from logical expressions
-a && b && a
+a && b
remove unused for-of variables
-for (const {a, b} of c) {
+for (const {a} of c) {
console.log(a);
}
remove unreferenced variables
-let a;
- a = 1;
let b;
b = 2;
console.log(b);
remove duplicate keys
const a = {
- x: 'hello',
- ...y,
x: 'world',
...y,
}
remove duplicate case
switch (x) {
case 5:
console.log('hello');
break;
- case 5:
- console.log('zz');
- break;
}
remove unused private fields
class Hello {
#a = 5;
- #b = 3;
get() {
return this.#a;
};
}
remove unused expressions
function show(error) {
- showError;
}
remove useless variables
- function hi(a) {
- const b = a;
};
+ function hi(b) {
};
remove useless map
-const [str] = lines.map((line) => `hello ${line}`);
+const [line] = lines;
+const str = `hello ${line}`;
remove useless continue
+for (sign = decpt, i = 0; (sign /= 10) != 0; i++);
-for (sign = decpt, i = 0; (sign /= 10) != 0; i++)
- continue;
remove useless operand
-a = a + b;
+a += b;
remove useless return
-module.exports.traverse = ({push}) => {
- return {
- ObjectExpression(path) {
- }
- }
-};
+module.exports.traverse = ({push}) => ({
+ ObjectExpression(path) {
+ }
+});
remove useless array constructor
-const a = Array(1, 2, 3);
+const a = [1, 2, 3];
remove useless conditions
-if (zone?.tooltipCallback) {
- zone.tooltipCallback(e);
-}
+zone?.tooltipCallback(e);
remove useless type conversion
-const a = Boolean(b.includes(c));
+const a = b.includes(c);
--if (!!a)
++if (a)
console.log('hi');
remove useless functions
- const f = (...a) => fn(...a);
+ const f = fn;
remove useless typeof
- typeof typeof 'hello';
+ typeof 'hello';
remove useless await
- await await Promise.resolve('hello');
+ await Promise.resolve('hello');
remove useless async
-const show = async () => {
+const show = () => {
console.log('hello');
};
add missing await
-runCli();
+await runCli();
async function runCli() {
}
declare undefined variables
const fs = import 'fs/promises';
const {stub} = import 'supertape';
+const {assign} = Object;
const readFile = stub();
assign(fs, {
readFile,
});
remove useless arguments
onIfStatement({
push,
- generate,
- abc,
})
function onIfStatement({push}) {
}
remove useless template expressions
-let y = `${"hello"} + ${"world"}`;
+let y = `hello + world`;
remove useless for-of
-for (const a of ['hello']) {
- console.log(a);
-}
+console.log('hello');
reuse duplicateinit
const putout = require('putout');
-const {operator} = require('putout');
+const {operator} = putout;
convert assignment
to arrow function
-const createRegExp = (a) = RegExp(a, 'g');
+const createRegExp = (a) => RegExp(a, 'g');
convert assignment
to comparison
-if (a = 5) {
+if (a === 5) {
}
convert bitwise
to logical
-a | !b
+a || !b
convert equal
to strict equal
-if (a == b) {
+if (a === b) {
}
convert indexOf
to includes
-if (~array.indexOf(element)) {
+if (array.includes(element)) {
}
convert generic
to shorthand
(for typescript) (why)
interface A {
- x: Array<X>;
+ x: X[];
}
remove useless types
from constants
(for typescript)
-const x: any = 5;
+const x = 5;
remove useless mapped types
(for typescript)
-type SuperType = {
- [Key in keyof Type]: Type[Key]
-}
+type SuperType = Type;
remove useless mapping modifiers
(for typescript)
type SuperType = {
- +readonly[Key in keyof Type]+?: Type[Key];
+ readonly[Key in keyof Type]?: Type[Key];
}
convert fs.promises
to fs/promises
for node.js
-const {readFile} = require('fs').promises;
+const {readFile} = require('fs/promises');
remove useless types
(for typescript)
type oldType = number;
-type newType = oldType;
-const x: newType = 5;
+const x: oldType = 5;
remove duplicate interface
keys (for typescript)
interface Hello {
- 'hello': any;
'hello': string;
}
remove unused types
(for typescript)
type n = number;
-type s = string;
+const x: n = 5;
remove useless escape
-const t = 'hello \"world\"';
-const s1 = `hello \"world\"`;
-const s = `hello \'world\'`;
+const t = 'hello "world"';
+const s1 = `hello "world"`;
+const s = `hello 'world'`;
remove useless Array.from
-for (const x of Array.from(y)) {}
+for (const x of y) {}
remove useless spread
-for (const x of [...y]) {}
+for (const x of y) {}
remove useless Promise.resolve
async () => {
- return Promise.resolve('x');
+ return 'x';
}
convertPromise.reject
to throw
async () => {
- return Promise.reject('x');
+ throw 'x';
}
remove debugger
statement
- debugger;
remove iife
-(function() {
- console.log('hello world');
-}());
+console.log('hello world');
remove boolean
from assertions
-if (a === true)
+if (a)
alert();
remove boolean
from logical expressions
-const t = true && false;
+const t = false;
remove nested blocks
for (const x of Object.keys(a)) {
- {
- console.log(x);
- }
+ console.log(x);
}
remove unreachable code
function hi() {
return 5;
- console.log('hello');
}
replace test.only
with test
calls
-test.only('some test here', (t) => {
+test('some test here', (t) => {
t.end();
});
replace test.skip
with test
calls
-test.skip('some test here', (t) => {
+test('some test here', (t) => {
t.end();
});
remove process.exit
call
-process.exit();
split variable declarations
-let a, b;
+let a;
+let b;
split nested destructuring
-const {a: {b}} = c;
+const {a} = c;
+const {b} = a;
simplify assignment
-const {a} = {a: 5};
-const [b] = [5];
+const a = 5;
+const b = 5;
simplify logical expressions
-!(options && !options.bidirectional);
+!options || options.bidirectional;
simplify ternary
-module.exports = fs.copyFileSync ? fs.copyFileSync : copyFileSync;
+module.exports = fs.copyFileSync || copyFileSync;
remove console.log
calls
-console.log('hello');
remove empty block statements
-if (x > 0) {
-}
remove empty patterns
-const {} = process;
remove strict mode directive from esm
-'use strict';
-
import * from fs;
Add strict mode
directive in commonjs
if absent
+'use strict';
+
const fs = require('fs');
remove constant conditions
function hi(a) {
- if (2 < 3) {
- console.log('hello');
- console.log('world');
- }
+ console.log('hello');
+ console.log('world');
};
function world(a) {
- if (false) {
- console.log('hello');
- console.log('world');
- }
};
convert esm
to commonjs
(disabled)
-import hello from 'world';
+const hello = require('world');
convert commonjs
to esm
(disabled)
-const hello = require('world');
+import hello from 'world';
convert replace
to replaceAll
(disabled, stage-4)
-'hello'.replace(/hello/g, 'world');
+'hello'.replaceAll('hello', 'world');
apply destructuring
-const hello = world.hello;
-const a = b[0];
+const {hello} = world;
+const [a] = b;
apply if condition
-if (2 > 3);
+if (2 > 3)
alert();
apply isArray
-x instanceof Array;
+Array.isArray(x);
apply Array.at
(disabled)
-const latest = (a) => a[a.length - 1];
+const latest = (a) => a.at(-1);
apply top-level-await (proposal-top-level-await, enabled for ESM)
import fs from 'fs';
-(async () => {
- const data = await fs.promises.readFile('hello.txt');
-})();
+const data = await fs.promises.readFile('hello.txt');
apply numeric separators(proposal-numeric-separator)
-const a = 100000000;
+const a = 100_000_000;
apply optional chaining (proposal-optional-chaining)
-const result = hello && hello.world;
+const result = hello?.world;
apply as
type assertion (according to best practices, for typescript)
-const boundaryElement = <HTMLElement>e.target;
+const boundaryElement1 = e.target as HTMLElement;
apply nullish coalescing (proposal-nullish-coalescing, not bundled)
-result = typeof result === 'undefined' ? 'hello': result;
result = result ?? 'hello';
apply utility types (for typescript)
-type SuperType = {
- [Key in keyof Type]?: Type[Key];
-}
+type SuperType = Partial<Type>;
convert throw
statement into expression (proposal-throw-expressions, not bundled)
-const fn = (a) => {throw Error(a);}
+const fn = (a) => throw Error(a);
merge destructuring properties
-const {one} = require('numbers'):
-const {two} = require('numbers');
+ const {
+ one,
+ two
+} = require('numbers');
merge duplicate imports
-import {m as b} from 'y';
-import {z} from 'y';
-import x from 'y';
+import x, {m as b, z} from 'y';
merge if
statements
-if (a > b)
- if (b < c)
- console.log('hi');
+if (a > b && b < c)
+ console.log('hi');
convert Math.pow
to exponentiation operator
-Math.pow(2, 4);
+2 ** 4;
convert anonymous
to arrow function
-module.exports = function(a, b) {
+module.exports = (a, b) => {
}
convert for
to for-of
-for (let i = 0; i < items.length; i++) {
+for (const item of items) {
- const item = items[i];
log(item);
}
convert forEach
to for-of
-Object.keys(json).forEach((name) => {
+for (const name of Object.keys(json)) {
manage(name, json[name]);
-});
+}
convert for-in
to for-of
-for (const name in object) {
- if (object.hasOwnProperty(name)) {
+for (const name of Object.keys(object)) {
console.log(a);
- }
}
convert map
to for-of
-names.map((name) => {
+for (const name of names) {
alert(`hello ${name}`);
+}
-});
convert array copy
to slice
-const places = [
- ...items,
-];
+const places = items.slice();
extract sequence expressions
-module.exports.x = 1,
-module.exports.y = 2;
+module.exports.x = 1;
+module.exports.y = 2;
extract object properties into variable
-const {replace} = putout.operator;
-const {isIdentifier} = putout.types;
+const {operator, types} = putout;
+const {replace} = operator;
+const {isIdentifier} = types;
convert apply
to spread
-console.log.apply(console, arguments);
+console.log(...arguments);
convert concat
to flat
-[].concat(...array);
+array.flat();
convert arguments
to rest
-function hello() {
- console.log(arguments);
+function hello(...args) {
+ console.log(args);
}
convert Object.assign
to merge spread
function merge(a) {
- return Object.assign({}, a, {
- hello: 'world'
- });
+ return {
+ ...a,
+ hello: 'world'
+ };
};
convert comparison
to boolean
- const a = b === b;
+ const a = true;
convert top-level return
into process.exit()
(because EcmaScript Modules doesn't support top level return)
- return;
+ process.exit();
add await
to return promise()
statements (because it's faster, produces call stack and more readable)
async run () {
- return promise();
+ return await promise();
}
The putout
repo is comprised of many npm packages. It is a lerna monorepo similar to babel.
Package | Version | Dependencies |
---|---|---|
@putout/plugin-split-variable-declarations |
||
@putout/plugin-split-nested-destructuring |
Package | Version | Dependencies |
---|---|---|
@putout/plugin-merge-destructuring-properties |
||
@putout/plugin-merge-duplicate-imports |
||
@putout/plugin-merge-if-statements |
Package | Version | Dependencies |
---|---|---|
@putout/plugin-simplify-assignment |
||
@putout/plugin-simplify-logical-expressions |
||
@putout/plugin-simplify-ternary |
Next packages bundled in @putout/plugin-promises
.
Package | Version | Dependencies |
---|---|---|
@putout/plugin-add-return-await |
||
@putout/plugin-remove-useless-async |
||
@putout/plugin-remove-useless-await |
Next packages not bundled with putout
but can be installed separately.
putout
uses formatters similar to eslint's formatters.
You can specify a formatter using the --format
or -f
flag on the command line. For example, --format codeframe
uses the codeframe
formatter.
The built-in formatter options are:
dump
stream
json
json-lines
codeframe
progress
progress-bar
frame
(codeframe
+progress
)memory
A formatter function executes on every processed file, it should return an output string
.
module.exports = ({name, source, places, index, count, filesCount, errorsCount}) => {
return '';
};
Here is list of options:
name
- name of processed filesource
- source code of processed fileindex
- current indexcount
- processing files countfilesCount
- count of files with errorserrorsCount
count of errors
You can avoid any of this and use only what you nead. To make your formatter usable with putout
, add the prefix putout-formatter-
to your npm
package,
and add the tags putout
, formatter
, putout-formatter
.
eslint formatters
can be used as well with help of @putout/formatter-eslint
this way:
Install:
npm i putout @putout/formatter-eslint eslint-formatter-pretty -D
Run:
ESLINT_FORMATTER=pretty putout -f eslint lib
To configure putout
add section putout
to your package.json
file or create .putout.json
file and override any of default options.
All rules located in plugins
section and built-in rules are enabled by default.
You can disable rules using "off", or enable them (in match
section) using "on".
{
"rules": {
"remove-unused-variables": "off"
}
}
Or pass options using rules
section:
{
"rules": {
"remove-unused-variables": ["on", {
"exclude": "const global = __"
}]
}
}
With help of exclude
you can set type
or code pattern
to exclude for current rule.
Pass an array when you have a couple templates to exclude:
{
"rules": {
"remove-unused-variables": ["on", {
"exclude": [
"VariableDeclaration"
]
}]
}
}
exclude
is cross-plugin function supported by core, when develop your plugin, please use other name
to keep users ability to customize all plugins in a way they need to.
When you need to match paths to rules you can use match
section for this purpose in .putout.json
:
{
"match": {
"server": {
"remove-process-exit": "on"
}
}
}
When you need to ignore some routes no matter what, you can use ignore
section in .putout.json
:
{
"ignore": [
"test/fixture"
]
}
There are two types of plugins supported by putout
, their names in npm start with a prefix:
@putout/plugin-
for official pluginsputout-plugin-
for user plugins
Example
If you need to remove-something
create putout
plugin with a name putout-plugin-remove-something
and add it to .putout.json
:
{
"plugins": [
"remove-something"
]
}
Add putout
as a peerDependency
to your packages.json
(>= of version you developing for).
Always add keywords putout
, putout-plugin
when publish putout plugin to npm
so others can easily find it.
Let's consider a couple of plugin types that can be used.
The simplest putout
plugin type, consits of 2 functions:
report
- report error message toputout
cli;replace
- replacekey
template intovalue
template;
module.exports.report = () => 'use optional chaining';
module.exports.replace = () => ({
'__a && __a.__b': '__a?.__b',
});
This plugin will find and suggest to replace all occurrences of code: object && object.property
into object?.property
.
More powerful plugin type, when you need more control over traversing. It should contain next 2 functions:
report
- report error message toputout
cli;fix
- fixes paths usingplaces
array received usingfind
function;
and one or more of this:
filter
- filter path, should returntrue
, orfalse
(don't use withtraverse
);include
- returns array of templates, or node names to include;exclude
- returns array of templates, or node names to exclude;
module.exports.report = () => 'use optional chaining';
module.exports.include = () => [
'debugger',
];
module.exports.fix = (path) => {
path.remove(path);
};
More information about supported plugin types you can find at @putout/engine-runner. About the process of plugins loading you can find at @putout/engine-loader.
When you need, you can use @babel/types, template and generate. All of this can be gotten from putout
:
const {
types,
template,
generate,
} = require('putout');
Most information you can find in Babel Plugin Handbook is relevant to putout
plugins.
To understand how things works from the inside take a look at Super Tiny Compiler.
When you need to use replaceWith
, replaceWithMultiple
, or insertAfter
, please use operator
instead of path
-methods.
const {template, operator} = require('putout');
const {replaceWith} = operator;
const ast = template.ast(`
const str = 'hello';
`);
module.exports.fix = (path) => {
// wrong
path.replaceWith(ast);
// correct
replaceWith(path, ast);
};
This should be done to preserve loc
and comments
information, which is different in babel
and recast
. putout
will handle this case for you :),
just use the methods of operator
.
When you work on a plugin
or codemod
please add rule putout
into .putout.json
:
{
"rules": {
"putout": "on"
}
}
@putout/plugin-putout will handle plugin-specific cases for you :).
Let's consider simplest possible plugin for removing debugger statements
@putout/plugin-remove-debugger:
// this is a message to show in putout cli
module.exports.report = () => 'Unexpected "debugger" statement';
// let's find all "debugger" statements and replace them with ""
module.exports.replace = () => ({
debugger: '',
});
Visitor
used in traverse function
can be code template as well. So when you need to find module.exports = <something>
, you
can use:
module.exports.traverse = ({push}) => ({
'module.exports = __'(path) {
push(path);
},
});
Where __
is a placeholder for anything.
Remember: template key should be valid JavaScript, or Type name like in previous example.
You can also use include
and/or exclude
insead of traverse
and filter
(more sophisticated example):
// should be always used include/or exclude, when traverse not used
module.exports.include = () => [
'debugger',
];
// optional
module.exports.exclude = () => [
'console.log',
];
// optional
module.exports.filter = (path) => {
// do some checks
return true;
};
There is predefined placeholders:
__
- any code;"__"
- any string literal;__
- any template string literal;
That was the simplest module to remove debugger
statements in your code. Let's look how to test it using @putout/test:
const removeDebugger = require('..');
const test = require('@putout/test')(__dirname, {
'remove-debugger': removeDebugger,
});
// this is how we test that messages is correct
test('remove debugger: report', (t) => {
t.reportCode('debugger', 'Unexpected "debugger" statement');
t.end();
});
// stetement should be removed so result is empty
test('remove debugger: transformCode', (t) => {
t.transformCode('debugger', '');
t.end();
});
As you see test runner it is little bit extended supertape. To see a more sophisticated example look at @putout/remove-console.
If you don't want to publish a plugin
you developed, you can pass it to Putout
as an object
described earler. Here is how it can look like:
putout('const a = 5', {
plugins: [
['remove-unused-variables', require('@putout/plugin-remove-unused-variables')],
],
});
Where plugins
is an array
that contains [name, implementation]
tuples
.
You can add babel
to the plugins
section of .putout.json
with babel/
prefix.
You can disable a rule, or use a match in a similar way.
Remember to omit babel-plugin-
or @babel/plugin
: putout will set it up for you :)
Example
Let's add babel-plugin-transform-inline-consecutive-adds
to .putout.json
:
{
"plugins": [
"babel/transform-inline-consecutive-adds"
]
}
Then create a file and process it with the help of babel plugin
.
coderaiser@cloudcmd:~$ cat > a.js
const t = [];
t.push(1);
t.push(2);
coderaiser@cloudcmd:~$ putout a.js -f codeframe
/home/coderaiser/a.js:4:0
2 | t.push(1);
3 | t.push(2);
> 4 |
| ^ transform inline consecutive adds
โ 1 errors in 1 files
fixable with the `--fix` option
coderaiser@cloudcmd:~$ putout --fix a.js
coderaiser@cloudcmd:~$ cat a.js
const t = [1, 2];
Using putout
as a runner for babel
plugins
you can not only change file content, but also see what exactly will be changed. You can use your already written
babel
plugins
or reuse work in progress plugins made for babel
, but remember that putout
plugins
gave more accurate information about changing places, and works faster (no need to find information about changes in transformed file).
Here you can find babel plugins
which feets the most main purpose of putout
and advised to use:
transform-inline-consecutive-adds
-const foo = {};
-foo.a = 42;
-foo.b = ["hi"];
-foo.c = bar();
-foo.d = "str";
+const foo = {
+ a: 42,
+ b: ["hi"],
+ c: bar(),
+ d: "str"
+};
-const bar = [];
-bar.push(1);
-bar.push(2);
+const bar = [1, 2];
codemod-object-assign-to-object-spread
function merge(a) {
- return Object.assign({}, a, {
- hello: 'world'
- });
+ return {
+ ...a,
+ hello: 'world'
+ };
};
codemod-optional-catch-binding
try {
throw 0;
-} catch (err) {
+} catch {
console.log("it failed, but this code executes");
}
Please send pull requests with babel plugins
which can be used as codemods, or simplify, fix, makes code more readable.
jscodeshift
codemods can be added to plugins
section of .putout.json
with prefix jscodeshift/
. This way:
Example
{
"plugins": [
"jscodeshift/async-await-codemod"
]
}
Here you can find jscodeshift codemods
which feets the most main purpose of putout
and advised to use:
async-await-codemod
-function makeRequest() {
- return getJSON().then(data => {
- console.log(data);
- return 'done';
- });
+ async function makeRequest() {
+ const data = await getJSON();
+ console.log(data);
+ return 'done';
}
Please send pull requests with jscodeshift codemods
which can be used to simplify, fix, or make code more readable.
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 example of work.
If you see that putout
brokes formatting of your code, use eslint plugin eslint-plugin-putout.
Install eslint-plugin-putout
with:
npm i eslint eslint-plugin-putout -D
Then create .eslintrc.json
:
{
"extends": [
"plugin:putout/recommended"
],
"plugins": [
"putout"
]
}
And use with putout
this way:
putout --fix lib
To set custom eslint config file
use ESLINT_CONFIG_FILE
env variable:
ESLINT_CONFIG_FILE=test.eslintrc.json putout --fix lib
You can even use only eslint
, because putout
bundled to eslint-plugin-putout
with:
eslint --fix lib
Will uses putout transformations for you :).
Putout
can be used as babel plugin.
Just create .babelrc.json
file with configuration you need.
{
"plugins": [
["putout", {
"rules": {
"remove-unused-variables": "off"
}
}]
]
}
Putout
can be used as loader this way:
node --loader putout your-file.js
You can also transform input files using Babel
. For example if you need to transform jsx
with @babel/plugin-transform-react-jsx
you can use .putout.json
:
{
"plugins": [
"babel/transform-react-jsx"
]
}
- Cloud Commander: orthodox file manager for the web.
- Eslint Config Hardcore: The most strict (but practical) ESLint config out there.
- Mock Import: Mocking of Node.js EcmaScript Modules.
- Madrun: CLI tool to run multiple npm-scripts in a madly comfortable way.
- Xterm.js: A terminal for the web.
- Stylelint: A mighty, modern linter that helps you avoid errors and enforce conventions in your styles.
- ESTrace: Trace functions in EcmaScript Modules.
Do you use putout
in your application as well? Please open a Pull Request to include it here. We would love to have it in our list.
Putout
follows semantic versioning (semver) principles, with version numbers being on the format major.minor.patch:
- patch:
bug fix
,dependency update
(17.0.0 -> 17.0.1
). - minor:
new features
,new rules
orfixes
(17.0.0 -> 17.1.0
). - major
breaking changes
,removing rules
(17.0.0 -> 18.0.0
).
You can contribute by proposing a feature, fixing a bug or a typo in the documentation, or by making a donation ;).
putout
requires quite a lot of effort and time. If you like it, support us on patreon.
MIT