Babel helper plugin that provides essential functionality for transforming modern JavaScript class features to ES6-compatible code
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Helper utilities for class initialization, computed key extraction, and AST manipulation.
Injects initialization code into class constructors.
/**
* Injects initialization code into a class constructor
* Creates constructor if none exists, or augments existing constructor
* @param path - Class path to modify
* @param constructor - Existing constructor path (undefined if none)
* @param instanceNodes - Initialization expressions to inject
* @param referenceVisitor - Callback for handling property references
* @param lastInstanceNodeReturnsThis - Whether last node returns 'this'
*/
function injectInitialization(
path: NodePath<t.Class>,
constructor: NodePath<t.ClassMethod> | undefined,
instanceNodes: t.ExpressionStatement[],
referenceVisitor: (visitor: Visitor, state: any) => void,
lastInstanceNodeReturnsThis: boolean
): void;
type Visitor = {
[key: string]: (path: NodePath, state: any) => void;
};Usage Examples:
import { injectInitialization } from "@babel/helper-create-class-features-plugin";
// Inject field initialization into constructor
injectInitialization(
classPath,
constructorPath, // may be undefined
[
t.expressionStatement(
t.assignmentExpression("=",
t.memberExpression(t.thisExpression(), t.identifier("field")),
t.stringLiteral("value")
)
)
],
(referenceVisitor, state) => {
// Handle property references during injection
for (const prop of props) {
if (!prop.node.static) {
prop.traverse(referenceVisitor, state);
}
}
},
false // last node doesn't return this
);Extracts and memoizes computed property keys from class members.
/**
* Extracts computed keys from class methods and properties
* Hoists computed key expressions to avoid re-evaluation
* @param path - Class path containing computed keys
* @param computedPaths - Paths with computed keys to extract
* @param file - Babel file instance
* @returns Array of statement nodes for hoisted key variables
*/
function extractComputedKeys(
path: NodePath<t.Class>,
computedPaths: NodePath<t.ClassProperty | t.ClassMethod>[],
file: File
): t.Statement[];Usage Examples:
import { extractComputedKeys } from "@babel/helper-create-class-features-plugin";
// Find computed properties
const computedPaths: NodePath<t.ClassProperty | t.ClassMethod>[] = [];
for (const memberPath of classPath.get("body.body")) {
if ((memberPath.isClassProperty() || memberPath.isClassMethod()) &&
memberPath.node.computed) {
computedPaths.push(memberPath);
}
}
// Extract computed keys
const keyNodes = extractComputedKeys(classPath, computedPaths, file);
// Insert hoisted key variables before class
classPath.insertBefore(keyNodes);Builds a right-hand side expression for private property 'in' checks with proper validation.
/**
* Builds a right-hand side expression for private property 'in' checks
* Wraps expressions with helper when available for proper validation
* @param rhs - The right-hand side expression to check
* @param file - Babel file instance for helper access
* @param inRHSIsObject - Whether RHS is known to be an object
* @returns Enhanced expression with proper validation
*/
function buildCheckInRHS(
rhs: t.Expression,
file: File,
inRHSIsObject?: boolean
): t.Expression;Usage Examples:
import { buildCheckInRHS } from "@babel/helper-create-class-features-plugin";
// Build RHS check for private 'in' operation
const rhs = t.identifier("obj");
const checkedRHS = buildCheckInRHS(rhs, file);
// Use in private property 'in' check
const privateInCheck = t.binaryExpression(
"in",
privateNameId,
checkedRHS
);
// With known object type (skips validation)
const checkedRHSOptimized = buildCheckInRHS(rhs, file, true);When no constructor exists, one is created:
// Before transformation
class Example {
field = "value";
}
// After initialization injection
class Example {
constructor() {
this.field = "value";
}
}When constructor exists, initialization is injected:
// Before transformation
class Example {
field = "value";
constructor(param) {
console.log("constructor");
}
}
// After initialization injection
class Example {
constructor(param) {
this.field = "value";
console.log("constructor");
}
}Initialization respects super call requirements:
// Before transformation
class Child extends Parent {
field = "value";
constructor() {
super();
console.log("after super");
}
}
// After initialization injection
class Child extends Parent {
constructor() {
super();
this.field = "value";
console.log("after super");
}
}// Before extraction
class Example {
[computeKey()] = "value";
[expensive.calculation] = "value2";
}
// After extraction
const _computeKey = computeKey();
const _expensive$calculation = expensive.calculation;
class Example {
[_computeKey] = "value";
[_expensive$calculation] = "value2";
}// Before extraction
class Example {
[prefix + Math.random()] = "value";
[getKey() + suffix] = "value2";
}
// After extraction
const _prefix$Math$random = prefix + Math.random();
const _getKey$suffix = getKey() + suffix;
class Example {
[_prefix$Math$random] = "value";
[_getKey$suffix] = "value2";
}The reference visitor pattern handles property references during initialization:
const referenceVisitor: Visitor = {
ThisExpression(path) {
// Handle 'this' references in initializers
},
Super(path) {
// Handle 'super' references in initializers
},
PrivateName(path) {
// Handle private name references
}
};
// Used in injectInitialization callback
(visitor, state) => {
for (const prop of instanceProps) {
prop.traverse(visitor, state);
}
}Utilities properly handle scope and binding: