turn classes transformer into a class like let scoping
This commit is contained in:
@@ -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);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user