add support for super in object literals - fixes #411
This commit is contained in:
parent
eb14f1da00
commit
c0af67eca1
@ -2,19 +2,24 @@
|
|||||||
|
|
||||||
module.exports = ReplaceSupers;
|
module.exports = ReplaceSupers;
|
||||||
|
|
||||||
var t = require("../../types");
|
var util = require("../../util");
|
||||||
|
var t = require("../../types");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description
|
* Description
|
||||||
*
|
*
|
||||||
* @param {Object} opts
|
* @param {Object} opts
|
||||||
|
* @param {Boolean} [inClass]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ReplaceSupers(opts) {
|
function ReplaceSupers(opts, inClass) {
|
||||||
this.topLevelThisReference = null;
|
this.topLevelThisReference = opts.topLevelThisReference;
|
||||||
this.methodNode = opts.methodNode;
|
this.methodNode = opts.methodNode;
|
||||||
this.className = opts.className;
|
this.className = opts.className;
|
||||||
this.superName = opts.superName;
|
this.superName = opts.superName;
|
||||||
|
this.isStatic = opts.isStatic;
|
||||||
|
this.hasSuper = false;
|
||||||
|
this.inClass = inClass;
|
||||||
this.isLoose = opts.isLoose;
|
this.isLoose = opts.isLoose;
|
||||||
this.scope = opts.scope;
|
this.scope = opts.scope;
|
||||||
this.file = opts.file;
|
this.file = opts.file;
|
||||||
@ -28,19 +33,21 @@ function ReplaceSupers(opts) {
|
|||||||
* _set(Object.getPrototypeOf(CLASS.prototype), "METHOD", "VALUE", this)
|
* _set(Object.getPrototypeOf(CLASS.prototype), "METHOD", "VALUE", this)
|
||||||
*
|
*
|
||||||
* @param {Node} property
|
* @param {Node} property
|
||||||
* @param {boolean} isStatic
|
* @param {Node} value
|
||||||
* @param {boolean} isComputed
|
* @param {Boolean} isComputed
|
||||||
|
* @param {Node} thisExpression
|
||||||
*
|
*
|
||||||
* @returns {Node}
|
* @returns {Node}
|
||||||
*/
|
*/
|
||||||
ReplaceSupers.prototype.setSuperProperty = function (property, value, isStatic, isComputed, thisExpression) {
|
|
||||||
|
ReplaceSupers.prototype.setSuperProperty = function (property, value, isComputed, thisExpression) {
|
||||||
return t.callExpression(
|
return t.callExpression(
|
||||||
this.file.addHelper("set"),
|
this.file.addHelper("set"),
|
||||||
[
|
[
|
||||||
t.callExpression(
|
t.callExpression(
|
||||||
t.memberExpression(t.identifier("Object"), t.identifier("getPrototypeOf")),
|
t.memberExpression(t.identifier("Object"), t.identifier("getPrototypeOf")),
|
||||||
[
|
[
|
||||||
isStatic ? this.className : t.memberExpression(this.className, t.identifier("prototype"))
|
this.isStatic ? this.className : t.memberExpression(this.className, t.identifier("prototype"))
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
isComputed ? property : t.literal(property.name),
|
isComputed ? property : t.literal(property.name),
|
||||||
@ -58,20 +65,20 @@ ReplaceSupers.prototype.setSuperProperty = function (property, value, isStatic,
|
|||||||
* _get(Object.getPrototypeOf(CLASS.prototype), "METHOD", this)
|
* _get(Object.getPrototypeOf(CLASS.prototype), "METHOD", this)
|
||||||
*
|
*
|
||||||
* @param {Node} property
|
* @param {Node} property
|
||||||
* @param {boolean} isStatic
|
* @param {Boolean} isComputed
|
||||||
* @param {boolean} isComputed
|
* @param {Node} thisExpression
|
||||||
*
|
*
|
||||||
* @returns {Node}
|
* @returns {Node}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ReplaceSupers.prototype.getSuperProperty = function (property, isStatic, isComputed, thisExpression) {
|
ReplaceSupers.prototype.getSuperProperty = function (property, isComputed, thisExpression) {
|
||||||
return t.callExpression(
|
return t.callExpression(
|
||||||
this.file.addHelper("get"),
|
this.file.addHelper("get"),
|
||||||
[
|
[
|
||||||
t.callExpression(
|
t.callExpression(
|
||||||
t.memberExpression(t.identifier("Object"), t.identifier("getPrototypeOf")),
|
t.memberExpression(t.identifier("Object"), t.identifier("getPrototypeOf")),
|
||||||
[
|
[
|
||||||
isStatic ? this.className : t.memberExpression(this.className, t.identifier("prototype"))
|
this.isStatic ? this.className : t.memberExpression(this.className, t.identifier("prototype"))
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
isComputed ? property : t.literal(property.name),
|
isComputed ? property : t.literal(property.name),
|
||||||
@ -153,7 +160,8 @@ ReplaceSupers.prototype.getThisReference = function () {
|
|||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ReplaceSupers.prototype.getLooseSuperProperty = function (methodNode, id, parent) {
|
ReplaceSupers.prototype.getLooseSuperProperty = function (id, parent) {
|
||||||
|
var methodNode = this.methodNode;
|
||||||
var methodName = methodNode.key;
|
var methodName = methodNode.key;
|
||||||
var superName = this.superName || t.identifier("Function");
|
var superName = this.superName || t.identifier("Function");
|
||||||
|
|
||||||
@ -195,13 +203,15 @@ ReplaceSupers.prototype.getLooseSuperProperty = function (methodNode, id, parent
|
|||||||
|
|
||||||
ReplaceSupers.prototype.looseHandle = function (getThisReference, node, parent) {
|
ReplaceSupers.prototype.looseHandle = function (getThisReference, node, parent) {
|
||||||
if (t.isIdentifier(node, { name: "super" })) {
|
if (t.isIdentifier(node, { name: "super" })) {
|
||||||
return this.getLooseSuperProperty(this.methodNode, node, parent);
|
this.hasSuper = true;
|
||||||
|
return this.getLooseSuperProperty(node, parent);
|
||||||
} else if (t.isCallExpression(node)) {
|
} else if (t.isCallExpression(node)) {
|
||||||
var callee = node.callee;
|
var callee = node.callee;
|
||||||
if (!t.isMemberExpression(callee)) return;
|
if (!t.isMemberExpression(callee)) return;
|
||||||
if (callee.object.name !== "super") return;
|
if (callee.object.name !== "super") return;
|
||||||
|
|
||||||
// super.test(); -> ClassName.prototype.MethodName.call(this);
|
// super.test(); -> ClassName.prototype.MethodName.call(this);
|
||||||
|
this.hasSuper = true;
|
||||||
t.appendToMemberExpression(callee, t.identifier("call"));
|
t.appendToMemberExpression(callee, t.identifier("call"));
|
||||||
node.arguments.unshift(getThisReference());
|
node.arguments.unshift(getThisReference());
|
||||||
}
|
}
|
||||||
@ -237,7 +247,7 @@ ReplaceSupers.prototype.specHandle = function (getThisReference, node, parent) {
|
|||||||
// bare `super` call is illegal inside non-constructors
|
// bare `super` call is illegal inside non-constructors
|
||||||
// - https://esdiscuss.org/topic/super-call-in-methods
|
// - https://esdiscuss.org/topic/super-call-in-methods
|
||||||
// - https://twitter.com/wycats/status/544553184396836864
|
// - https://twitter.com/wycats/status/544553184396836864
|
||||||
if (methodNode.key.name !== "constructor") {
|
if (methodNode.key.name !== "constructor" || !this.inClass) {
|
||||||
var methodName = methodNode.key.name || "METHOD_NAME";
|
var methodName = methodNode.key.name || "METHOD_NAME";
|
||||||
throw this.file.errorWithNode(node, "Direct super call is illegal in non-constructor, use super." + methodName + "() instead");
|
throw this.file.errorWithNode(node, "Direct super call is illegal in non-constructor, use super." + methodName + "() instead");
|
||||||
}
|
}
|
||||||
@ -253,13 +263,16 @@ ReplaceSupers.prototype.specHandle = function (getThisReference, node, parent) {
|
|||||||
computed = node.computed;
|
computed = node.computed;
|
||||||
} else if (t.isAssignmentExpression(node) && isSuper(node.left.object, node.left) && methodNode.kind === "set") {
|
} else if (t.isAssignmentExpression(node) && isSuper(node.left.object, node.left) && methodNode.kind === "set") {
|
||||||
// super.name = "val"; -> _set(Object.getPrototypeOf(ClassName.prototype), "name", this);
|
// super.name = "val"; -> _set(Object.getPrototypeOf(ClassName.prototype), "name", this);
|
||||||
return this.setSuperProperty(node.left.property, node.right, methodNode.static, node.left.computed, getThisReference());
|
this.hasSuper = true;
|
||||||
|
return this.setSuperProperty(node.left.property, node.right, node.left.computed, getThisReference());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!property) return;
|
if (!property) return;
|
||||||
|
|
||||||
|
this.hasSuper = true;
|
||||||
|
|
||||||
thisReference = getThisReference();
|
thisReference = getThisReference();
|
||||||
var superProperty = this.getSuperProperty(property, methodNode.static, computed, thisReference);
|
var superProperty = this.getSuperProperty(property, computed, thisReference);
|
||||||
if (args) {
|
if (args) {
|
||||||
if (args.length === 1 && t.isSpreadElement(args[0])) {
|
if (args.length === 1 && t.isSpreadElement(args[0])) {
|
||||||
// super(...arguments);
|
// super(...arguments);
|
||||||
|
|||||||
@ -152,10 +152,11 @@ Class.prototype.buildBody = function () {
|
|||||||
methodNode: node,
|
methodNode: node,
|
||||||
className: this.className,
|
className: this.className,
|
||||||
superName: this.superName,
|
superName: this.superName,
|
||||||
|
isStatic: node.static,
|
||||||
isLoose: this.isLoose,
|
isLoose: this.isLoose,
|
||||||
scope: this.scope,
|
scope: this.scope,
|
||||||
file: this.file
|
file: this.file
|
||||||
});
|
}, true);
|
||||||
replaceSupers.replace();
|
replaceSupers.replace();
|
||||||
|
|
||||||
if (node.key.name === "constructor") {
|
if (node.key.name === "constructor") {
|
||||||
|
|||||||
31
lib/6to5/transformation/transformers/es6/object-super.js
Normal file
31
lib/6to5/transformation/transformers/es6/object-super.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
var ReplaceSupers = require("../../helpers/replace-supers");
|
||||||
|
var util = require("../../../util");
|
||||||
|
var t = require("../../../types");
|
||||||
|
|
||||||
|
exports.Property = function (node, parent, scope, file) {
|
||||||
|
if (!node.method) return;
|
||||||
|
|
||||||
|
var value = node.value;
|
||||||
|
var thisExpr = scope.generateUidIdentifier("this");
|
||||||
|
|
||||||
|
var replaceSupers = new ReplaceSupers({
|
||||||
|
topLevelThisReference: thisExpr,
|
||||||
|
methodNode: node,
|
||||||
|
className: thisExpr,
|
||||||
|
isStatic: true,
|
||||||
|
scope: scope,
|
||||||
|
file: file
|
||||||
|
});
|
||||||
|
|
||||||
|
replaceSupers.replace();
|
||||||
|
|
||||||
|
if (replaceSupers.hasSuper) {
|
||||||
|
value.body.body.unshift(
|
||||||
|
t.variableDeclaration("var", [
|
||||||
|
t.variableDeclarator(thisExpr, t.thisExpression())
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -28,6 +28,7 @@ module.exports = {
|
|||||||
asyncToGenerator: require("./other/async-to-generator"),
|
asyncToGenerator: require("./other/async-to-generator"),
|
||||||
bluebirdCoroutines: require("./other/bluebird-coroutines"),
|
bluebirdCoroutines: require("./other/bluebird-coroutines"),
|
||||||
|
|
||||||
|
"es6.objectSuper": require("./es6/object-super"),
|
||||||
"es7.objectRestSpread": require("./es7/object-rest-spread"),
|
"es7.objectRestSpread": require("./es7/object-rest-spread"),
|
||||||
"es7.exponentiationOperator": require("./es7/exponentiation-operator"),
|
"es7.exponentiationOperator": require("./es7/exponentiation-operator"),
|
||||||
"es6.spread": require("./es6/spread"),
|
"es6.spread": require("./es6/spread"),
|
||||||
|
|||||||
15
test/fixtures/transformation/es6-object-super/simple.js
vendored
Normal file
15
test/fixtures/transformation/es6-object-super/simple.js
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
var a = {
|
||||||
|
name() {
|
||||||
|
return "Suyash";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var b = {
|
||||||
|
name() {
|
||||||
|
return super.name() + " Verma";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.setPrototypeOf(b, a);
|
||||||
|
|
||||||
|
assert.equal(b.name(), "Suyash Verma");
|
||||||
Loading…
x
Reference in New Issue
Block a user