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: