Multi-version decorator transformation supporting various decorator specifications with proper handling of decorator metadata and class modification.
Checks if a class or class member has decorators.
/**
* Checks if a class has decorators (on class or any member)
* @param node - Class AST node to check
* @returns true if the class has any decorators
*/
function hasDecorators(node: t.Class): boolean;
/**
* Checks if a node has its own decorators
* @param node - Class or class member node to check
* @returns true if the node has decorators directly attached
*/
function hasOwnDecorators(node: t.Class | t.ClassBody["body"][number]): boolean;Usage Examples:
import { hasDecorators, hasOwnDecorators } from "@babel/helper-create-class-features-plugin";
// Check if class has any decorators
if (hasDecorators(classNode)) {
// Class or its members have decorators
applyDecoratorTransform(classNode);
}
// Check specific decorator placement
if (hasOwnDecorators(classNode)) {
// Class itself has decorators
}
for (const member of classNode.body.body) {
if (hasOwnDecorators(member)) {
// This member has decorators
}
}Creates a visitor for handling named evaluation patterns in decorators.
/**
* Creates a visitor for handling named evaluation in decorator contexts
* @param needsName - Function to determine if a path needs named evaluation
* @param visitor - Callback to handle paths that need named evaluation
* @returns Visitor object for traversing and handling named evaluations
*/
function buildNamedEvaluationVisitor(
needsName: (path: NodePath) => boolean,
visitor: (
path: NodePath,
state: PluginPass,
name: string | t.Identifier | t.StringLiteral | t.NumericLiteral | t.BigIntLiteral
) => void
): Visitor;Usage Examples:
import { buildNamedEvaluationVisitor } from "@babel/helper-create-class-features-plugin";
// Create visitor for decorator evaluation with custom logic
const namedEvaluationVisitor = buildNamedEvaluationVisitor(
(path) => {
// Determine if path needs named evaluation
return path.isCallExpression() || path.isIdentifier();
},
(path, state, name) => {
// Handle named evaluation
console.log(`Processing ${name} for path:`, path.type);
// Custom transformation logic here
}
);
// Use in transformation pipeline
path.traverse(namedEvaluationVisitor, state);The helper supports multiple decorator specification versions.
/**
* Supported decorator specification versions
*/
type DecoratorVersionKind =
| "2023-11" // Final stage-3 specification (Babel 8 default)
| "2023-05" // Near-final stage-3 specification
| "2023-01" // Refined stage-3 specification
| "2022-03" // Updated stage-3 specification
| "2021-12"; // Early stage-3 specification
// Legacy decorator support (pre-standardization)
type LegacyDecoratorVersion = "2018-09";
type AllDecoratorVersions = DecoratorVersionKind | LegacyDecoratorVersion;Usage Examples:
import { createClassFeaturePlugin, FEATURES } from "@babel/helper-create-class-features-plugin";
// Modern decorators (stage-3)
export default createClassFeaturePlugin({
name: "transform-decorators",
api,
feature: FEATURES.decorators,
decoratorVersion: "2023-11"
});
// Legacy decorators (pre-standard)
export default createClassFeaturePlugin({
name: "transform-decorators-legacy",
api,
feature: FEATURES.decorators,
decoratorVersion: "2018-09"
});Main decorator transformation function (default export).
/**
* Main decorator transformation function
* @param api - Babel plugin API
* @param options - Decorator transformation options
* @param decoratorVersion - Decorator specification version
* @param inherits - Plugin inheritance configuration
* @returns Configured PluginObject for decorator transformation
*/
export default function createDecoratorTransform(
api: PluginAPI,
options: { loose?: boolean },
decoratorVersion: DecoratorVersionKind,
inherits?: PluginObject["inherits"]
): PluginObject;Special handling for legacy decorator specification.
/**
* Builds decorated class for legacy decorators (2018-09)
* @param classRefForDefine - Class reference identifier
* @param path - Class path to transform
* @param elements - Class body elements
* @param file - Babel file instance
* @returns Transformation result with instance nodes and wrapper
*/
function buildDecoratedClass(
classRefForDefine: t.Identifier,
path: NodePath<t.Class>,
elements: NodePath<t.ClassMethod | t.ClassProperty>[],
file: File
): {
instanceNodes: t.ExpressionStatement[];
wrapClass: (path: NodePath<t.Class>) => NodePath;
};The system handles various decorator patterns:
Class Decorators:
@decorator
@decorator2(options)
class MyClass {}Method Decorators:
class MyClass {
@methodDecorator
@methodDecorator2(options)
method() {}
}Property Decorators:
class MyClass {
@propertyDecorator
@propertyDecorator2(options)
property = "value";
}Accessor Decorators:
class MyClass {
@accessorDecorator
get value() { return this._value; }
@accessorDecorator
set value(v) { this._value = v; }
}The system follows proper decorator evaluation order:
2018-09 (Legacy):
2021-12 to 2023-11 (Modern):
Modern decorators support rich metadata:
// Decorator context includes:
interface DecoratorContext {
kind: "class" | "method" | "getter" | "setter" | "field" | "accessor";
name: string | symbol;
access: { get?(): any; set?(value: any): void };
private?: boolean;
static?: boolean;
addInitializer(initializer: () => void): void;
}Decorator support with private members has limitations:
The system provides detailed error messages for: