or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

index.mddocs/

Babel Plugin Transform Decorators Legacy

babel-plugin-transform-decorators-legacy is a Babel 6 plugin that transforms decorator syntax to provide backward compatibility with Babel 5's decorator behavior. It implements the original decorator proposal specification with proper evaluation order and handles edge cases around static property initialization that were problematic in Babel 5.

Package Information

  • Package Name: babel-plugin-transform-decorators-legacy
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install --save-dev babel-plugin-transform-decorators-legacy

Core Imports

This is a Babel plugin, so it doesn't have traditional imports. It's configured in your Babel configuration:

{
  "plugins": ["transform-decorators-legacy"]
}

The plugin can also be imported programmatically for advanced usage:

const transformDecoratorsLegacy = require("babel-plugin-transform-decorators-legacy");

Basic Usage

Configure the plugin in your .babelrc file or Babel configuration:

{
  "plugins": ["transform-decorators-legacy"]
}

Important: Order matters! If you're using transform-class-properties, make sure transform-decorators-legacy comes before it:

{
  "plugins": [
    "transform-decorators-legacy",
    "transform-class-properties"
  ]
}

The plugin transforms decorator syntax in your code:

// Input: Decorator syntax
@deprecated
@logged
class MyClass {
  @readonly
  @validate
  method() {
    return "hello";
  }

  @configurable(false)
  property = "value";
}

// Output: Legacy decorator behavior compatible with Babel 5

Architecture

The plugin is built around several key components:

  • Main Plugin Function: Default export that returns Babel plugin configuration
  • AST Visitors: Transform specific node types (classes, objects, assignments)
  • Helper Generators: Create runtime helper functions for decorator application
  • Template System: Uses babel-template to generate consistent code patterns
  • Evaluation Order: Ensures decorators are evaluated top-to-bottom, executed bottom-to-top

Capabilities

Plugin Configuration

Main plugin export that integrates with Babel's plugin system.

/**
 * Main Babel plugin function for transform-decorators-legacy
 * @param {Object} api - Babel plugin API containing types and utilities
 * @param {Object} api.types - Babel types (t) for AST manipulation
 * @returns {Object} Plugin configuration with inherits and visitor
 */
export default function({types: t}): BabelPlugin;

interface BabelPlugin {
  /** Inherits babel-plugin-syntax-decorators for decorator parsing */
  inherits: any;
  /** AST visitor configuration for transforming decorator nodes */
  visitor: VisitorConfig;
}

interface VisitorConfig {
  /** Handles export default class declarations with decorators */
  ExportDefaultDeclaration(path: NodePath): void;
  /** Transforms class declarations to variable declarations for decorator processing */
  ClassDeclaration(path: NodePath): void;
  /** Main visitor for processing class expressions with decorators */
  ClassExpression(path: NodePath, state: PluginState): void;
  /** Processes object expressions with decorated properties/methods */
  ObjectExpression(path: NodePath, state: PluginState): void;
  /** Handles class property assignments for decorator initialization */
  AssignmentExpression(path: NodePath, state: PluginState): void;
}

Helper Functions

Internal helper functions for generating runtime code and managing plugin state.

/**
 * Ensures the applyDecoratedDescriptor helper function exists in the program
 * @param {NodePath} path - Current AST path
 * @param {PluginState} state - Plugin state object
 * @returns {Identifier} Identifier for the helper function
 */
function ensureApplyDecoratedDescriptorHelper(path: NodePath, state: PluginState): Identifier;

/**
 * Ensures the initializerDefineProp helper function exists in the program
 * @param {NodePath} path - Current AST path
 * @param {PluginState} state - Plugin state object
 * @returns {Identifier} Identifier for the helper function
 */
function ensureInitializerDefineProp(path: NodePath, state: PluginState): Identifier;

/**
 * Ensures the initializerWarning helper function exists in the program
 * @param {NodePath} path - Current AST path
 * @param {PluginState} state - Plugin state object
 * @returns {Identifier} Identifier for the helper function
 */
function ensureInitializerWarning(path: NodePath, state: PluginState): Identifier;

/**
 * Applies proper evaluation ordering for decorator expressions
 * @param {NodePath} path - Class or object path with decorators
 * @returns {Expression} Sequence expression with ordered evaluations
 */
function applyEnsureOrdering(path: NodePath): Expression | null;

/**
 * Applies class-level decorators to a class expression
 * @param {NodePath} classPath - Class expression path
 * @param {PluginState} state - Plugin state object
 * @returns {Expression} Decorated class expression
 */
function applyClassDecorators(classPath: NodePath, state: PluginState): Expression | null;

/**
 * Applies method decorators to class methods
 * @param {NodePath} path - Class expression path
 * @param {PluginState} state - Plugin state object
 * @returns {Expression} Class expression with decorated methods
 */
function applyMethodDecorators(path: NodePath, state: PluginState): Expression | null;

/**
 * Applies decorators to object expression properties
 * @param {NodePath} path - Object expression path  
 * @param {PluginState} state - Plugin state object
 * @returns {Expression} Object expression with decorated properties
 */
function applyObjectDecorators(path: NodePath, state: PluginState): Expression | null;

Template System

Code generation templates used internally by the plugin to create consistent runtime helpers.

/**
 * Template for applying a class decorator
 * Generates: DECORATOR(CLASS_REF = INNER) || CLASS_REF;
 */
const buildClassDecorator: Template;

/**
 * Template for accessing class prototype
 * Generates: CLASS_REF.prototype;
 */
const buildClassPrototype: Template;

/**
 * Template for getting property descriptor
 * Generates: Object.getOwnPropertyDescriptor(TARGET, PROPERTY);
 */
const buildGetDescriptor: Template;

/**
 * Template for getting object property initializer descriptor
 * Creates descriptor with initializer function for object properties
 */
const buildGetObjectInitializer: Template;

/**
 * Template for initializer warning helper function
 * Throws error when class properties aren't properly configured
 */
const buildInitializerWarningHelper: Template;

/**
 * Template for initializer property definition helper
 * Defines properties with initializer values at runtime
 */
const buildInitializerDefineProperty: Template;

/**
 * Template for applying decorated descriptor helper function
 * Main runtime helper that applies decorators to property descriptors
 */
const buildApplyDecoratedDescriptor: Template;

Class Decorators

Transforms class-level decorators that modify or replace the constructor.

Behavior: Class decorators are functions that receive the class constructor and can return a new constructor or modify the existing one.

Evaluation Order: Decorator expressions are evaluated top-to-bottom, but decorators are applied bottom-to-top (closest to class first).

// Decorator function signature
function classDecorator(constructor) {
  // Can return new constructor or modify existing one
  return constructor;
}

@classDecorator
class MyClass {}

Method Decorators

Transforms method decorators that modify property descriptors.

Behavior: Method decorators receive (target, property, descriptor) following the legacy decorator proposal.

// Method decorator function signature  
function methodDecorator(target, property, descriptor) {
  // Can return new descriptor or modify existing one
  return descriptor;
}

class MyClass {
  @methodDecorator
  method() {}

  @methodDecorator  
  static staticMethod() {}
}

Property Decorators

Transforms property decorators including class properties with initializers.

Behavior: Property decorators receive a descriptor with an initializer function for properties with default values.

// Property decorator function signature
function propertyDecorator(target, property, descriptor) {
  // descriptor.initializer contains the property's initial value function
  return descriptor;
}

class MyClass {
  @propertyDecorator
  property = "default value";

  @propertyDecorator
  static staticProperty = 42;
}

Object Decorators

Transforms decorators on object literal properties and methods.

Behavior: Works the same as class decorators but applies to object expressions.

const obj = {
  @methodDecorator
  method() {},

  @propertyDecorator  
  property: "value"
};

Decorator Evaluation Order

Ensures proper decorator evaluation and execution order.

