Babel plugin that transforms ES2015 object super references to ES5-compatible code
npx @tessl/cli install tessl/npm-babel--plugin-transform-object-super@7.27.0@babel/plugin-transform-object-super is a Babel plugin that transforms ES2015 object super references to ES5-compatible code. It handles super property access and method calls within object methods by replacing them with equivalent expressions that work in ES5 environments.
npm install --save-dev @babel/plugin-transform-object-super// CommonJS
const plugin = require("@babel/plugin-transform-object-super");
// ESM (module type)
import plugin from "@babel/plugin-transform-object-super";Add the plugin to your Babel configuration:
// babel.config.js
module.exports = {
plugins: [
"@babel/plugin-transform-object-super"
]
};// .babelrc
{
"plugins": ["@babel/plugin-transform-object-super"]
}Example 1: Super Property Access
Input (ES2015 with object super):
var o = {
m() {
return super.x;
}
};Output (ES5 compatible):
var _obj;
var o = _obj = {
m: function () {
return babelHelpers.superPropGet(_obj, "x", this);
}
};Example 2: Super Method Call
Input:
var parent = {
getName() {
return "Parent";
}
};
var child = {
getName() {
return super.getName() + " Child";
}
};
Object.setPrototypeOf(child, parent);Output:
var _obj;
var parent = {
getName: function getName() {
return "Parent";
}
};
var child = _obj = {
getName: function getName() {
return babelHelpers.superPropGet(_obj, "getName", this).call(this) + " Child";
}
};
Object.setPrototypeOf(child, parent);Example 3: Loop Handling with Let Declarations
Input:
const objects = [];
for (const proto of [{x: 0}, {x: 1}]) {
if(true) {
objects.push({
__proto__: proto,
foo() {
return super.x
}
});
}
}Output:
const objects = [];
for (const proto of [{
x: 0
}, {
x: 1
}]) {
let _obj;
if (true) {
objects.push(_obj = {
__proto__: proto,
foo: function () {
return babelHelpers.superPropGet(_obj, "x", this);
}
});
}
}The plugin uses the Babel plugin factory pattern and consists of several key components:
@babel/helper-plugin-utils declare() function to create the plugin@babel/helper-replace-supers for the actual transformation logicObjectExpression and Loop visitors for AST transformationlet declarations in loops and var elsewhereThe plugin processes object expressions containing methods with super references, generates unique identifiers for object references, and delegates the actual super transformation to the ReplaceSupers helper.
The main export is a Babel plugin created using the declare helper from @babel/helper-plugin-utils.
import { declare } from "@babel/helper-plugin-utils";
declare(api => {
api.assertVersion(REQUIRED_VERSION(7));
return {
name: "transform-object-super",
visitor: {
Loop: LoopVisitor,
ObjectExpression: ObjectExpressionVisitor
}
};
});
function REQUIRED_VERSION(version: number): string | number;The plugin factory returns a configuration object with visitor methods for AST transformation.
interface BabelPlugin {
/** Plugin identifier name */
name: "transform-object-super";
/** AST visitor object containing transformation methods */
visitor: {
Loop: {
exit(path: NodePath): void;
};
ObjectExpression(path: NodePath<t.ObjectExpression>, state: PluginPass): void;
};
}The plugin includes an internal helper function for replacing super references in object methods.
function replacePropertySuper(
path: NodePath<t.ObjectMethod>,
getObjectRef: () => t.Identifier,
file: File
): void;Handles variable scoping for object references in loops, using let declarations for proper block scoping.
interface LoopVisitor {
exit(path: NodePath): void;
}The loop visitor:
let declarationslet bindings to the appropriate scopeTransforms object expressions containing methods with super references.
interface ObjectExpressionVisitor {
(path: NodePath<t.ObjectExpression>, state: PluginPass): void;
}The ObjectExpression visitor:
replacePropertySuperlet vs var)The plugin uses the @babel/helper-replace-supers helper for the actual super transformation.
import ReplaceSupers from "@babel/helper-replace-supers";
// Usage within the plugin
const replaceSupers = new ReplaceSupers({
getObjectRef: () => t.Identifier,
methodPath: NodePath<t.ObjectMethod>,
file: File
});
replaceSupers.replace();The plugin requires these packages:
// Core dependencies
"@babel/helper-plugin-utils": "workspace:^"
"@babel/helper-replace-supers": "workspace:^"
// Peer dependency
"@babel/core": "^7.0.0-0"
// Imported types and utilities
import { types as t } from "@babel/core";
import type { File, NodePath, PluginPass } from "@babel/core";// Node.js compatibility
engines: {
node: ">=6.9.0"
}
// Babel version requirement
api.assertVersion(REQUIRED_VERSION(7))import type {
File,
NodePath,
PluginPass
} from "@babel/core";
import { types as t } from "@babel/core";
// Core Babel AST types used
type ObjectExpression = t.ObjectExpression;
type ObjectMethod = t.ObjectMethod;
type Identifier = t.Identifier;
type AssignmentExpression = t.AssignmentExpression;
interface NodePath<T = t.Node> {
node: T;
scope: Scope;
get(key: string): NodePath | NodePath[];
isMethod(): boolean;
findParent(predicate: (path: NodePath) => boolean): NodePath | null;
replaceWith(replacement: t.Node): void;
requeue(): void;
isFunction(): boolean;
isProgram(): boolean;
isLoop(): boolean;
}
interface Scope {
generateUidIdentifier(name: string): t.Identifier;
push(binding: { id: t.Identifier; kind: "var" | "let" }): void;
crawl(): void;
}
interface PluginPass {
file: File;
opts: any;
}The plugin performs the following transformations:
super.property to babelHelpers.superPropGet(obj, "property", this)super.method() to babelHelpers.superPropGet(obj, "method", this).call(this)_obj, _obj2, etc.) for each object containing super referenceslet declarations for object references within loops, var declarations elsewhereThe plugin handles various edge cases:
api.assertVersion()t.cloneNode()This plugin is essential for:
Object.setPrototypeOf