diff --git a/lib/6to5/transformation/transformers/classes.js b/lib/6to5/transformation/transformers/classes.js index a05d08751b..758351db41 100644 --- a/lib/6to5/transformation/transformers/classes.js +++ b/lib/6to5/transformation/transformers/classes.js @@ -5,12 +5,12 @@ var _ = require("lodash"); exports.ClassDeclaration = function (node, parent, file, scope) { return t.variableDeclaration("var", [ - t.variableDeclarator(node.id, buildClass(node, file, scope)) + t.variableDeclarator(node.id, new Class(node, file, scope).run()) ]); }; exports.ClassExpression = function (node, parent, file, scope) { - return buildClass(node, file, scope); + return new Class(node, file, scope).run(); }; var getMemberExpressionObject = function (node) { @@ -20,31 +20,58 @@ var getMemberExpressionObject = function (node) { return node; }; -var buildClass = function (node, file, scope) { - var superName = node.superClass; - var className = node.id || t.identifier(file.generateUid("class", scope)); +/** + * Description + * + * @param {Node} node + * @param {File} file + * @param {Scope} scope + */ - var superClassArgument = node.superClass; - var superClassCallee = node.superClass; +function Class(node, file, scope) { + this.scope = scope; + this.node = node; + this.file = file; + + this.hasConstructor = false; + + this.className = node.id || t.identifier(file.generateUid("class", scope)); + this.superName = node.superClass; +} + +/** + * Description + * + * @returns {Array} + */ + +Class.prototype.run = function () { + var superClassArgument = this.superName; + var superClassCallee = this.superName; + var superName = this.superName; + var className = this.className; + var file = this.file; if (superName) { if (t.isMemberExpression(superName)) { superClassArgument = superClassCallee = getMemberExpressionObject(superName); } else if (!t.isIdentifier(superName)) { superClassArgument = superName; - superClassCallee = superName = t.identifier(file.generateUid("ref", scope)); + superClassCallee = superName = t.identifier(file.generateUid("ref", this.scope)); } } + this.superName = superName; + var container = util.template("class", { CLASS_NAME: className }); var block = container.callee.expression.body; - var body = block.body; - var constructor = body[0].declarations[0].init; + var body = this.body = block.body; + var constructor = this.constructor = body[0].declarations[0].init; - if (node.id) constructor.id = className; + if (this.node.id) constructor.id = className; var returnStatement = body.pop(); @@ -55,14 +82,7 @@ var buildClass = function (node, file, scope) { container.callee.expression.params.push(superClassCallee); } - buildClassBody({ - file: file, - body: body, - node: node, - className: className, - superName: superName, - constructor: constructor, - }); + this.buildBody(); if (body.length === 1) { // only a constructor so no need for a closure container @@ -73,32 +93,32 @@ var buildClass = function (node, file, scope) { } }; -var buildClassBody = function (opts) { - var file = opts.file; - var body = opts.body; - var node = opts.node; - var constructor = opts.constructor; - var className = opts.className; - var superName = opts.superName; +/** + * Description + */ + +Class.prototype.buildBody = function () { + var constructor = this.constructor; + var className = this.className; + var superName = this.superName; + var classBody = this.node.body.body; + var body = this.body; + var self = this; var instanceMutatorMap = {}; var staticMutatorMap = {}; - var hasConstructor = false; - - var classBody = node.body.body; _.each(classBody, function (node) { var methodName = node.key; var method = node.value; - replaceInstanceSuperReferences(superName, node); + self.replaceInstanceSuperReferences(node); if (node.key.name === "constructor") { if (node.kind === "") { - hasConstructor = true; - addConstructor(constructor, method); + self.addConstructor(method); } else { - throw file.errorWithNode(node, "illegal kind for constructor method"); + throw self.file.errorWithNode(node, "illegal kind for constructor method"); } } else { var mutatorMap = instanceMutatorMap; @@ -115,7 +135,7 @@ var buildClassBody = function (opts) { } }); - if (!hasConstructor && superName) { + if (!this.hasConstructor && superName) { constructor.body.body.push(util.template("class-super-constructor-call", { SUPER_NAME: superName }, true)); @@ -143,17 +163,28 @@ var buildClassBody = function (opts) { if (instanceProps) args.push(instanceProps); body.push(t.expressionStatement( - t.callExpression(file.addDeclaration("class-props"), args) + t.callExpression(this.file.addDeclaration("class-props"), args) )); } }; -var superIdentifier = function (superName, methodNode, node, parent) { - var methodName = methodNode.key; +/** + * Description + * + * @param {Node} methodNode MethodDefinition + * @param {Node} node Identifier + * @param {Node} parent + * + * @returns {Node} + */ - if (parent.property === 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: node })) { + } else if (t.isCallExpression(parent, { callee: id })) { // super(); -> ClassName.prototype.MethodName.call(this); parent.arguments.unshift(t.thisExpression()); @@ -161,15 +192,15 @@ var superIdentifier = function (superName, methodNode, node, parent) { // constructor() { super(); } return t.memberExpression(superName, t.identifier("call")); } else { - node = superName; + id = superName; // foo() { super(); } if (!methodNode.static) { - node = t.memberExpression(node, t.identifier("prototype")); + id = t.memberExpression(id, t.identifier("prototype")); } - node = t.memberExpression(node, methodName, methodNode.computed); - return t.memberExpression(node, t.identifier("call")); + 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 @@ -179,14 +210,19 @@ var superIdentifier = function (superName, methodNode, node, parent) { } }; -var replaceInstanceSuperReferences = function (superName, methodNode) { - var method = methodNode.value; +/** + * Description + * + * @param {Node} methodNode MethodDefinition + */ - superName = superName || t.identifier("Function"); +Class.prototype.replaceInstanceSuperReferences = function (methodNode) { + var method = methodNode.value; + var self = this; traverse(method, function (node, parent) { if (t.isIdentifier(node, { name: "super" })) { - return superIdentifier(superName, methodNode, node, parent); + return self.superIdentifier(methodNode, node, parent); } else if (t.isCallExpression(node)) { var callee = node.callee; if (!t.isMemberExpression(callee)) return; @@ -199,11 +235,18 @@ var replaceInstanceSuperReferences = function (superName, methodNode) { }); }; -var addConstructor = function (construct, method) { +/** + * Description + */ + +Class.prototype.addConstructor = function (method) { + this.hasConstructor = true; + + var construct = this.constructor; + t.inherits(construct, method); + construct.defaults = method.defaults; construct.params = method.params; construct.body = method.body; construct.rest = method.rest; - - t.inherits(construct, method); };