# 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;
  }
1
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;
  };
1
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
1
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);
1
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.

jscodeshift and recast relation image

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

  1. parse the source into an abstract syntax tree (AST),
  2. poke around to make your changes,
  3. 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
1

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
1

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();
  }
1
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;
1
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

See Tree Transformations References

Last Updated: 10 months ago