estree-toolkit
Version:
Traverser, scope tracker, and more tools for working with ESTree AST
898 lines (837 loc) • 19.5 kB
TypeScript
/** This interface documents each field of a NodePath. */
export interface NodePathDocs {
/** The node associated with the current path */
node: any;
/** Type of the node that is associated with this path */
type: any;
/**
The current node's key in its parent
___Example___
```
const ast = {
type: 'IfStatement',
test: {
type: 'Identifier',
name: 'targetNode'
},
consequent: {
type: 'EmptyStatement'
},
alternate: null
};
traverse(ast, {
Identifier(path) {
if (path.node.name === 'targetNode') {
path.key === 'test' // => true
}
}
});
```
*/
key: any;
/**
If this node is part of an array, `listKey` would be the key of the array in its parent
___Example___
```
const ast = {
type: 'ArrayExpression',
elements: [
{
type: 'Identifier',
name: 'targetNode'
}
]
};
traverse(ast, {
Identifier(path) {
if (path.node.name === 'targetNode') {
path.listKey === 'elements' // => true
path.key === 0 // => true
}
}
});
```
*/
listKey: any;
/** If the node has been removed from its parent */
removed: any;
/** The parent path of the current path */
parentPath: any;
/** The parent node of the current path */
parent: any;
/**
Container of the node
___Example 1___ - In this case `container` is an array
```
const ast = {
type: 'ArrayExpression',
elements: [
{
type: 'Identifier',
name: 'targetNode'
}
]
};
traverse(ast, {
Identifier(path) {
if (path.node.name === 'targetNode') {
path.container === ast.elements // => true
}
}
});
```
___Example 2___ - In this case `container` is a node object
```
const ast = {
type: 'IfStatement',
test: {
type: 'Identifier',
name: 'targetNode'
},
consequent: {
type: 'EmptyStatement'
},
alternate: null
};
traverse(ast, {
Identifier(path) {
if (path.node.name === 'targetNode') {
path.container === ast // => true
}
}
});
```
*/
container: any;
/** Clone the node associated with the current nodepath */
cloneNode: any;
/**
Skip the path from traversal
___Example___
```
const ast = {
type: 'IfStatement',
test: {
type: 'Identifier',
name: 'targetNode'
},
consequent: {
type: 'EmptyStatement'
},
alternate: null
};
traverse(ast, {
IfStatement(path) {
path.get('test').skip();
},
Identifier() {
// Never gets called because the path has been skipped
}
});
```
*/
skip: any;
/** Skip all children. Note: Grandchildren are not skipped */
skipChildren: any;
/**
Un-skip the path from traversal. Whenever un-skipped, the path would be
traversed if it's not already traversed
*/
unSkip: any;
/** Alias of `unSkip` */
unskip: any;
/** Un-skip all children. Opposite of skipChildren */
unSkipChildren: any;
/** Alias of `unSkipChildren` */
unskipChildren: any;
/** Traverse this path and its children with the given `visitor` and `state` */
traverse: any;
/**
Starting at the parent path of this path and going up the tree,
returns first parent path where `predicate` is true
___Example___
```
const ast = {
type: 'BlockStatement',
body: [
{
type: 'BlockStatement',
body: [
{
type: 'ExpressionStatement',
expression: {
type: 'Literal',
value: 0
}
}
]
}
]
};
traverse(ast, {
Literal(path) {
const blockParent = path.findParent(
(parent) => parent.type === 'BlockStatement'
).node;
blockParent === ast.body[0] // => true, Notice how it is not `ast` and is `ast.body[0]`
}
});
```
*/
findParent: any;
/**
Starting from **this** path and going up the tree,
returns the first path where `predicate` is true
___Example___
```
const ast = {
type: 'ExpressionStatement',
expression: {
type: 'Literal',
value: 0
}
};
traverse(ast, {
Literal(path) {
path.find((p) => p.type === 'Literal').node === ast.expression // => true
path.find((p) => p.type === 'ExpressionStatement').node === ast // => true
}
});
```
*/
find: any;
/** Get the closest function parent */
getFunctionParent: any;
/** Get all the ancestors. Returns an array. __THIS NODE IS INCLUDED__ */
getAncestry: any;
/** Checks if the path is ancestor of the given path */
isAncestorOf: any;
/** Checks if the path is descendant of the given path */
isDescendantOf: any;
/**
Inserts the `nodes` before the current node
___Example___
```
const ast = {
type: 'ArrayExpression',
elements: [
{
type: 'Identifier',
name: 'targetNode'
}
]
};
traverse(ast, {
Identifier(path) {
if (path.node.name === 'targetNode') {
const newPaths = path.insertBefore([
{
type: 'Literal',
value: 1
},
{
type: 'Literal',
value: 2
}
]);
// `newPaths` are the paths for the inserted nodes
}
}
});
assert.deepEqual(ast, {
type: 'ArrayExpression',
elements: [
{
type: 'Literal',
value: 1
},
{
type: 'Literal',
value: 2
},
{
type: 'Identifier',
name: 'targetNode'
}
]
});
```
*/
insertBefore: any;
/**
Inserts the `nodes` after the current node
___Example___
```
const ast = {
type: 'ArrayExpression',
elements: [
{
type: 'Identifier',
name: 'targetNode'
}
]
};
traverse(ast, {
Identifier(path) {
if (path.node.name === 'targetNode') {
const newPaths = path.insertAfter([
{
type: 'Literal',
value: 1
},
{
type: 'Literal',
value: 2
}
]);
// `newPaths` are the paths for the inserted nodes
}
}
});
assert.deepEqual(ast, {
type: 'ArrayExpression',
elements: [
{
type: 'Identifier',
name: 'targetNode'
},
{
type: 'Literal',
value: 1
},
{
type: 'Literal',
value: 2
}
]
});
```
*/
insertAfter: any;
/**
Inserts child nodes at the start of the container
___Example___
```
const ast = {
type: 'ArrayExpression',
elements: [
{
type: 'Identifier',
name: 'undefined'
}
]
};
traverse(ast, {
ArrayExpression(path) {
const newPaths = path.unshiftContainer('elements', [
{
type: 'Literal',
value: 1
},
{
type: 'Literal',
value: 2
}
]);
// `newPaths` are the paths for the inserted nodes
}
});
assert.deepEqual(ast, {
type: 'ArrayExpression',
elements: [
{
type: 'Literal',
value: 1
},
{
type: 'Literal',
value: 2
},
{
type: 'Identifier',
name: 'undefined'
}
]
});
```
*/
unshiftContainer: any;
/**
Inserts the child nodes at the end of the container
___Example___
```
const ast = {
type: 'ArrayExpression',
elements: [
{
type: 'Identifier',
name: 'undefined'
}
]
};
traverse(ast, {
ArrayExpression(path) {
const newPaths = path.pushContainer('elements', [
{
type: 'Literal',
value: 1
},
{
type: 'Literal',
value: 2
}
]);
// `newPaths` are the paths for the inserted nodes
}
});
assert.deepEqual(ast, {
type: 'ArrayExpression',
elements: [
{
type: 'Identifier',
name: 'undefined'
},
{
type: 'Literal',
value: 1
},
{
type: 'Literal',
value: 2
}
]
});
```
*/
pushContainer: any;
/**
Get the children's path for which the key is `key`
___Example___
```
const ast = {
type: 'IfStatement',
test: {
type: 'Identifier',
name: 'targetNode'
},
consequent: {
type: 'EmptyStatement'
},
alternate: null
};
traverse(ast, {
IfStatement(path) {
const testPath = path.get('test');
testPath.node === ast.test // => true
}
});
```
*/
get: any;
/**
Get the path of its sibling for which the key is `key`
___Example___
```
const ast = {
type: 'ArrayExpression',
elements: [
{
type: 'Identifier',
name: 'targetNode'
},
{
type: 'Literal',
value: 16
},
{
type: 'Literal',
value: 5
}
]
};
traverse(ast, {
Identifier(path) {
if (path.node.name === 'targetNode') {
path.getSibling(2).node === ast.elements[2] // => true
}
}
});
```
*/
getSibling: any;
/**
Get the opposite path of the current path
___Example___
```
const ast = {
type: 'AssignmentExpression',
left: {
type: 'Identifier',
name: 'a'
},
operator: '=',
right: {
type: 'Identifier',
name: 'b'
}
};
traverse(ast, {
Identifier(path) {
if (path.key === 'left') {
path.getOpposite().node === ast.right // => true
}
}
});
```
*/
getOpposite: any;
/**
The the previous sibling's path of the current path
___Example___
```
const ast = {
type: 'ArrayExpression',
elements: [
{
type: 'Literal',
value: 16
},
{
type: 'Identifier',
name: 'targetNode'
},
{
type: 'Literal',
value: 5
}
]
};
traverse(ast, {
Identifier(path) {
if (path.node.name === 'targetNode') {
path.getPrevSibling().node === ast.elements[0] // => true
}
}
});
```
*/
getPrevSibling: any;
/**
The the next sibling's path of the current path
___Example___
```
const ast = {
type: 'ArrayExpression',
elements: [
{
type: 'Literal',
value: 16
},
{
type: 'Identifier',
name: 'targetNode'
},
{
type: 'Literal',
value: 5
}
]
};
traverse(ast, {
Identifier(path) {
if (path.node.name === 'targetNode') {
path.getNextSibling().node === ast.elements[2] // => true
}
}
});
```
*/
getNextSibling: any;
/**
Get all previous siblings' path of the current path\
__NOTE__: Returned paths are reversed (they are sorted in how close
they are to the current path, see example)
___Example___
```
const ast = {
type: 'ArrayExpression',
elements: [
{
type: 'Literal',
value: 1
},
{
type: 'Literal',
value: 2
},
{
type: 'Identifier',
name: 'targetNode'
},
{
type: 'Literal',
value: 3
},
{
type: 'Literal',
value: 4
}
]
};
traverse(ast, {
Identifier(path) {
if (path.node.name === 'targetNode') {
const prevPaths = path.getAllPrevSiblings();
prevPaths[0].node === ast.elements[1] // => true
prevPaths[1].node === ast.elements[0] // => true
}
}
});
```
*/
getAllPrevSiblings: any;
/**
Get all next siblings' path of the current path
___Example___
```
const ast = {
type: 'ArrayExpression',
elements: [
{
type: 'Literal',
value: 1
},
{
type: 'Literal',
value: 2
},
{
type: 'Identifier',
name: 'targetNode'
},
{
type: 'Literal',
value: 3
},
{
type: 'Literal',
value: 4
}
]
};
traverse(ast, {
Identifier(path) {
if (path.node.name === 'targetNode') {
const nextPaths = path.getAllNextSiblings();
nextPaths[0].node === ast.elements[3] // => true
nextPaths[1].node === ast.elements[4] // => true
}
}
});
```
*/
getAllNextSiblings: any;
/**
Checks if the path has the specific property.
If value of the property is an array, checks if the array is not empty.
___Example - 1___
```
const ast = {
type: 'IfStatement',
test: {
type: 'Identifier',
name: 'x'
},
consequent: {
type: 'EmptyStatement'
},
alternate: null
};
traverse(ast, {
IfStatement(path) {
path.has('consequent') // => true
path.has('alternate') // => false
}
});
```
___Example - 2___
```
const ast1 = {
type: 'Program',
sourceType: 'module',
body: []
};
traverse(ast1, {
Program(path) {
path.has('body') // => false
// Because the array is empty
}
});
const ast2 = {
type: 'Program',
sourceType: 'module',
body: [
{
type: 'EmptyStatement'
}
]
};
traverse(ast2, {
Program(path) {
path.has('body') // => true
// In this case the array is not empty
}
});
```
*/
has: any;
/**
Checks if path _is_ something
___Example___
```
const ast = {
type: 'ObjectExpression',
properties: [
{
type: 'Property',
key: {
type: 'Identifier',
name: 'x'
},
value: {
type: 'Identifier',
name: 'x'
},
kind: 'init',
computed: false,
method: false,
shorthand: true
}
]
};
traverse(ast, {
Property(path) {
if (path.node === ast.properties[0]) {
path.is('shorthand') // => true
path.is('method') // => false
}
}
});
```
*/
is: any;
/** Removes the path from its parent */
remove: any;
/**
Removes the old node and inserts the new node in the old node's position
___Example___
```
const ast = {
type: 'AssignmentExpression',
left: {
type: 'Identifier',
name: 'targetNode'
},
operator: '=',
right: {
type: 'Identifier',
name: 'b'
}
};
traverse(ast, {
Identifier(path) {
if (path.node.name === 'targetNode') {
const newPath = path.replace({
type: 'Identifier',
name: 'a'
});
// `newPath` is the path for the new node
}
}
});
assert.deepEqual(ast, {
type: 'AssignmentExpression',
left: {
type: 'Identifier',
name: 'a'
},
operator: '=',
right: {
type: 'Identifier',
name: 'b'
}
});
```
*/
replaceWith: any;
/**
Removes the old node and inserts the new nodes in the old node's position
___Example___
```
const ast = {
type: 'ArrayExpression',
elements: [
{
type: 'Literal',
value: 1
},
{
type: 'Identifier',
name: 'targetNode'
},
{
type: 'Literal',
value: 5
}
]
};
traverse(ast, {
Identifier(path) {
if (path.node.name === 'targetNode') {
const newPaths = path.replaceWithMultiple([
{
type: 'Literal',
value: 2
},
{
type: 'Literal',
value: 3
},
{
type: 'Literal',
value: 4
}
]);
// `newPaths` are the paths for the new nodes
}
}
});
assert.deepEqual(ast, {
type: 'ArrayExpression',
elements: [
{
type: 'Literal',
value: 1
},
{
type: 'Literal',
value: 2
},
{
type: 'Literal',
value: 3
},
{
type: 'Literal',
value: 4
},
{
type: 'Literal',
value: 5
}
]
});
```
*/
replaceWithMultiple: any;
}