Babel plugin that transforms ES2015 classes to ES5 for backward compatibility
npx @tessl/cli install tessl/npm-babel-plugin-transform-es2015-classes@6.24.0babel-plugin-transform-es2015-classes is a Babel plugin that transforms ES2015 (ES6) class syntax into equivalent ES5 code for backward compatibility. It provides comprehensive class compilation including constructor functions, method definitions, inheritance via prototype chains, and super call transformations.
npm install --save-dev babel-plugin-transform-es2015-classes// Direct import (for programmatic usage)
const transformEs2015Classes = require("babel-plugin-transform-es2015-classes");The plugin is typically not imported directly but configured through Babel's configuration system.
{
"plugins": ["transform-es2015-classes"]
}With options:
{
"plugins": [
["transform-es2015-classes", {
"loose": true
}]
]
}babel --plugins transform-es2015-classes script.jsconst babel = require("babel-core");
const result = babel.transform(code, {
plugins: ["transform-es2015-classes"]
});The plugin follows a multi-phase transformation architecture:
Main plugin factory function that creates the Babel transform plugin.
/**
* Main plugin factory function that creates the Babel transform plugin
* @param {Object} options - Babel API object
* @param {Object} options.types - Babel types utility object
* @returns {Object} Babel plugin configuration object
*/
function transformEs2015Classes({ types: t });Returns a plugin object with the following structure:
interface PluginObject {
visitor: {
ExportDefaultDeclaration(path: NodePath): void;
ClassDeclaration(path: NodePath): void;
ClassExpression(path: NodePath, state: PluginState): void;
};
}
interface PluginState {
opts: PluginOptions;
file: BabelFile;
}Configuration options for the transformation behavior.
interface PluginOptions {
/**
* Enable loose mode for simpler, faster output
* Defaults to false for spec-compliant transformation
*/
loose?: boolean;
}The plugin uses two main transformer classes based on the configuration:
The default spec-compliant transformer class that handles complete ES6 class transformations.
/**
* Main class transformer that handles spec-compliant ES6 to ES5 class transformation
* @param {NodePath} path - AST path for the class expression
* @param {BabelFile} file - Babel file context
*/
class ClassTransformer {
constructor(path: NodePath, file: BabelFile);
/** Main transformation method that returns the transformed AST */
run(): Node;
/** Push the class constructor to the transformation body */
_pushConstructor(): void;
/** Transform class methods into ES5-compatible functions */
_processMethod(node: Method, scope: Scope): boolean;
/** Transform class properties */
_pushInstanceProperties(): void;
/** Transform static class properties */
_pushStaticProperties(): void;
/** Set up inheritance chain for derived classes */
_pushInherits(): void;
}Extends ClassTransformer with loose mode optimizations for simpler, faster output.
/**
* Loose mode transformer that generates simpler output with better performance
* Uses assignment instead of Object.defineProperty for method definitions
*/
class LooseClassTransformer extends ClassTransformer {
constructor(path: NodePath, file: BabelFile);
/** Override for loose method processing using simple assignment */
_processMethod(node: Method, scope: Scope): boolean;
}The plugin provides three main AST visitor methods:
Handles transformation of exported class declarations by splitting them into separate class and export statements.
/**
* Transforms export default class declarations
* Splits class declaration and export into separate statements
* @param {NodePath} path - AST path for ExportDefaultDeclaration node
*/
ExportDefaultDeclaration(path: NodePath): void;Input:
export default class MyClass {
constructor() {}
}Output:
let MyClass = function MyClass() {
// constructor logic
};
export default MyClass;Transforms class declarations into variable declarations with class expressions.
/**
* Transforms class declarations into variable declarations
* @param {NodePath} path - AST path for ClassDeclaration node
*/
ClassDeclaration(path: NodePath): void;Input:
class MyClass {
constructor() {}
}Output:
let MyClass = function MyClass() {
// constructor and methods
};Main transformation logic that converts class expressions to ES5-compatible functions.
/**
* Main class expression transformation logic
* Delegates to VanillaTransformer or LooseTransformer based on options
* @param {NodePath} path - AST path for ClassExpression node
* @param {PluginState} state - Plugin state containing options and file context
*/
ClassExpression(path: NodePath, state: PluginState): void;The plugin supports two transformation modes:
Full ECMAScript specification compliance with property descriptors and proper enumeration behavior.
Object.defineProperty for method definitionsSimplified transformation for better performance and smaller output at the cost of some specification compliance.
Enable loose mode:
{
"plugins": [
["transform-es2015-classes", { "loose": true }]
]
}The plugin fully supports ES6 class inheritance patterns:
// Input
class Parent {
constructor(name) {
this.name = name;
}
greet() {
return `Hello, I'm ${this.name}`;
}
}
class Child extends Parent {
constructor(name, age) {
super(name);
this.age = age;
}
greet() {
return `${super.greet()} and I'm ${this.age} years old`;
}
}The plugin transforms this into ES5-compatible constructor functions with proper prototype chain setup and super call handling.
The plugin provides comprehensive super() call transformation:
super.propertyName patternsthis in derived constructorsStatic methods are properly transformed and attached to the constructor function:
// Input
class MyClass {
static create() {
return new MyClass();
}
}
// Transformed to attach static methods to constructorThe plugin supports all ES6 class method types:
class MyClass {
myMethod() {
return "hello";
}
}class MyClass {
get value() {
return this._value;
}
set value(val) {
this._value = val;
}
}class MyClass {
[methodName]() {
return "computed";
}
}The plugin uses Babel template builders for generating common AST patterns:
Template for generating derived class constructors that properly call super().
/**
* Template builder for derived class constructors
* Generates constructor function that calls super(...arguments)
*/
const buildDerivedConstructor: Template;Generates:
(function () {
super(...arguments);
})The plugin defines specialized AST visitors for validation and transformation:
Validates super() call usage in class constructors, ensuring spec compliance.
/**
* Visitor that validates constructor super() calls and 'this' usage
* Throws errors for invalid patterns like missing super() or early 'this' access
*/
const verifyConstructorVisitor: Visitor;Locates all ThisExpression nodes within class methods for transformation.
/**
* Visitor that collects all ThisExpression nodes in class methods
* Used for tracking 'this' references that need transformation
*/
const findThisesVisitor: Visitor;Prevents traversal into nested function scopes during class transformation.
/**
* Visitor that skips function expressions and method definitions
* Prevents incorrect transformation of nested scopes
*/
const noMethodVisitor: Visitor;The plugin performs comprehensive validation and throws descriptive errors for invalid patterns:
/**
* Error types thrown by the plugin during transformation
*/
interface TransformationErrors {
/** Thrown when super() is not called in derived class constructor */
"missing super() call in constructor": CodeFrameError;
/** Thrown when 'this' is used before super() in derived constructor */
"'this' is not allowed before super()": CodeFrameError;
/** Thrown when super() is called in non-derived constructor */
"super() is only allowed in a derived constructor": CodeFrameError;
/** Thrown when super.* is accessed before super() call */
"'super.*' is not allowed before super()": CodeFrameError;
/** Thrown when decorator transform is needed but not applied */
"Method has decorators, put the decorator plugin before the classes one": CodeFrameError;
/** Thrown when class properties transform is needed but not applied */
"Missing class properties transform": CodeFrameError;
}/** Base Babel AST node interface */
interface Node {
type: string;
loc?: SourceLocation;
leadingComments?: Array<Comment>;
innerComments?: Array<Comment>;
trailingComments?: Array<Comment>;
}
/** AST node source location */
interface SourceLocation {
start: Position;
end: Position;
filename?: string;
identifierName?: string;
}
/** Position in source code */
interface Position {
line: number;
column: number;
}
/** Comment node in AST */
interface Comment {
type: "CommentBlock" | "CommentLine";
value: string;
loc: SourceLocation;
}
/** Method node type for class methods */
interface Method extends Node {
type: "ClassMethod";
key: Expression;
params: Array<Pattern>;
body: BlockStatement;
computed: boolean;
static: boolean;
kind: "constructor" | "method" | "get" | "set";
decorators?: Array<Decorator>;
generator: boolean;
async: boolean;
}
/** Babel AST node path interface */
interface NodePath {
node: Node;
scope: Scope;
parent: Node;
parentPath: NodePath;
}
/** Babel file context */
interface BabelFile {
addHelper(name: string): Identifier;
}
/** Babel scope interface */
interface Scope {
generateUidIdentifier(name: string): Identifier;
generateUidIdentifierBasedOnNode(node: Node): Identifier;
hasOwnBinding(name: string): boolean;
rename(oldName: string, newName?: string): void;
}
/** Babel AST identifier node */
interface Identifier {
type: "Identifier";
name: string;
}
/** Code frame error for transformation issues */
interface CodeFrameError extends Error {
code: string;
loc: SourceLocation;
}
/** Template builder interface for generating AST patterns */
interface Template {
(substitutions?: Object): Node;
}
/** Babel visitor interface for AST traversal */
interface Visitor {
[key: string]: Function | Object;
}
/** Expression node types */
interface Expression extends Node {}
/** Pattern node types for function parameters */
interface Pattern extends Node {}
/** Block statement node for function bodies */
interface BlockStatement extends Node {
type: "BlockStatement";
body: Array<Statement>;
}
/** Statement node types */
interface Statement extends Node {}
/** Decorator node for class/method decorators */
interface Decorator extends Node {
type: "Decorator";
expression: Expression;
}The plugin should be ordered correctly with related transforms:
{
"plugins": [
"transform-decorators-legacy", // Must come before classes
"transform-class-properties", // Must come before classes
"transform-es2015-classes",
"transform-es2015-arrow-functions"
]
}The plugin is included in the babel-preset-es2015 preset:
{
"presets": [
["es2015", {
"loose": true // Applies loose mode to all applicable plugins
}]
]
}The transformed code is compatible with:
The plugin generates ES5-compatible code that runs in environments without native class support.