Utilities for extracting binding identifiers and function names from AST nodes. These functions help analyze variable declarations, assignments, and function definitions in JavaScript code.
Extract all binding identifiers from a node and its children.
/**
* Extract binding identifiers from a node
* @param node - Node to extract bindings from
* @param duplicates - Whether to collect duplicate bindings in arrays (default: false)
* @param outerOnly - Whether to only collect outer-level bindings (default: false)
* @param newBindingsOnly - Whether to only collect new bindings, excluding assignments (default: false)
* @returns Object mapping identifier names to identifiers or arrays of identifiers
*/
function getBindingIdentifiers(
node: t.Node,
duplicates: true,
outerOnly?: boolean,
newBindingsOnly?: boolean
): Record<string, Array<t.Identifier>>;
function getBindingIdentifiers(
node: t.Node,
duplicates?: false,
outerOnly?: boolean,
newBindingsOnly?: boolean
): Record<string, t.Identifier>;Extract only outer-level binding identifiers, excluding nested bindings.
/**
* Extract only outer-level binding identifiers
* @param node - Node to extract bindings from
* @param duplicates - Whether to collect duplicate bindings in arrays (default: false)
* @returns Object mapping identifier names to identifiers or arrays of identifiers
*/
function getOuterBindingIdentifiers(
node: t.Node,
duplicates: true
): Record<string, Array<t.Identifier>>;
function getOuterBindingIdentifiers(
node: t.Node,
duplicates?: false
): Record<string, t.Identifier>;Extract identifiers that are being assigned to in assignment expressions.
/**
* Extract identifiers from assignment expressions
* @param node - Node to extract assignment identifiers from
* @returns Object mapping identifier names to arrays of identifiers
*/
function getAssignmentIdentifiers(node: t.Node): Record<string, Array<t.Identifier>>;Extract the name of a function from various function node types.
/**
* Get the name identifier of a function
* @param node - Function node (FunctionDeclaration, FunctionExpression, etc.)
* @returns Function name identifier or null if anonymous
*/
function getFunctionName(node: t.Function): t.Identifier | null;import * as t from "@babel/types";
// Variable declaration: const { a, b } = obj;
const destructuringDecl = t.variableDeclaration("const", [
t.variableDeclarator(
t.objectPattern([
t.objectProperty(t.identifier("a"), t.identifier("a"), false, true),
t.objectProperty(t.identifier("b"), t.identifier("b"), false, true)
]),
t.identifier("obj")
)
]);
const bindings = t.getBindingIdentifiers(destructuringDecl);
console.log(Object.keys(bindings)); // ["a", "b"]
console.log(bindings.a.name); // "a"
console.log(bindings.b.name); // "b"// Function with parameters: function test(x, y, {z}) { }
const funcDecl = t.functionDeclaration(
t.identifier("test"),
[
t.identifier("x"),
t.identifier("y"),
t.objectPattern([
t.objectProperty(t.identifier("z"), t.identifier("z"), false, true)
])
],
t.blockStatement([])
);
const paramBindings = t.getBindingIdentifiers(funcDecl);
console.log(Object.keys(paramBindings)); // ["test", "x", "y", "z"]// Multiple declarations with same name
const multipleDecls = t.program([
t.variableDeclaration("var", [
t.variableDeclarator(t.identifier("x"), t.numericLiteral(1))
]),
t.variableDeclaration("var", [
t.variableDeclarator(t.identifier("x"), t.numericLiteral(2))
])
]);
// Without duplicates - returns last occurrence
const singleBindings = t.getBindingIdentifiers(multipleDecls);
console.log(singleBindings.x); // Second 'x' identifier
// With duplicates - returns array
const duplicateBindings = t.getBindingIdentifiers(multipleDecls, true);
console.log(duplicateBindings.x.length); // 2
console.log(duplicateBindings.x[0]); // First 'x' identifier
console.log(duplicateBindings.x[1]); // Second 'x' identifier// Function with nested function
const outerFunc = t.functionDeclaration(
t.identifier("outer"),
[t.identifier("param")],
t.blockStatement([
t.functionDeclaration(
t.identifier("inner"),
[t.identifier("innerParam")],
t.blockStatement([])
)
])
);
// All bindings (including nested)
const allBindings = t.getBindingIdentifiers(outerFunc);
console.log(Object.keys(allBindings)); // ["outer", "param", "inner", "innerParam"]
// Only outer-level bindings
const outerBindings = t.getOuterBindingIdentifiers(outerFunc);
console.log(Object.keys(outerBindings)); // ["outer", "param"]// Assignment expressions: a = b, obj.prop = value
const assignments = [
t.assignmentExpression("=", t.identifier("a"), t.identifier("b")),
t.assignmentExpression("=",
t.memberExpression(t.identifier("obj"), t.identifier("prop")),
t.identifier("value")
),
t.assignmentExpression("=",
t.objectPattern([
t.objectProperty(t.identifier("x"), t.identifier("x"))
]),
t.identifier("source")
)
];
assignments.forEach(assignment => {
const assignmentIds = t.getAssignmentIdentifiers(assignment);
console.log(Object.keys(assignmentIds));
});
// ["a"]
// [] (member expressions don't create bindings)
// ["x"] (destructuring creates bindings)// Named function declaration
const namedFunc = t.functionDeclaration(
t.identifier("myFunction"),
[],
t.blockStatement([])
);
console.log(t.getFunctionName(namedFunc)?.name); // "myFunction"
// Anonymous function expression
const anonFunc = t.functionExpression(
null,
[],
t.blockStatement([])
);
console.log(t.getFunctionName(anonFunc)); // null
// Arrow function (anonymous)
const arrowFunc = t.arrowFunctionExpression(
[],
t.identifier("result")
);
console.log(t.getFunctionName(arrowFunc)); // null
// Method definition
const method = t.objectMethod(
"method",
t.identifier("methodName"),
[],
t.blockStatement([])
);
console.log(t.getFunctionName(method)?.name); // "methodName"// Complex destructuring: const [a, {b, c: d}, ...rest] = array;
const complexPattern = t.variableDeclaration("const", [
t.variableDeclarator(
t.arrayPattern([
t.identifier("a"),
t.objectPattern([
t.objectProperty(t.identifier("b"), t.identifier("b"), false, true),
t.objectProperty(t.identifier("c"), t.identifier("d"))
]),
t.restElement(t.identifier("rest"))
]),
t.identifier("array")
)
]);
const destructuredBindings = t.getBindingIdentifiers(complexPattern);
console.log(Object.keys(destructuredBindings)); // ["a", "b", "d", "rest"]// Class with methods
const classDecl = t.classDeclaration(
t.identifier("MyClass"),
null,
t.classBody([
t.classMethod(
"constructor",
t.identifier("constructor"),
[t.identifier("param")],
t.blockStatement([])
),
t.classMethod(
"method",
t.identifier("doSomething"),
[],
t.blockStatement([])
)
])
);
const classBindings = t.getBindingIdentifiers(classDecl);
console.log(Object.keys(classBindings)); // ["MyClass", "param"]
// Get function names from class methods
const methods = classDecl.body.body.filter(t.isMethod);
methods.forEach(method => {
const name = t.getFunctionName(method);
console.log(name?.name); // "constructor", "doSomething"
});// Import declaration: import {a, b as c} from "module";
const importDecl = t.importDeclaration([
t.importSpecifier(t.identifier("a"), t.identifier("a")),
t.importSpecifier(t.identifier("c"), t.identifier("b"))
], t.stringLiteral("module"));
const importBindings = t.getBindingIdentifiers(importDecl);
console.log(Object.keys(importBindings)); // ["a", "c"]
// Export declaration: export const {x, y} = obj;
const exportDecl = t.exportNamedDeclaration(
t.variableDeclaration("const", [
t.variableDeclarator(
t.objectPattern([
t.objectProperty(t.identifier("x"), t.identifier("x"), false, true),
t.objectProperty(t.identifier("y"), t.identifier("y"), false, true)
]),
t.identifier("obj")
)
])
);
const exportBindings = t.getBindingIdentifiers(exportDecl);
console.log(Object.keys(exportBindings)); // ["x", "y"]// Prepare binding information for scope analysis
function analyzeBindings(node: t.Node) {
const allBindings = t.getBindingIdentifiers(node, true);
const assignments = t.getAssignmentIdentifiers(node);
return {
declared: Object.keys(allBindings),
assigned: Object.keys(assignments),
duplicates: Object.entries(allBindings)
.filter(([_, ids]) => Array.isArray(ids) && ids.length > 1)
.map(([name]) => name)
};
}
// Usage with a program
const program = t.program([
t.variableDeclaration("var", [
t.variableDeclarator(t.identifier("x"), t.numericLiteral(1))
]),
t.expressionStatement(
t.assignmentExpression("=", t.identifier("y"), t.identifier("x"))
)
]);
const analysis = analyzeBindings(program);
console.log(analysis);
// {
// declared: ["x"],
// assigned: ["y"],
// duplicates: []
// }