@putout/engine-runner
Run 🐊Putout
plugins.
Install
npm i @putout/engine-runner
Supported Plugin Types
Replacer
Replacer
converts code in declarative way. Simplest possible form, no need to use fix
. Just from
and to
parts.
Simplest replace example:
module.exports.report = () => 'any message here';
module.exports.replace = () => ({
'const a = 1': 'const b = 1',
});
module.exports.filter = (path) => {
return true;
};
module.exports.match = () => ({
'const __a = 1': ({__a}) => {
return true;
},
});
module.exports.exclude = () => [
`const hello = 'world'`,
'ArrowFunctionExpression',
];
Simplest remove example:
module.exports.report = () => 'debugger should not be used';
module.exports.replace = () => ({
'debugger': '',
});
Templates:
module.exports.report = () => 'any message here';
module.exports.replace = () => ({
'var __a = 1': 'const __a = 1',
});
A couple variables example:
module.exports.report = () => 'any message here';
module.exports.replace = () => ({
'const __a = __b': 'const __b = __a',
});
Processing of node using functions
You can pass a function as object value for more soficticated processing.
Remove node:
module.exports.report = () => 'any message here';
module.exports.replace = () => ({
'for (const __a of __b) __c': ({__a, __b, __c}, path) => {
return '';
},
});
Update node:
module.exports.report = () => 'any message here';
module.exports.replace = () => ({
'for (const __a of __array) __c': ({__a, __array, __c}, path) => {
path.node.right.elements = [];
return path;
},
});
Update node using template variables:
module.exports.report = () => 'any message here';
module.exports.replace = () => ({
'for (const __a of __array) __c': ({__a, __array, __c}, path) => {
return 'for (const x of y) z';
},
});
Includer
includer
is the most preferable format of a plugin, simplest to use (after replacer
)
module.exports.report = () => 'debugger statement should not be used';
module.exports.fix = (path) => {
path.remove();
};
module.exports.include = () => [
'debugger',
];
module.exports.exclude = () => {
};
module.exports.filter = (path) => {
return true;
};
include
and exclude
returns an array of @babel/types, or code blocks:
const __ = 'hello';
Where __
can be any node. All this possible with help of @putout/compare. Templates format supported in traverse
and find
plugins as well.
Traverser
Traverse plugins
gives you more power to filter
and fix
nodes you need.
module.exports.report = () => 'debugger statement should not be used';
module.exports.fix = (path, {options}) => {
path.remove();
};
module.exports.traverse = ({push}) => ({
'debugger'(path) {
push(path);
},
});
listStore
To keep things during traverse in a safe way listStore
can be used.
module.exports.traverse = ({push, listStore}) => ({
'debugger'(path) {
listStore('x');
push(path);
},
Program: {
exit() {
console.log(listStore());
['x', 'x', 'x'];
'debugger; debugger; debugger';
},
},
});
store
is preferred way of keeping data, because of caching 🐊putout
, traverse
init function called only once, and any other way
of handling variables will most likely will lead to bugs.
Store
When you need key-value
storage store
can be used.
module.exports.traverse = ({push, store}) => ({
'debugger'(path) {
store('hello', 'world');
push(path);
},
Program: {
exit() {
store();
['world'];
store.entries();
[['hello', 'world']];
store('hello');
'world';
},
},
});
Upstore
When you need to update already saved values, use upstore
module.exports.traverse = ({push, store}) => ({
TSTypeAliasDeclaration(path) {
if (path.parentPath.isExportNamedDeclaration())
return;
store(path.node.id.name, {
path,
});
},
ObjectProperty(path) {
const {value} = path.node;
const {name} = value;
store(name, {
used: true,
});
},
Program: {
exit() {
for (const {path, used} of store()) {
if (used)
continue;
push(path);
}
},
},
});
ListStore
When you need to track list of elements, use listStore
:
module.exports.traverse = ({push, listStore}) => ({
ImportDeclaration(path) {
listStore(path);
},
Program: {
exit: () => {
processImports(push, listStore());
},
},
});
Finder
Find plugins
gives you all the control over traversing, but it's the slowest format.
Because traversers
not merged in contrast with other plugin formats.
module.exports.report = () => 'debugger statement should not be used';
module.exports.fix = (path) => {
path.remove();
};
module.exports.find = (ast, {push, traverse}) => {
traverse(ast, {
'debugger'(path) {
push(path);
},
});
};
Example
const {runPlugins} = require('@putout/engine-runner');
const {parse} = require('@putout/engin-parser');
const plugins = [{
rule: "remove-debugger",
msg: "",
options: {},
plugin: {
include: () => ['debugger'],
fix: (path) => path.remove(),
report: () => `debugger should not be used`,
},
}];
const ast = parse('const m = "hi"; debugger');
const places = runPlugins({
ast,
shebang: false,
fix: true,
fixCount: 1,
plugins,
parser: 'babel',
});
Logs
To see logs, use:
DEBUG=putout:runner:*
DEBUG=putout:runner:fix
DEBUG=putout:runner:find
DEBUG=putout:runner:template
License
MIT