Helper function to explode an assignable expression into safe temporary variables
npx @tessl/cli install tessl/npm-babel-helper-explode-assignable-expression@6.24.0Helper function to explode an assignable expression by safely extracting object references and property accesses into temporary variables. This ensures that side effects (like getters) are only evaluated once during complex assignment operations, making it essential for Babel transformations involving destructuring, object property assignments, and other complex assignment patterns.
npm install babel-helper-explode-assignable-expressionimport explode from "babel-helper-explode-assignable-expression";For TypeScript/Flow projects, you may also need to import the Scope type:
import explode from "babel-helper-explode-assignable-expression";
import type { Scope } from "babel-traverse";For CommonJS:
const explode = require("babel-helper-explode-assignable-expression");import explode from "babel-helper-explode-assignable-expression";
import * as t from "babel-types";
function processAssignmentExpression(path, file) {
const { node, scope } = path;
const nodes = [];
// Explode the left-hand side of an assignment
const exploded = explode(node.left, nodes, file, scope);
// nodes now contains any necessary variable declarations
// exploded.uid is the assignment target
// exploded.ref is the reference for reading the current value
nodes.push(t.assignmentExpression("=", exploded.ref, node.right));
path.replaceWithMultiple(nodes);
}The explode function works by analyzing assignable expressions and breaking them down into safe components:
The function uses two internal helper functions to achieve this:
getObjRef(): Safely extracts object references, creating temporary variables when neededgetPropRef(): Safely extracts property references for computed property accessThe main function that explodes an assignable expression into safe temporary variables.
/**
* Explodes an assignable expression by safely extracting object references
* and property accesses into temporary variables
* @param node - The AST node representing the assignable expression
* @param nodes - Array to collect generated variable declaration nodes
* @param file - Babel file object for transformations
* @param scope - Babel traverse scope object for variable binding analysis
* @param allowedSingleIdent - Whether single identifiers should be treated as objects
* @returns Object with uid (assignment target) and ref (reference for reading)
*/
function explode(
node: Object,
nodes: Array<Object>,
file: Object,
scope: Scope,
allowedSingleIdent?: boolean
): {
uid: Object;
ref: Object;
}Parameters:
node (Object): The AST node representing the assignable expression to explode. Supported types:
t.isIdentifier)t.isMemberExpression)t.isSuper)nodes (Array<Object>): Array to collect generated variable declaration nodes that need to be inserted before the assignmentfile (Object): Babel file object used for transformations and contextscope (Scope): Babel traverse scope object for analyzing variable bindings and generating unique identifiersallowedSingleIdent (boolean, optional): Whether single identifiers should be treated as objects when explodingReturn Value:
Returns an object with two properties:
uid (Object): The unique identifier or member expression to use as the assignment targetref (Object): The reference expression to use for reading the current valueError Handling:
Throws Error with message "We can't explode this node type ${node.type}" for unsupported AST node types.
Usage Examples:
import explode from "babel-helper-explode-assignable-expression";
import * as t from "babel-types";
// Example 1: Simple identifier (locally bound)
const nodes1 = [];
const result1 = explode(
t.identifier("localVar"),
nodes1,
file,
scope,
true
);
// nodes1: [] (no temp variables needed)
// result1: { uid: Identifier(localVar), ref: Identifier(localVar) }
// Example 2: Member expression with safe object
const nodes2 = [];
const memberExpr = t.memberExpression(
t.identifier("obj"),
t.identifier("prop")
);
const result2 = explode(memberExpr, nodes2, file, scope);
// nodes2: [] (obj is safe to re-evaluate)
// result2: { uid: MemberExpression(obj.prop), ref: MemberExpression(obj.prop) }
// Example 3: Complex member expression requiring temp variables
const nodes3 = [];
const complexExpr = t.memberExpression(
t.callExpression(t.identifier("getObject"), []),
t.callExpression(t.identifier("getProp"), []),
true // computed property
);
const result3 = explode(complexExpr, nodes3, file, scope);
// nodes3: [VariableDeclaration for temp object, VariableDeclaration for temp property]
// result3: { uid: MemberExpression(temp$0[temp$1]), ref: MemberExpression(temp$0[temp$1]) }// Flow type definitions
type Scope = {
hasBinding(name: string): boolean;
generateUidIdentifierBasedOnNode(node: Object): Object;
// ... other Babel traverse scope properties
};
type ExplodeResult = {
uid: Object; // Assignment target identifier or member expression
ref: Object; // Reference expression for reading current value
};This helper requires the following Babel packages:
babel-traverse: For Scope type and traversal functionalitybabel-types: For AST node creation, type checking, and utility functionsbabel-runtime: For runtime support and polyfills