Evaluation: Decorator expressions are evaluated top-to-bottom (as written) Execution: Decorators are executed bottom-to-top (closest to target first)

function dec(id) {
  console.log('evaluated', id);
  return function(target, property, descriptor) {
    console.log('executed', id);
    return descriptor;
  };
}

class Example {
  @dec(1)  // Evaluated first
  @dec(2)  // Evaluated second, but executed first
  method() {}
}
// Output: evaluated 1, evaluated 2, executed 2, executed 1

Error Handling

The plugin generates helpful error messages for common issues:

  • Missing transform-class-properties: Throws clear error when class properties aren't properly configured
  • Computed decorators: Throws error for unsupported computed property decorators
  • Helper function conflicts: Manages helper function naming to avoid conflicts

Types

/** Babel plugin state object passed between visitors */
interface PluginState {
  /** Helper function identifier for applying decorated descriptors */
  applyDecoratedDescriptor?: Identifier;
  /** Helper function identifier for defining properties with initializers */
  initializerDefineProp?: Identifier;
  /** Helper function identifier for initializer warning */
  initializerWarningHelper?: Identifier;
}

/** Babel template interface for code generation */
interface Template {
  /** Generate AST nodes from template with placeholders */
  (opts: {[key: string]: any}): {expression?: Expression, statement?: Statement};
}

/** Babel AST node path interface */
interface NodePath {
  /** The AST node */
  node: Node;
  /** Scope information */
  scope: Scope;
  /** Replace this node with another */
  replaceWith(node: Node): void;
  /** Insert a node after this one */
  insertAfter(node: Node): void;
  /** Get a child path */
  get(key: string): NodePath;
  /** Check if this path represents a class */
  isClass(): boolean;
  /** Check if this path represents a class declaration */
  isClassDeclaration(): boolean;
  /** Build error with code frame */
  buildCodeFrameError(message: string): Error;
}

/** Babel scope interface */
interface Scope {
  /** Generate unique identifier */
  generateUidIdentifier(name: string): Identifier;
  /** Generate declared unique identifier */
  generateDeclaredUidIdentifier(name: string): Identifier;
  /** Get the program parent scope */
  getProgramParent(): Scope;
  /** Scope path */
  path: NodePath;
}

/** Babel AST Expression node */
interface Expression {
  type: string;
}

/** Babel AST Statement node */
interface Statement {
  type: string;
}

/** Babel AST Identifier node */
interface Identifier {
  type: "Identifier";
  name: string;
}

/** Babel AST Node interface */
interface Node {
  type: string;
  decorators?: Decorator[];
}

/** Decorator AST node */
interface Decorator {
  expression: Expression;
}

/** Decorator function signature for legacy decorators */
type DecoratorFunction = (
  target: any,
  property: string | symbol,
  descriptor: PropertyDescriptor
) => PropertyDescriptor | void;

/** Class decorator function signature */
type ClassDecoratorFunction = (constructor: Function) => Function | void;

Compatibility Notes

Babel 5 vs Babel 6 Differences

  1. Evaluation Order: Fixed to match decorator specification (top-to-bottom evaluation, bottom-to-top execution)
  2. Static Property Initializers: Pre-computed to prevent multiple evaluation issues from Babel 5
  3. Error Handling: Better error messages and integration with transform-class-properties

Plugin Dependencies

  • babel-plugin-syntax-decorators: Required for parsing decorator syntax (inherited automatically)
  • babel-runtime: Provides runtime helpers for generated code
  • babel-template: Used internally for code generation patterns

Configuration Requirements

  • Must be placed before transform-class-properties in plugin array
  • Requires transform-class-properties for proper class property handling
  • Compatible with Babel 6.x only (use @babel/plugin-proposal-decorators with legacy: true for Babel 7+)

Migration from Babel 5

The plugin provides a smooth migration path from Babel 5 decorator behavior:

  • Same decorator function signatures: (target, property, descriptor)
  • Compatible with existing decorator libraries
  • Fixes evaluation order issues from Babel 5
  • Handles static property edge cases better than Babel 5