Prelim is an unused-code-removal tool for JavaScript.
It can take some source code like:
const bEnabled = false;
const { a, b } = { a: 'hi', b: 'bye' };
console.log(a);
if (bEnabled) {
console.log(b);
}
and transform it into:
const { a } = { a: 'hi' };
console.log(a);
We want to modify Prelim to support removing unused properties on js objects. That is, we want to support transforming:
const object1 = { a: 1, b: 2 };
console.log(object1.a);
into
const object1 = { a: 1 };
console.log(object1.a);
This sort of transformation is particularly usefor when paired with some CSS-in-JS libraries that make use of style objects, like React Native or Aphrodite. When using those libraries, a transformation like this can find unused styles and clean them up from the codebase.
When JavaScript is run, it is first transformed into a syntax tree: a tree of node objects describing the code from the point of view of JavaScript engine/compiler.
Check out astexplorer.net to see the above program as a syntax tree.
Prelim consists of a collection of Babel Visitors: objects with methods for handling different types of JavaScript syntax nodes. Check out src/visitors/unused-variables.js for an example visitor which removes unused variables.
Create a new visitor in src/visitors, and add it to the Core Visitor. Take a look at some of the other visitors in src/visitors to see what is possible, or check out the babel plugin handbook.
To help us, Babel has a pretty nice API for these sorts of queries and manipulations.
Here's a variety of the useful API information / helpers we might need:
class Binding {
// the variable identifier
identifier: node,
// the VariableDeclarator path where the variable is declared
path: path,
// Where the variable is used:
referencePaths: [path, path, path],
// Whether the variable is ever reassigned:
constant: false,
// ...
}
class NodePath {
// The Syntax Node (see astexplorer.net for properties)
node: node,
// The parent NodePath (useful for walking up the syntax tree)
parentPath: path,
// Get a child NodePath at the given key (see astexplorer.net for keys)
get(key)
// Is this path's node an identifier?
isIdentifier()
// Is this path's node an object literal?
isObjectExpression()
// is this path's node a MemberExpression (`obj.prop` or `obj[propName]`)
isMemberExpression()
// Remove this path from the tree
remove()
// ...
}
Tests are found in src/visitors/tests/
and can be run with jest or via npm test