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 buildClassBody = function (body, className, superName, node) {
|
||||||
var instanceMutatorMap = {};
|
var instanceMutatorMap = {};
|
||||||
var staticMutatorMap = {};
|
var staticMutatorMap = {};
|
||||||
|
var hasConstructor = false;
|
||||||
|
|
||||||
|
var construct = body[0];
|
||||||
var classBody = node.body.body;
|
var classBody = node.body.body;
|
||||||
|
|
||||||
_.each(classBody, function (node) {
|
_.each(classBody, function (node) {
|
||||||
var methodName = node.key.name;
|
var methodName = node.key.name;
|
||||||
var method = node.value;
|
var method = node.value;
|
||||||
|
|
||||||
replaceInstanceSuperReferences(superName, method);
|
replaceInstanceSuperReferences(superName, method, methodName);
|
||||||
|
|
||||||
if (methodName === "constructor") {
|
if (methodName === "constructor") {
|
||||||
if (node.kind === "") {
|
if (node.kind === "") {
|
||||||
addConstructor(body[0], method);
|
hasConstructor = true;
|
||||||
|
addConstructor(construct, method);
|
||||||
} else {
|
} else {
|
||||||
throw util.errorWithNode(node, "unknown kind for constructor method");
|
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)) {
|
if (!_.isEmpty(instanceMutatorMap)) {
|
||||||
var protoId = util.template("prototype-identifier", {
|
var protoId = util.template("prototype-identifier", {
|
||||||
CLASS_NAME: className
|
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;
|
if (parent.property === node) return;
|
||||||
|
|
||||||
node.name = superName.name || superName.value;
|
node.name = superName.name || superName.value;
|
||||||
|
|
||||||
// super(); -> ClassName.call(this);
|
// super(); -> ClassName.prototype.MethodName.call(this);
|
||||||
if (parent.type === "CallExpression" && parent.callee === node) {
|
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());
|
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");
|
superName = superName || b.literal("Function");
|
||||||
|
|
||||||
traverse(method, function (node, parent) {
|
traverse(method, function (node, parent) {
|
||||||
if (node.type === "Identifier" && node.name === "super") {
|
if (node.type === "Identifier" && node.name === "super") {
|
||||||
superIdentifier(superName, node, parent);
|
superIdentifier(superName, methodName, 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;
|
|
||||||
}
|
|
||||||
} else if (node.type === "CallExpression") {
|
} else if (node.type === "CallExpression") {
|
||||||
var callee = node.callee;
|
var callee = node.callee;
|
||||||
if (callee.type !== "MemberExpression") return;
|
if (callee.type !== "MemberExpression") return;
|
||||||
if (callee.object.name !== "super") 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());
|
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) {
|
var addConstructor = function (construct, method) {
|
||||||
construct.defaults = method.defaults;
|
construct.defaults = method.defaults;
|
||||||
construct.params = method.params;
|
construct.params = method.params;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "6to5",
|
"name": "6to5",
|
||||||
"description": "Turn ES6 code into vanilla ES5 with source maps and no runtime",
|
"description": "Turn ES6 code into vanilla ES5 with source maps and no runtime",
|
||||||
"version": "1.7.4",
|
"version": "1.7.5",
|
||||||
"author": "Sebastian McKenzie <sebmck@gmail.com>",
|
"author": "Sebastian McKenzie <sebmck@gmail.com>",
|
||||||
"homepage": "https://github.com/sebmck/6to5",
|
"homepage": "https://github.com/sebmck/6to5",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
50
test/bin.js
Normal file
50
test/bin.js
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
var child = require("child_process");
|
||||||
|
var fs = require("fs");
|
||||||
|
|
||||||
|
var tmpLoc = __dirname + "/tmp";
|
||||||
|
|
||||||
|
var readTree = function () {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
var run = function (name, args, callback) {
|
||||||
|
args = [__dirname + "/../bin." + name].concat(args);
|
||||||
|
var spawn = child.spawn(process.execPath, args);
|
||||||
|
|
||||||
|
var data = "";
|
||||||
|
|
||||||
|
spawn.stdout.on("write", function (chunk) {
|
||||||
|
data += chunk;
|
||||||
|
});
|
||||||
|
|
||||||
|
spawn.on("close", function () {
|
||||||
|
callback(data);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
before(function () {
|
||||||
|
if (!fs.existsSync(tmpLoc)) fs.mkdirSync(tmpLoc);
|
||||||
|
process.chdir(tmpLoc);
|
||||||
|
});
|
||||||
|
|
||||||
|
suite("bin/6to5", function () {
|
||||||
|
test("--source-maps-inline");
|
||||||
|
|
||||||
|
test("--source-maps");
|
||||||
|
|
||||||
|
test("--whitelist");
|
||||||
|
|
||||||
|
test("--blacklist");
|
||||||
|
|
||||||
|
test("--out-file");
|
||||||
|
|
||||||
|
test("--out-dir");
|
||||||
|
|
||||||
|
test("stdout");
|
||||||
|
});
|
||||||
|
|
||||||
|
suite("bin/6to5-node", function () {
|
||||||
|
test("--eval");
|
||||||
|
|
||||||
|
test("--print");
|
||||||
|
});
|
||||||
@@ -5,4 +5,8 @@ class Test extends Foo {
|
|||||||
super.test();
|
super.test();
|
||||||
foob(super);
|
foob(super);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,5 +14,8 @@ var Test = function (Foo) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
Test.__proto__ = Foo;
|
Test.__proto__ = Foo;
|
||||||
|
Test.prototype.test = function () {
|
||||||
|
Foo.prototype.test.call(this);
|
||||||
|
};
|
||||||
return Test;
|
return Test;
|
||||||
}(Foo);
|
}(Foo);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
class Test extends Foo {
|
class Test extends Foo {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
super.test;
|
||||||
super.test.whatever;
|
super.test.whatever;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
18
test/fixtures/classes/accessing-super-properties/expected.js
vendored
Normal file
18
test/fixtures/classes/accessing-super-properties/expected.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
var Test = function(Foo) {
|
||||||
|
function Test() {
|
||||||
|
Foo.prototype.test;
|
||||||
|
Foo.prototype.test.whatever;
|
||||||
|
}
|
||||||
|
|
||||||
|
Test.prototype = Object.create(Foo.prototype, {
|
||||||
|
constructor: {
|
||||||
|
value: Test,
|
||||||
|
enumerable: false,
|
||||||
|
writable: true,
|
||||||
|
configurable: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Test.__proto__ = Foo;
|
||||||
|
return Test;
|
||||||
|
}(Foo);
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
class Test extends Foo {
|
class Test extends Foo {
|
||||||
constructor() {
|
constructor() {
|
||||||
super.test.whatever();
|
super.test.whatever();
|
||||||
|
super.test();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
16
test/fixtures/classes/calling-super-properties/expected.js
vendored
Normal file
16
test/fixtures/classes/calling-super-properties/expected.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
var Test = function(Foo) {
|
||||||
|
function Test() {
|
||||||
|
Foo.prototype.test.whatever();
|
||||||
|
Foo.prototype.test.call(this);
|
||||||
|
}
|
||||||
|
Test.prototype = Object.create(Foo.prototype, {
|
||||||
|
constructor: {
|
||||||
|
value: Test,
|
||||||
|
enumerable: false,
|
||||||
|
writable: true,
|
||||||
|
configurable: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Test.__proto__ = Foo;
|
||||||
|
return Test;
|
||||||
|
}(Foo);
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"throws": "cannot access super properties"
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"throws": "cannot access super properties"
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
var BaseController = function (Chaplin) {
|
var BaseController = function (Chaplin) {
|
||||||
function BaseController() {
|
function BaseController() {
|
||||||
|
Chaplin.Controller.call(this, arguments);
|
||||||
}
|
}
|
||||||
BaseController.prototype = Object.create(Chaplin.Controller.prototype, {
|
BaseController.prototype = Object.create(Chaplin.Controller.prototype, {
|
||||||
constructor: {
|
constructor: {
|
||||||
@@ -15,6 +16,7 @@ var BaseController = function (Chaplin) {
|
|||||||
|
|
||||||
var BaseController2 = function (Chaplin) {
|
var BaseController2 = function (Chaplin) {
|
||||||
function BaseController2() {
|
function BaseController2() {
|
||||||
|
Chaplin.Controller.Another.call(this, arguments);
|
||||||
}
|
}
|
||||||
BaseController2.prototype = Object.create(Chaplin.Controller.Another.prototype, {
|
BaseController2.prototype = Object.create(Chaplin.Controller.Another.prototype, {
|
||||||
constructor: {
|
constructor: {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
var Q = function(_ref) {
|
var Q = function(_ref) {
|
||||||
function Q() {}
|
function Q() {
|
||||||
|
_ref.call(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
Q.prototype = Object.create(_ref.prototype, {
|
Q.prototype = Object.create(_ref.prototype, {
|
||||||
constructor: {
|
constructor: {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
var Test = function (Foo) {
|
var Test = function (Foo) {
|
||||||
function Test() {
|
function Test() {
|
||||||
|
Foo.call(this, arguments);
|
||||||
}
|
}
|
||||||
Test.prototype = Object.create(Foo.prototype, {
|
Test.prototype = Object.create(Foo.prototype, {
|
||||||
constructor: {
|
constructor: {
|
||||||
|
|||||||
Reference in New Issue
Block a user