Babel plugin for turning __proto__ into a shallow property clone
npx @tessl/cli install tessl/npm-babel-plugin-transform-proto-to-assign@6.26.0This Babel plugin transforms JavaScript __proto__ property assignments into function calls that perform shallow copying of object properties. It addresses compatibility issues with __proto__ usage by converting these assignments to use helper functions (defaults and extends) that copy properties from the source object to the target object.
npm install --save-dev babel-plugin-transform-proto-to-assign// CommonJS (typical for Babel plugins)
const transformProtoToAssign = require("babel-plugin-transform-proto-to-assign");Note: This plugin is typically used through Babel configuration (.babelrc, CLI, or Node API) rather than direct imports. The plugin exports using ES6 export default but is consumed by Babel's plugin system.
{
"plugins": ["transform-proto-to-assign"]
}babel --plugins transform-proto-to-assign script.jsrequire("babel-core").transform("code", {
plugins: ["transform-proto-to-assign"]
});This plugin follows the standard Babel plugin architecture:
defaults and extends) for property copyingThe main entry point that creates the Babel plugin.
/**
* Main plugin factory function that creates a Babel transformation plugin
* @param {Object} babel - Babel API object containing types
* @param {Object} babel.types - Babel types utilities for AST manipulation
* @returns {Object} Babel plugin configuration object with visitor methods
*/
function transformProtoToAssign({ types: t }) {
// Returns visitor object
}The object returned by the main factory function.
/**
* Plugin configuration object structure (returned by factory function)
* @returns {Object} Plugin configuration with visitor methods
*/
{
visitor: {
AssignmentExpression: function(path, file) { /* ... */ },
ExpressionStatement: function(path, file) { /* ... */ },
ObjectExpression: function(path, file) { /* ... */ }
}
}Handles __proto__ assignments in assignment expressions like obj.__proto__ = value.
/**
* Transforms __proto__ assignment expressions
* @param {Object} path - AST node path for the assignment expression
* @param {Object} file - Babel file context for adding helper imports
*/
function AssignmentExpression(path, file) {
// Transforms assignment expressions containing __proto__
}Transformation Example:
// Input
console.log(foo.__proto__ = bar);
// Output
var _foo;
console.log((_foo = foo, babelHelpers.defaults(_foo, bar), _foo));Handles __proto__ assignments in expression statements like obj.__proto__ = value;.
/**
* Transforms __proto__ assignments in expression statements
* @param {Object} path - AST node path for the expression statement
* @param {Object} file - Babel file context for adding helper imports
*/
function ExpressionStatement(path, file) {
// Transforms expression statements containing __proto__ assignments
}Transformation Example:
// Input
obj.__proto__ = source;
// Output
babelHelpers.defaults(obj, source);Handles __proto__ properties in object literals like { __proto__: value, other: prop }.
/**
* Transforms __proto__ properties in object literals
* @param {Object} path - AST node path for the object expression
* @param {Object} file - Babel file context for adding helper imports
*/
function ObjectExpression(path, file) {
// Transforms object expressions containing __proto__ properties
}Transformation Example:
// Input
var foo = {
bar: "foo",
__proto__: source
};
// Output
var foo = babelHelpers.extends({}, source, {
bar: "foo"
});Internal Implementation Details: The plugin uses two internal helper functions:
isProtoKey(node): Checks if a property key is "proto"isProtoAssignmentExpression(node): Checks if an assignment targets "proto"/**
* Babel API objects and their key methods used by the plugin
*/
// Babel Types object (passed as { types: t } to plugin factory)
const babelTypes = {
isLiteral: function(node, opts) { /* checks if node is a literal */ },
isMemberExpression: function(node) { /* checks if node is member expression */ },
isAssignmentExpression: function(node, opts) { /* checks if node is assignment */ },
toComputedKey: function(node, key) { /* converts property to computed form */ },
expressionStatement: function(expression) { /* creates expression statement */ },
callExpression: function(callee, args) { /* creates function call */ },
assignmentExpression: function(operator, left, right) { /* creates assignment */ },
objectExpression: function(properties) { /* creates object literal */ }
};
// NodePath object (passed to visitor methods)
const nodePath = {
node: {}, // The AST node
scope: {}, // Scope information
replaceWith: function(replacement) { /* replace node with another */ },
replaceWithMultiple: function(replacements) { /* replace with multiple nodes */ }
};
// Babel File object (passed to visitor methods)
const babelFile = {
addHelper: function(name) { /* adds babel runtime helper import */ }
};
// Scope object (available on path.scope)
const scope = {
maybeGenerateMemoised: function(node) { /* generates temp variable if needed */ }
};defaults, extends)pull function)This plugin uses two Babel runtime helpers for property copying:
Used for __proto__ assignments. Copies properties from source to target object.
Used for object literals with __proto__ properties. Creates new objects by merging properties.
Important Limitation: This plugin creates shallow copies, not true prototypal inheritance. Changes to the source object after assignment will not be reflected in the target object.
// This will work as expected
var foo = { a: 1 };
var bar = { b: 2 };
bar.__proto__ = foo;
bar.a; // 1
bar.b; // 2
// This will NOT work as expected with the plugin
var foo = { a: 1 };
var bar = { b: 2 };
bar.__proto__ = foo;
bar.a; // 1
foo.a = 2;
bar.a; // 1 (still 1, should be 2 in true prototypal inheritance)