estree-toolkit
Tools for working with ESTree AST
Installation
npm i estree-toolkit
yarn add estree-toolkit
Usage
import { traverse, builders as b } from 'estree-toolkit';
const { traverse, builders: b } = require('estree-toolkit');
Basic operations
Traversing an AST
const { traverse } = require('estree-toolkit');
traverse(ast, {
Program(path) {
}
});
Building Nodes
const { builders: b } = require('estree-toolkit');
b.identifier('x');
Checking node types
const { traverse, is } = require('estree-toolkit');
const { parseModule } = require('meriyah');
const ast = parseModule(`x = 0`);
traverse(ast, {
AssignmentExpression(path) {
if (is.identifier(path.node.left, { name: 'x' })) {
}
}
});
Replacing a node
const { traverse, builders: b } = require('estree-toolkit');
const { parseModule } = require('meriyah');
const ast = parseModule('a = b');
traverse(ast, {
Identifier(path) {
if (path.node.name === 'a') {
path.replaceWith(b.identifier('c'));
}
}
});
Collecting scope information
const { traverse } = require('estree-toolkit');
traverse(ast, {
$: { scope: true },
Program(path) {
}
});
Checking if a binding is available
const { traverse } = require('estree-toolkit');
const { parseModule } = require('meriyah');
const ast = parseModule(`
import { a } from 'source';
const { b, c: [d, { e }] } = a;
`);
traverse(ast, {
$: { scope: true },
Program(path) {
path.scope.hasBinding('a')
path.scope.hasBinding('b')
path.scope.hasBinding('c')
path.scope.hasBinding('d')
path.scope.hasBinding('e')
}
});
Getting all references of a binding
const { traverse } = require('estree-toolkit');
const { parseModule } = require('meriyah');
const ast = parseModule(`
import { a } from 'source';
fn(a);
s = a;
let obj = { a };
`);
traverse(ast, {
$: { scope: true },
Program(path) {
path.scope.getBinding('a').references
}
});
Checking if a global has been used
const { traverse } = require('estree-toolkit');
const { parseModule } = require('meriyah');
const ast = parseModule(`
const fx = require('fx-mod');
`);
traverse(ast, {
$: { scope: true },
Program(path) {
path.scope.hasGlobalBinding('require')
}
});
Renaming a binding
const { traverse } = require('estree-toolkit');
const { parseModule } = require('meriyah');
const ast = parseModule(`
const a = 0
a.reload()
while (a.ok) a.run()
`);
traverse(ast, {
$: { scope: true },
Program(path) {
path.scope.renameBinding('a', 'b')
}
});
Utilities
There are several static utilities that you can use.
evaluate
Evaluates the given path.
const { utils: u, traverse } = require('estree-toolkit');
const { parseModule } = require('meriyah');
traverse(parseModule(`1 + 2`), {
BinaryExpression(path) {
u.evaluate(path)
}
});
traverse(parseModule(`1 === 2`), {
BinaryExpression(path) {
u.evaluate(path)
}
});
traverse(parseModule(`iDoNotKnowWhatThisIs === 55`), {
BinaryExpression(path) {
u.evaluate(path)
}
});
traverse(parseModule(`
({
text: 'This is an object',
data: [1, 'two']
})
`), {
ObjectExpression(path) {
u.evaluate(path)
}
});
traverse(parseModule(`1 > 5 ? 'YES' : 'NO'`), {
ConditionalExpression(path) {
u.evaluate(path)
}
});
evaluateTruthy
Evaluates the path for truthiness and returns true
, false
or undefined
depending on
evaluation result.
There's more functionalities, please read the documentation.
Documentation
You can find the documentation at https://estree-toolkit.netlify.app/
Why another traverser?
I know there is Babel. But there are
other tools which are faster than Babel. For example, meriyah
is 3x faster than @babel/parser
, astring
is up to 50x faster than @babel/generator
. But these tool only work with ESTree AST. I wanted to use these
faster alternatives for one of my projects but could not find any traverser with
batteries-included. So I built one myself, with awesome scope analysis, it has all the things that you would need for traversing an ESTree AST. Also, a little bit faster than Babel.
Need help?
If you need help in any kind of ESTree AST modification, then don't hesitate to open a new discussion in Q&A Discussions. I will try my best to help you :)
License
Licensed under the MIT License.