These are basic utilities that you can use as helper functions
const { utils: u } = require('estree-toolkit');
evaluate(path)
path
: <NodePath
> The path that you want to evaluate{ value: any } | undefined
The evaluation resultEvaluates the given path and returns the evaluated result. If it's sure
about the evaluation it would return an object with the evaluated value stored
in value
property. If it's not sure about the evaluation it would return undefined
.
These AST Nodes are supported for now
Identifier
- with undefined
as valueLiteral
BinaryExpression
- except instanceof
operatorUnaryExpression
- except delete
operatorLogicalExpression
ObjectExpression
ArrayExpression
const { utils: u, traverse } = require('estree-toolkit');
const { parseModule } = require('meriyah');
traverse(parseModule(`undefined`), {
Identifier(path) {
u.evaluate(path) // => { value: undefined }
}
});
traverse(parseModule(`'some string'`), {
Literal(path) {
u.evaluate(path) // => { value: 'some string' }
}
});
traverse(parseModule(`1 + 2`), {
BinaryExpression(path) {
u.evaluate(path) // => { value: 3 }
}
});
traverse(parseModule(`!(1 === 2)`), {
UnaryExpression(path) {
u.evaluate(path) // => { value: true }
}
});
traverse(parseModule(`false && unknown`), {
LogicalExpression(path) {
u.evaluate(path) // => { value: false }
}
});
traverse(parseModule(`
({ a: 1, b: 2, m: { c: 1 } })
`), {
ObjectExpression(path) {
if (path.parent.type !== 'ExpressionStatement') return;
u.evaluate(path) // => { value: { a: 1, b: 2, m: { c: 1 } } }
}
});
traverse(parseModule(`[1, 2, '3']`), {
ArrayExpression(path) {
u.evaluate(path) // => { value: [1, 2, '3'] }
}
});
// Whenever unknown binding is involved, it returns `undefined`
traverse(parseModule(`unknownVariable`), {
Identifier(path) {
u.evaluate(path) // => undefined
}
});
traverse(parseModule(`unknownVariable === 55`), {
BinaryExpression(path) {
u.evaluate(path) // => undefined
}
});
evaluateTruthy(path)
path
: <NodePath
> The path that you want to evaluatetrue | false | undefined
The evaluation resultIt's just like evaluate(path)
but it evaluates for truthiness. It returns true
or false
depending on the evaluation result, if it's sure. If it's not sure, it would return undefined
.
const { utils: u, traverse } = require('estree-toolkit');
const { parseModule } = require('meriyah');
traverse(parseModule(`false && unknown`), {
LogicalExpression(path) {
u.evaluateTruthy(path) // => false
}
});
traverse(parseModule(`true || unknown`), {
LogicalExpression(path) {
u.evaluateTruthy(path) // => true
}
});
traverse(parseModule(`!0`), {
UnaryExpression(path) {
u.evaluateTruthy(path) // => true
}
});
hasBinding(path, name)
path
: <NodePath
> The path from where the searching should startname
: <string
> The name of the bindingboolean
If the binding is available in the current positionYou can easily track scopes by enabling Scope
when traversing.
But if you need to check if a binding is available only one or two times, using Scope
can be
overkill, because scope builds all the graphs that you may not need. So using hasBinding
in this
case would be more preferable.
This function starts walking up the tree from the path
and finds if there is any binding
with the provided name. If there is any binding it returns true
, if not then it returns false
.
const { utils: u, traverse } = require('estree-toolkit');
const { parseModule } = require('meriyah');
const ast = parseModule(`
{
let a;
{
id1;
}
}
id2;
`);
traverse(ast, {
Identifier(path) {
if (path.node.name === 'id1') {
u.hasBinding(path, 'a') // => true
} else if (path.node.name === 'id2') {
u.hasBinding(path, 'a') // => false
}
}
});
getCommonAncestor(paths)
paths
: <NodePath[]
> The paths for which the ancestor should be commonNodePath
> The NodePath of the ancestorFinds the closest common parent (or ancestor) for all the provided paths