add classesFastSuper optional transformer - fixes #451

This commit is contained in:
Sebastian McKenzie
2015-01-12 10:19:22 +11:00
parent 2a4f03330b
commit 6131cea5b2
18 changed files with 320 additions and 1 deletions

View File

@@ -0,0 +1,5 @@
(function () {
if (SUPER_NAME != null) {
SUPER_NAME.apply(this, arguments);
}
});

View File

@@ -58,6 +58,7 @@ _.each({
arrayComprehension: require("./transformers/es7-array-comprehension"),
generatorComprehension: require("./transformers/es7-generator-comprehension"),
arrowFunctions: require("./transformers/es6-arrow-functions"),
classesFastSuper: require("./transformers/optional-classes-fast-super"),
classes: require("./transformers/es6-classes"),
objectSpread: require("./transformers/es7-object-spread"),

View File

@@ -291,7 +291,7 @@ Class.prototype.replaceInstanceSuperReferences = function (methodNode) {
*/
Class.prototype.pushConstructor = function (method) {
if (method.kind !== "") {
if (method.kind) {
throw this.file.errorWithNode(method, "illegal kind for constructor method");
}

View File

@@ -0,0 +1,74 @@
var traverse = require("../../traverse");
var util = require("../../util");
var t = require("../../types");
exports.optional = true;
exports.Class = function (node) {
var superClass = node.superClass || t.identifier("Function");
var hasConstructor = false;
var body = node.body.body;
for (var i in body) {
var methodNode = body[i];
hasConstructor = hasConstructor || methodNode.key.name === "constructor";
traverse(methodNode, {
enter: function (node, parent) {
if (t.isIdentifier(node, { name: "super" })) {
return superIdentifier(superClass, methodNode, node, parent);
} else if (t.isCallExpression(node)) {
var callee = node.callee;
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());
}
}
});
}
if (node.superClass && !hasConstructor) {
body.unshift(t.methodDefinition(
t.identifier("constructor"),
util.template("class-super-constructor-call-fast", {
SUPER_NAME: superClass
})
));
}
};
var superIdentifier = function (superClass, methodNode, id, parent) {
var methodName = methodNode.key;
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(superClass, t.identifier("call"));
} else {
id = superClass;
// 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(superClass, t.identifier("prototype"));
} else {
return superClass;
}
};

View File

@@ -16,6 +16,7 @@
"Literal": ["value"],
"LogicalExpression": ["operator", "left", "right"],
"MemberExpression": ["object", "property", "computed"],
"MethodDefinition": ["key", "value", "computed", "kind"],
"NewExpression": ["callee", "arguments"],
"ObjectExpression": ["properties"],
"Program": ["body"],

View File

@@ -0,0 +1,25 @@
class Test extends Foo {
constructor() {
woops.super.test();
super();
super.test();
super(...arguments);
super("test", ...arguments);
super.test(...arguments);
super.test("test", ...arguments);
}
test() {
super();
super(...arguments);
super("test", ...arguments);
}
static foo() {
super();
super(...arguments);
super("test", ...arguments);
}
}

View File

@@ -0,0 +1,50 @@
"use strict";
var _slice = Array.prototype.slice;
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);
}
child.prototype = Object.create(parent && parent.prototype, {
constructor: {
value: child,
enumerable: false,
writable: true,
configurable: true
}
});
if (parent) child.__proto__ = parent;
};
var Test = (function (Foo) {
var Test = function Test() {
var _Foo$prototype$test, _Foo$prototype$test2;
woops["super"].test();
Foo.call(this);
Foo.prototype.test.call(this);
Foo.call.apply(Foo, [this].concat(_slice.call(arguments)));
Foo.call.apply(Foo, [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)));
};
_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)));
};
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)));
};
return Test;
})(Foo);

View File

@@ -0,0 +1,6 @@
class Test extends Foo {
constructor() {
super.test;
super.test.whatever;
}
}

View File

@@ -0,0 +1,27 @@
"use strict";
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);
}
child.prototype = Object.create(parent && parent.prototype, {
constructor: {
value: child,
enumerable: false,
writable: true,
configurable: true
}
});
if (parent) child.__proto__ = parent;
};
var Test = (function (Foo) {
var Test = function Test() {
Foo.prototype.test;
Foo.prototype.test.whatever;
};
_inherits(Test, Foo);
return Test;
})(Foo);

View File

@@ -0,0 +1,10 @@
class Test extends Foo {
constructor() {
super.test.whatever();
super.test();
}
static test() {
return super.wow();
}
}

View File

@@ -0,0 +1,31 @@
"use strict";
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);
}
child.prototype = Object.create(parent && parent.prototype, {
constructor: {
value: child,
enumerable: false,
writable: true,
configurable: true
}
});
if (parent) child.__proto__ = parent;
};
var Test = (function (Foo) {
var Test = function Test() {
Foo.prototype.test.whatever();
Foo.prototype.test.call(this);
};
_inherits(Test, Foo);
Test.test = function () {
return Foo.wow.call(this);
};
return Test;
})(Foo);

View File

@@ -0,0 +1,3 @@
{
"optional": ["classesFastSuper"]
}

View File

@@ -0,0 +1,7 @@
class BaseController extends Chaplin.Controller {
}
class BaseController2 extends Chaplin.Controller.Another {
}

View File

@@ -0,0 +1,40 @@
"use strict";
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);
}
child.prototype = Object.create(parent && parent.prototype, {
constructor: {
value: child,
enumerable: false,
writable: true,
configurable: true
}
});
if (parent) child.__proto__ = parent;
};
var BaseController = (function (_Chaplin$Controller) {
var BaseController = function BaseController() {
if (Chaplin.Controller != null) {
Chaplin.Controller.apply(this, arguments);
}
};
_inherits(BaseController, _Chaplin$Controller);
return BaseController;
})(Chaplin.Controller);
var BaseController2 = (function (_Chaplin$Controller$Another) {
var BaseController2 = function BaseController2() {
if (Chaplin.Controller.Another != null) {
Chaplin.Controller.Another.apply(this, arguments);
}
};
_inherits(BaseController2, _Chaplin$Controller$Another);
return BaseController2;
})(Chaplin.Controller.Another);

View File

@@ -0,0 +1 @@
class Test extends Foo { }

View File

@@ -0,0 +1,28 @@
"use strict";
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);
}
child.prototype = Object.create(parent && parent.prototype, {
constructor: {
value: child,
enumerable: false,
writable: true,
configurable: true
}
});
if (parent) child.__proto__ = parent;
};
var Test = (function (Foo) {
var Test = function Test() {
if (Foo != null) {
Foo.apply(this, arguments);
}
};
_inherits(Test, Foo);
return Test;
})(Foo);

View File

@@ -0,0 +1,5 @@
class Test {
constructor() {
super.hasOwnProperty("test");
}
}

View File

@@ -0,0 +1,5 @@
"use strict";
var Test = function Test() {
Function.prototype.hasOwnProperty.call(this, "test");
};