Merge pull request #408 from 6to5/fix-esnext-class-tests

[WIP] Fix super with getters and setters and with class prototypes changing.
This commit is contained in:
Sebastian McKenzie
2015-01-09 07:22:35 +11:00
14 changed files with 230 additions and 76 deletions

View File

@@ -36,7 +36,8 @@ File.helpers = [
"interop-require-wildcard",
"typeof",
"exports-wildcard",
"extends"
"extends",
"get"
];
File.excludeHelpersFromRuntime = [

View File

@@ -1,3 +1,3 @@
if (SUPER_NAME !== null) {
SUPER_NAME.apply(this, arguments);
if (Object.getPrototypeOf(CLASS_NAME) !== null) {
Object.getPrototypeOf(CLASS_NAME).apply(this, arguments);
}

View File

@@ -0,0 +1,23 @@
(function get(object, property, receiver) {
var desc = Object.getOwnPropertyDescriptor(object, property);
if (desc === undefined) {
var parent = Object.getPrototypeOf(object);
if (parent === null) {
return undefined;
} else {
return get(parent);
}
} else if ("value" in desc && desc.writable) {
return desc.value;
} else {
var getter = desc.get;
if (getter === undefined) {
return undefined;
}
return getter.call(receiver);
}
});

View File

@@ -149,7 +149,7 @@ Class.prototype.buildBody = function () {
if (!this.hasConstructor && superName && !t.isFalsyExpression(superName)) {
constructor.body.body.push(util.template("class-super-constructor-call", {
SUPER_NAME: superName
CLASS_NAME: className
}, true));
}
@@ -215,45 +215,45 @@ Class.prototype.pushMethod = function (node) {
};
/**
* Given a `methodNode`, produce a `MemberExpression` super class reference.
* Gets a node representing the super class value of the named property.
*
* @param {Node} methodNode MethodDefinition
* @param {Node} node Identifier
* @param {Node} parent
* @example
*
* _get(Object.getPrototypeOf(CLASS.prototype), "METHOD", this)
*
* @param {Node} property
* @param {boolean} isStatic
* @param {boolean} isComputed
*
* @returns {Node}
*/
Class.prototype.superIdentifier = function (methodNode, id, parent) {
var methodName = methodNode.key;
var superName = this.superName || t.identifier("Function");
if (parent.property === id) {
return;
} else if (t.isCallExpression(parent, { callee: id })) {
// super(); -> ClassName.prototype.MethodName.call(this);
parent.arguments.unshift(t.thisExpression());
if (methodName.name === "constructor") {
// constructor() { super(); }
return t.memberExpression(superName, t.identifier("call"));
} else {
id = superName;
// foo() { super(); }
if (!methodNode.static) {
id = t.memberExpression(id, t.identifier("prototype"));
}
id = t.memberExpression(id, methodName, methodNode.computed);
return t.memberExpression(id, t.identifier("call"));
}
} else if (t.isMemberExpression(parent) && !methodNode.static) {
// super.test -> ClassName.prototype.test
return t.memberExpression(superName, t.identifier("prototype"));
} else {
return superName;
}
Class.prototype.superProperty = function (property, isStatic, isComputed) {
return t.callExpression(
this.file.addHelper("get"),
[
t.callExpression(
t.memberExpression(
t.identifier("Object"),
t.identifier("getPrototypeOf"),
false
),
[
isStatic ?
this.className :
t.memberExpression(
this.className,
t.identifier("prototype"),
false
)
]
),
isComputed ?
property :
t.literal(property.name),
t.thisExpression()
]
);
};
/**
@@ -268,16 +268,48 @@ Class.prototype.replaceInstanceSuperReferences = function (methodNode) {
traverse(method, {
enter: function (node, parent) {
var property;
var computed;
var args;
if (t.isIdentifier(node, { name: "super" })) {
return self.superIdentifier(methodNode, node, parent);
if (!(t.isMemberExpression(parent) && !parent.computed && parent.property === node)) {
throw self.file.errorWithNode(node, "illegal use of bare super");
}
} else if (t.isCallExpression(node)) {
var callee = node.callee;
if (!t.isMemberExpression(callee)) return;
if (callee.object.name !== "super") return;
if (t.isIdentifier(callee) && callee.name === "super") {
// super(); -> _get(Object.getPrototypeOf(ClassName), "MethodName", this).call(this);
property = methodNode.key;
computed = methodNode.computed;
args = node.arguments;
} else {
if (!t.isMemberExpression(callee)) return;
if (callee.object.name !== "super") return;
// super.test(); -> ClassName.prototype.MethodName.call(this);
t.appendToMemberExpression(callee, t.identifier("call"));
node.arguments.unshift(t.thisExpression());
// super.test(); -> _get(Object.getPrototypeOf(ClassName.prototype), "test", this).call(this);
property = callee.property;
computed = callee.computed;
args = node.arguments;
}
} else if (t.isMemberExpression(node)) {
if (!t.isIdentifier(node.object, { name: "super" })) return;
// super.name; -> _get(Object.getPrototypeOf(ClassName.prototype), "name", this);
property = node.property;
computed = node.computed;
}
if (property) {
var superProperty = self.superProperty(property, methodNode.static, computed);
if (args) {
return t.callExpression(
t.memberExpression(superProperty, t.identifier("call"), false),
[t.thisExpression()].concat(args)
);
} else {
return superProperty;
}
}
}
});

View File

@@ -3,7 +3,6 @@ class Test extends Foo {
woops.super.test();
super();
super.test();
foob(super);
super(...arguments);
super("test", ...arguments);

View File

@@ -1,6 +1,28 @@
"use strict";
var _slice = Array.prototype.slice;
var _get = function get(object, property, receiver) {
var desc = Object.getOwnPropertyDescriptor(object, property);
if (desc === undefined) {
var parent = Object.getPrototypeOf(object);
if (parent === null) {
return undefined;
} else {
return get(parent);
}
} else if ("value" in desc && desc.writable) {
return desc.value;
} else {
var getter = desc.get;
if (getter === undefined) {
return undefined;
}
return getter.call(receiver);
}
};
var _inherits = function (child, parent) {
if (typeof parent !== "function" && parent !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof parent);
@@ -19,34 +41,34 @@ var _inherits = function (child, parent) {
var Test = (function () {
var _Foo = Foo;
var Test = function Test() {
var _Foo$prototype$test, _Foo$prototype$test2;
var _get2, _get3, _get4, _get5;
woops["super"].test();
_Foo.call(this);
_Foo.prototype.test.call(this);
foob(_Foo);
_get(Object.getPrototypeOf(Test.prototype), "constructor", this).call(this);
_get(Object.getPrototypeOf(Test.prototype), "test", this).call(this);
_Foo.call.apply(_Foo, [this].concat(_slice.call(arguments)));
_Foo.call.apply(_Foo, [this, "test"].concat(_slice.call(arguments)));
(_get2 = _get(Object.getPrototypeOf(Test.prototype), "constructor", this)).call.apply(_get2, [this].concat(_slice.call(arguments)));
(_get3 = _get(Object.getPrototypeOf(Test.prototype), "constructor", this)).call.apply(_get3, [this, "test"].concat(_slice.call(arguments)));
(_Foo$prototype$test = _Foo.prototype.test).call.apply(_Foo$prototype$test, [this].concat(_slice.call(arguments)));
(_Foo$prototype$test2 = _Foo.prototype.test).call.apply(_Foo$prototype$test2, [this, "test"].concat(_slice.call(arguments)));
(_get4 = _get(Object.getPrototypeOf(Test.prototype), "test", this)).call.apply(_get4, [this].concat(_slice.call(arguments)));
(_get5 = _get(Object.getPrototypeOf(Test.prototype), "test", this)).call.apply(_get5, [this, "test"].concat(_slice.call(arguments)));
};
_inherits(Test, _Foo);
Test.prototype.test = function () {
var _Foo$prototype$test3, _Foo$prototype$test4;
_Foo.prototype.test.call(this);
(_Foo$prototype$test3 = _Foo.prototype.test).call.apply(_Foo$prototype$test3, [this].concat(_slice.call(arguments)));
(_Foo$prototype$test4 = _Foo.prototype.test).call.apply(_Foo$prototype$test4, [this, "test"].concat(_slice.call(arguments)));
var _get6, _get7;
_get(Object.getPrototypeOf(Test.prototype), "test", this).call(this);
(_get6 = _get(Object.getPrototypeOf(Test.prototype), "test", this)).call.apply(_get6, [this].concat(_slice.call(arguments)));
(_get7 = _get(Object.getPrototypeOf(Test.prototype), "test", this)).call.apply(_get7, [this, "test"].concat(_slice.call(arguments)));
};
Test.foo = function () {
var _Foo$foo, _Foo$foo2;
_Foo.foo.call(this);
(_Foo$foo = _Foo.foo).call.apply(_Foo$foo, [this].concat(_slice.call(arguments)));
(_Foo$foo2 = _Foo.foo).call.apply(_Foo$foo2, [this, "test"].concat(_slice.call(arguments)));
var _get8, _get9;
_get(Object.getPrototypeOf(Test), "foo", this).call(this);
(_get8 = _get(Object.getPrototypeOf(Test), "foo", this)).call.apply(_get8, [this].concat(_slice.call(arguments)));
(_get9 = _get(Object.getPrototypeOf(Test), "foo", this)).call.apply(_get9, [this, "test"].concat(_slice.call(arguments)));
};
return Test;
})();

View File

@@ -1,5 +1,27 @@
"use strict";
var _get = function get(object, property, receiver) {
var desc = Object.getOwnPropertyDescriptor(object, property);
if (desc === undefined) {
var parent = Object.getPrototypeOf(object);
if (parent === null) {
return undefined;
} else {
return get(parent);
}
} else if ("value" in desc && desc.writable) {
return desc.value;
} else {
var getter = desc.get;
if (getter === undefined) {
return undefined;
}
return getter.call(receiver);
}
};
var _inherits = function (child, parent) {
if (typeof parent !== "function" && parent !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof parent);
@@ -18,11 +40,12 @@ var _inherits = function (child, parent) {
var Test = (function () {
var _Foo = Foo;
var Test = function Test() {
_Foo.prototype.test;
_Foo.prototype.test.whatever;
_get(Object.getPrototypeOf(Test.prototype), "test", this);
_get(Object.getPrototypeOf(Test.prototype), "test", this).whatever;
};
_inherits(Test, _Foo);
return Test;
})();

View File

@@ -0,0 +1,5 @@
class Test {
constructor() {
console.log(super);
}
}

View File

@@ -0,0 +1,3 @@
{
"throws": "illegal use of bare super"
}

View File

@@ -1,5 +1,27 @@
"use strict";
var _get = function get(object, property, receiver) {
var desc = Object.getOwnPropertyDescriptor(object, property);
if (desc === undefined) {
var parent = Object.getPrototypeOf(object);
if (parent === null) {
return undefined;
} else {
return get(parent);
}
} else if ("value" in desc && desc.writable) {
return desc.value;
} else {
var getter = desc.get;
if (getter === undefined) {
return undefined;
}
return getter.call(receiver);
}
};
var _inherits = function (child, parent) {
if (typeof parent !== "function" && parent !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof parent);
@@ -18,15 +40,16 @@ var _inherits = function (child, parent) {
var Test = (function () {
var _Foo = Foo;
var Test = function Test() {
_Foo.prototype.test.whatever();
_Foo.prototype.test.call(this);
_get(Object.getPrototypeOf(Test.prototype), "test", this).whatever();
_get(Object.getPrototypeOf(Test.prototype), "test", this).call(this);
};
_inherits(Test, _Foo);
Test.test = function () {
return _Foo.wow.call(this);
return _get(Object.getPrototypeOf(Test), "wow", this).call(this);
};
return Test;
})();

View File

@@ -18,8 +18,8 @@ var _inherits = function (child, parent) {
var BaseController = (function () {
var _Chaplin$Controller = Chaplin.Controller;
var BaseController = function BaseController() {
if (_Chaplin$Controller !== null) {
_Chaplin$Controller.apply(this, arguments);
if (Object.getPrototypeOf(BaseController) !== null) {
Object.getPrototypeOf(BaseController).apply(this, arguments);
}
};
@@ -31,8 +31,8 @@ var BaseController = (function () {
var BaseController2 = (function () {
var _Chaplin$Controller$Another = Chaplin.Controller.Another;
var BaseController2 = function BaseController2() {
if (_Chaplin$Controller$Another !== null) {
_Chaplin$Controller$Another.apply(this, arguments);
if (Object.getPrototypeOf(BaseController2) !== null) {
Object.getPrototypeOf(BaseController2).apply(this, arguments);
}
};

View File

@@ -18,8 +18,8 @@ var _inherits = function (child, parent) {
var Test = (function () {
var _Foo = Foo;
var Test = function Test() {
if (_Foo !== null) {
_Foo.apply(this, arguments);
if (Object.getPrototypeOf(Test) !== null) {
Object.getPrototypeOf(Test).apply(this, arguments);
}
};

View File

@@ -1,5 +1,28 @@
"use strict";
var Test = function Test() {
Function.prototype.hasOwnProperty.call(this, "test");
var _get = function get(object, property, receiver) {
var desc = Object.getOwnPropertyDescriptor(object, property);
if (desc === undefined) {
var parent = Object.getPrototypeOf(object);
if (parent === null) {
return undefined;
} else {
return get(parent);
}
} else if ("value" in desc && desc.writable) {
return desc.value;
} else {
var getter = desc.get;
if (getter === undefined) {
return undefined;
}
return getter.call(receiver);
}
};
var Test = function Test() {
_get(Object.getPrototypeOf(Test.prototype), "hasOwnProperty", this).call(this, "test");
};

View File

@@ -28,8 +28,8 @@ var _inherits = function (child, parent) {
var Foo = (function () {
var _Bar = Bar;
var Foo = function Foo() {
if (_Bar !== null) {
_Bar.apply(this, arguments);
if (Object.getPrototypeOf(Foo) !== null) {
Object.getPrototypeOf(Foo).apply(this, arguments);
}
};