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
Comprehensive private and public field transformation including private name mapping, field initialization, and usage transformation.
Creates a mapping of private names to their metadata for transformation.
/**
* Builds mapping of private names to metadata
* @param className - Name of the class being transformed
* @param privateFieldsAsSymbolsOrProperties - Whether to use symbols/properties instead of WeakMap
* @param props - Array of class property paths
* @param file - Babel file instance
* @returns Map of private names to their metadata
*/
function buildPrivateNamesMap(
className: string,
privateFieldsAsSymbolsOrProperties: boolean,
props: PropPath[],
file: File
): PrivateNamesMap;
type PrivateNamesMap = Map<string, PrivateNameMetadata>;
interface PrivateNameMetadata {
id: t.Identifier;
static: boolean;
method: boolean;
getId?: t.Identifier;
setId?: t.Identifier;
methodId?: t.Identifier;
initAdded?: boolean;
getterDeclared?: boolean;
setterDeclared?: boolean;
}Usage Examples:
import { buildPrivateNamesMap } from "@babel/helper-create-class-features-plugin";
// Build private names map for a class
const privateNamesMap = buildPrivateNamesMap(
"MyClass",
loose, // Use symbols instead of WeakMap
props, // Class property paths
file
);
// Access metadata for a private field
const fieldMetadata = privateNamesMap.get("privateField");
if (fieldMetadata) {
console.log(fieldMetadata.id.name); // Generated identifier
console.log(fieldMetadata.static); // Is static field
console.log(fieldMetadata.method); // Is method
}Creates AST nodes for private name declarations.
/**
* Creates AST nodes for private name declarations
* @param privateNamesMap - Map of private names to metadata
* @param privateFieldsAsProperties - Use properties instead of WeakMap
* @param privateFieldsAsSymbols - Use symbols instead of WeakMap
* @param file - Babel file instance
* @returns Array of AST statement nodes
*/
function buildPrivateNamesNodes(
privateNamesMap: PrivateNamesMap,
privateFieldsAsProperties: boolean,
privateFieldsAsSymbols: boolean,
file: File
): t.Statement[];Builds comprehensive field initialization nodes for classes.
/**
* Builds field initialization nodes for classes
* @param ref - Class reference identifier (null for class expressions)
* @param superRef - Super class expression (undefined if no inheritance)
* @param props - Array of class property paths
* @param privateNamesMap - Map of private names to metadata
* @param file - Babel file instance
* @param setPublicClassFields - Whether to set public fields as assignments
* @param privateFieldsAsSymbolsOrProperties - Use symbols/properties for private fields
* @param noUninitializedPrivateFieldAccess - Skip uninitialized access checks
* @param constantSuper - Assume super class is constant
* @param innerBindingRef - Inner class binding identifier
* @returns Object containing initialization nodes and utilities
*/
function buildFieldsInitNodes(
ref: t.Identifier | null,
superRef: t.Expression | undefined,
props: PropPath[],
privateNamesMap: PrivateNamesMap,
file: File,
setPublicClassFields: boolean,
privateFieldsAsSymbolsOrProperties: boolean,
noUninitializedPrivateFieldAccess: boolean,
constantSuper: boolean,
innerBindingRef: t.Identifier | null
): FieldsInitResult;
interface FieldsInitResult {
staticNodes: t.Statement[];
pureStaticNodes: t.FunctionDeclaration[];
instanceNodes: t.ExpressionStatement[];
lastInstanceNodeReturnsThis: boolean;
classBindingNode: t.Statement | null;
wrapClass: (path: NodePath<t.Class>) => NodePath;
}Usage Examples:
import { buildFieldsInitNodes } from "@babel/helper-create-class-features-plugin";
// Build field initialization for a class
const {
staticNodes,
pureStaticNodes,
instanceNodes,
lastInstanceNodeReturnsThis,
classBindingNode,
wrapClass
} = buildFieldsInitNodes(
ref,
path.node.superClass,
props,
privateNamesMap,
file,
setPublicClassFields ?? loose,
privateFieldsAsSymbolsOrProperties ?? loose,
noUninitializedPrivateFieldAccess,
constantSuper ?? loose,
innerBinding
);
// Apply transformations
const wrappedPath = wrapClass(path);
wrappedPath.insertBefore(staticNodes);
wrappedPath.insertAfter(pureStaticNodes);Transforms all private name usage throughout the class.
/**
* Transforms private name usage throughout the class
* @param classRefForDefine - Class reference for private field definitions
* @param path - Class path to transform
* @param privateNamesMap - Map of private names to metadata
* @param options - Transformation options
* @param file - Babel file instance
*/
function transformPrivateNamesUsage(
classRefForDefine: t.Identifier,
path: NodePath<t.Class>,
privateNamesMap: PrivateNamesMap,
options: {
privateFieldsAsProperties: boolean;
noUninitializedPrivateFieldAccess: boolean;
noDocumentAll: boolean;
innerBinding: t.Identifier | null;
},
file: File
): void;Builds checks for right-hand side private property access (#prop in obj).
/**
* Builds private property access checks for 'in' expressions
* @param privateNamesMap - Map of private names to metadata
* @param loose - Whether to use loose mode checks
* @param privateFieldsAsSymbols - Whether private fields use symbols
* @returns Expression for checking private property access
*/
function buildCheckInRHS(
privateNamesMap: PrivateNamesMap,
loose: boolean,
privateFieldsAsSymbols: boolean
): t.Expression;Usage Examples:
import { buildCheckInRHS } from "@babel/helper-create-class-features-plugin";
// Build check for private property 'in' expressions
const checkExpression = buildCheckInRHS(
privateNamesMap,
loose,
privateFieldsAsSymbols
);
// Used to transform: #privateField in obj
// Into appropriate runtime checkCreates visitors for traversing and transforming private name usage.
/**
* Factory for creating private name visitors
* @param visitor - Base visitor configuration
* @returns Configured visitor for private name transformation
*/
function privateNameVisitorFactory<S, V>(
visitor: PrivateNameVisitor<S, V>
): PrivateNameVisitor<S, V>;
interface PrivateNameVisitorState<V> {
privateNamesMap: PrivateNamesMapGeneric<V>;
redeclared?: string[];
}
interface PrivateNameVisitor<S, V> {
ClassExpression?(path: NodePath<t.ClassExpression>, state: S): void;
ClassDeclaration?(path: NodePath<t.ClassDeclaration>, state: S): void;
PrivateName?(path: NodePath<t.PrivateName>, state: S): void;
}Defines the types of class properties that can be transformed.
/**
* Union type for all class property node types
*/
type PropNode =
| t.ClassProperty
| t.ClassPrivateProperty
| t.ClassPrivateMethod
| t.StaticBlock;
/**
* NodePath for class property nodes
*/
type PropPath = NodePath<PropNode>;The system supports various field initialization patterns:
// Instance fields
class Example {
publicField = "value"; // Becomes assignment in constructor
#privateField = "value"; // Uses WeakMap or symbol storage
}
// Static fields
class Example {
static publicStatic = "value"; // Becomes class.prop = value
static #privateStatic = "value"; // Uses WeakMap or symbol storage
}
// Computed fields
class Example {
[computedKey] = "value"; // Key extracted and memoized
#[computedPrivate] = "value"; // Not supported - syntax error
}The transformation behavior changes based on loose mode:
Strict Mode (default):
Loose Mode: