Traverser, scope tracker, and more tools for working with ESTree AST
npm install estree-toolkitestree-toolkit
bash
npm i estree-toolkit
or
yarn add estree-toolkit
`
Usage
`js
// Supports both CommonJS and ES Modules
// ES Module
import { traverse, builders as b } from 'estree-toolkit';
// CommonJS
const { traverse, builders: b } = require('estree-toolkit');
`
Basic operations
$3
`js
const { traverse } = require('estree-toolkit');
traverse(ast, {
Program(path) {
// Do something with the path
}
});
`
$3
`js
const { builders: b } = require('estree-toolkit');
b.identifier('x'); // => { type: 'Identifier', name: 'x' }
`
$3
`js
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' })) {
// left is an identifier with name x
}
}
});
`
$3
`js
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'));
}
}
});
// Now the AST represents - c = b
`
$3
`js
const { traverse } = require('estree-toolkit');
traverse(ast, {
// Enable scope
$: { scope: true },
Program(path) {
// path.scope is now available in all paths
}
});
`
#### Checking if a binding is available
`js
const { traverse } = require('estree-toolkit');
const { parseModule } = require('meriyah');
const ast = parseModule(
);
traverse(ast, {
$: { scope: true },
Program(path) {
path.scope.hasBinding('a') // => true
path.scope.hasBinding('b') // => true
path.scope.hasBinding('c') // => false
path.scope.hasBinding('d') // => true
path.scope.hasBinding('e') // => true
}
});
`
#### Getting all references of a binding
`js
const { traverse } = require('estree-toolkit');
const { parseModule } = require('meriyah');
const ast = parseModule(
);
traverse(ast, {
$: { scope: true },
Program(path) {
// Returns all the paths that reference the binding a
path.scope.getBinding('a').references // => [NodePath, NodePath, NodePath]
}
});
`
#### Checking if a global has been used
`js
const { traverse } = require('estree-toolkit');
const { parseModule } = require('meriyah');
const ast = parseModule(
);
traverse(ast, {
$: { scope: true },
Program(path) {
path.scope.hasGlobalBinding('require') // => true
}
});
`
#### Renaming a binding
`js
const { traverse } = require('estree-toolkit');
const { parseModule } = require('meriyah');
const ast = parseModule(
);
traverse(ast, {
$: { scope: true },
Program(path) {
// a -> b
path.scope.renameBinding('a', 'b')
}
});
// Output code:
// const b = 0
//
// b.reload()
// while (b.ok) b.run()
`
$3
There are several static utilities that you can use.
- evaluate\
Evaluates the given path.
`js
const { utils: u, traverse } = require('estree-toolkit');
// We are using meriyah but you can use any parser (like acorn)
const { parseModule } = require('meriyah');
traverse(parseModule(1 + 2), {
BinaryExpression(path) {
u.evaluate(path) // => { value: 3 }
}
});
traverse(parseModule(1 === 2), {
BinaryExpression(path) {
u.evaluate(path) // => { value: false }
}
});
traverse(parseModule(iDoNotKnowWhatThisIs === 55), {
BinaryExpression(path) {
u.evaluate(path) // => undefined
}
});
traverse(parseModule(
), {
ObjectExpression(path) {
u.evaluate(path) // => { value: { text: 'This is an object', data: [1, 'two'] } }
}
});
traverse(parseModule(1 > 5 ? 'YES' : 'NO'), {
ConditionalExpression(path) {
u.evaluate(path) // => { value: 'NO' }
}
});
`
- 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