make super behaviour more spec compliant - fixes #32
This commit is contained in:
2
lib/6to5/templates/class-super-constructor-call.js
Normal file
2
lib/6to5/templates/class-super-constructor-call.js
Normal file
@@ -0,0 +1,2 @@
|
||||
SUPER_NAME.call(this, arguments);
|
||||
|
||||
@@ -71,18 +71,22 @@ var buildClass = function (node, generateUid) {
|
||||
|
||||
var buildClassBody = function (body, className, superName, node) {
|
||||
var instanceMutatorMap = {};
|
||||
var staticMutatorMap = {};
|
||||
var staticMutatorMap = {};
|
||||
var hasConstructor = false;
|
||||
|
||||
var construct = body[0];
|
||||
var classBody = node.body.body;
|
||||
|
||||
_.each(classBody, function (node) {
|
||||
var methodName = node.key.name;
|
||||
var method = node.value;
|
||||
|
||||
replaceInstanceSuperReferences(superName, method);
|
||||
replaceInstanceSuperReferences(superName, method, methodName);
|
||||
|
||||
if (methodName === "constructor") {
|
||||
if (node.kind === "") {
|
||||
addConstructor(body[0], method);
|
||||
hasConstructor = true;
|
||||
addConstructor(construct, method);
|
||||
} else {
|
||||
throw util.errorWithNode(node, "unknown kind for constructor method");
|
||||
}
|
||||
@@ -103,6 +107,12 @@ var buildClassBody = function (body, className, superName, node) {
|
||||
}
|
||||
});
|
||||
|
||||
if (!hasConstructor && superName) {
|
||||
construct.body.body.push(util.template("class-super-constructor-call", {
|
||||
SUPER_NAME: superName
|
||||
}, true));
|
||||
}
|
||||
|
||||
if (!_.isEmpty(instanceMutatorMap)) {
|
||||
var protoId = util.template("prototype-identifier", {
|
||||
CLASS_NAME: className
|
||||
@@ -116,51 +126,46 @@ var buildClassBody = function (body, className, superName, node) {
|
||||
}
|
||||
};
|
||||
|
||||
var superIdentifier = function (superName, node, parent) {
|
||||
var superIdentifier = function (superName, methodName, node, parent) {
|
||||
if (parent.property === node) return;
|
||||
|
||||
node.name = superName.name || superName.value;
|
||||
|
||||
// super(); -> ClassName.call(this);
|
||||
// super(); -> ClassName.prototype.MethodName.call(this);
|
||||
if (parent.type === "CallExpression" && parent.callee === node) {
|
||||
node.name += ".call";
|
||||
if (methodName === "constructor") {
|
||||
// constructor() { super(); }
|
||||
node.name += ".call";
|
||||
} else {
|
||||
// foo() { super(); }
|
||||
node.name += ".prototype." + methodName + ".call";
|
||||
}
|
||||
|
||||
parent.arguments.unshift(b.thisExpression());
|
||||
} else if (parent.type === "MemberExpression") {
|
||||
// super.test -> ClassName.prototype.test
|
||||
node.name += ".prototype";
|
||||
}
|
||||
};
|
||||
|
||||
var replaceInstanceSuperReferences = function (superName, method) {
|
||||
var replaceInstanceSuperReferences = function (superName, method, methodName) {
|
||||
superName = superName || b.literal("Function");
|
||||
|
||||
traverse(method, function (node, parent) {
|
||||
if (node.type === "Identifier" && node.name === "super") {
|
||||
superIdentifier(superName, node, parent);
|
||||
} else if (node.type === "MemberExpression") {
|
||||
// no accessing of super properties
|
||||
|
||||
if (isAccessingSuperProperties(parent, node)) {
|
||||
throw util.errorWithNode(node, "cannot access super properties");
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
superIdentifier(superName, methodName, node, parent);
|
||||
} else if (node.type === "CallExpression") {
|
||||
var callee = node.callee;
|
||||
if (callee.type !== "MemberExpression") return;
|
||||
if (callee.object.name !== "super") return;
|
||||
|
||||
callee.property.name = "prototype." + callee.property.name + ".call";
|
||||
// super.test(); -> Classname.prototype.MethodName.call(this);
|
||||
callee.property.name = callee.property.name + ".call";
|
||||
node.arguments.unshift(b.thisExpression());
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var isAccessingSuperProperties = function (parent, node) {
|
||||
var obj = node.object;
|
||||
return obj.type === "Identifier" && obj.name === "super" &&
|
||||
parent.object === node;
|
||||
};
|
||||
|
||||
var addConstructor = function (construct, method) {
|
||||
construct.defaults = method.defaults;
|
||||
construct.params = method.params;
|
||||
|
||||
Reference in New Issue
Block a user