# Recast and JSCodeShift
# Recast
Recast is a library for parsing and modifying JavaScript code written on top of esprima and ast-types (opens new window). Recast provides methods for pretty printing ASTs as well as API to construct new ASTs without parsing any source code.
See the examples in /crguezl/hello-jscodeshift/hello-recast.js (opens new window)
This code example (opens new window) takes as input the code
function add(a, b) {
return a - b;
}
2
3
and just for fun switches the parameters a
and b
and converts the function add
declaration in a function expression:
➜ hello-jscodeshift git:(master) ✗ node hello-recast.js
var add = function(b, a) {
return a - b;
};
2
3
4
5
Here is the code:
const recast = require("recast");
const code = `
function add(a, b) {
return a - b;
}
`;
const ast = recast.parse(code);
const add = ast.program.body[0]; // The node of the add function declaration
2
3
4
5
6
7
8
See the module ast-types (opens new window) (especially the file def/core.ts (opens new window)) module for a thorough overview of the ast
API.
const n = recast.types.namedTypes;
n.FunctionDeclaration.assert(add);
// If you choose to use recast.builders to construct new AST nodes, all builder
// arguments will be dynamically type-checked against the Mozilla Parser API.
const B = recast.types.builders;
// This kind of manipulation should seem familiar if you've used Esprima or the
// Mozilla Parser API before.
ast.program.body[0] = B.variableDeclaration("var", [
B.variableDeclarator(add.id, B.functionExpression(
null, // Anonymize the function expression.
add.params,
add.body
))
]);
// Just for fun, because addition is commutative:
add.params.push(add.params.shift());
const output = recast.print(ast).code;
console.log(output);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# JSCodeshift
JSCodeshift is a toolkit for running codemods over multiple JavaScript or TypeScript files. The interface that jscodeshift provides is a wrapper around recast and ast-types (opens new window) packages.
The jscodeshift toolkit allows you to pump a bunch of source files through a transform and replace them with what comes out the other end.
Inside the transform, you
- parse the source into an abstract syntax tree (AST),
- poke around to make your changes,
- then regenerate the source from the altered AST.
The interface that jscodeshift provides is a wrapper around recast (opens new window) and ast-types (opens new window) packages. recast (opens new window) handles the conversion from source to AST and back while ast-types (opens new window) handles the low-level interaction with the AST nodes.
jscodeshift -t some-transform.js input-file.js -d -p
This will run input-file.js
through the transform some-transform.js
and
print the results without altering the file.
We can install it globally:
$ npm install -g jscodeshift
For example, the following transformation in file hello-jscodeshift.js:
module.exports = function(fileInfo, api, options) {
return api.jscodeshift(fileInfo.source)
.findVariableDeclarators('foo')
.renameTo('bar')
.toSource();
}
2
3
4
5
6
Changes all the apearances of variable foo
to bar
. See the following execution:
➜ hello-jscodeshift git:(master) ✗ cat foo.js
var foo = 4;%
➜ hello-jscodeshift git:(master) ✗ jscodeshift -t hello-jscodeshift.js foo.js
Processing 1 files...
Spawning 1 workers...
Sending 1 files to free worker...
All done.
Results:
0 errors
0 unmodified
0 skipped
1 ok
Time elapsed: 0.947seconds
➜ hello-jscodeshift git:(master) ✗ cat foo.js
var bar = 4;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Continue now reading the section Facebook jscodeshift
# References
More on JSCodeshift in the article Write Code to Rewrite Your Code: jscodeshift (opens new window) by Jeremy Greer