'use strict';
var objectPatternF = require('nodes');
var nodes = objectPatternF.nodes;
var syntax = require('nodes/syntax.json');
var objectPatternE = require('./spread');
var applyContext = objectPatternE.applyContext;
var objectPatternD = require('../util/insertion');
var insertAfter = objectPatternD.insertAfter;
var objectPatternC = require('../util/string');
var express = objectPatternC.express, upper = objectPatternC.upper;
var objectPatternB = require('../util/id');
var getUniqueId = objectPatternB.getUniqueId;
var objectPatternA = require('../util/extend');
var getExtendId = objectPatternA.getExtendId;
var objectPattern = require('../util/self');
var getSelfId = objectPattern.getSelfId;
function classify(program) {
program.search('#Class').forEach(function (node) {
var definitions = node.body.body;
if (!node.id && node.parentNode.type === syntax.VariableDeclarator) {
node.id = new nodes.Identifier({ name: upper(node.parentNode.id.name) });
}
if (!node.id) {
node.id = getUniqueId(node, 'Class');
}
var name = node.id.name;
var getPrototypeOfNamePrototype = 'Object.getPrototypeOf(' + name + '.prototype)';
var getPrototypeOfName = 'Object.getPrototypeOf(' + name + ')';
var extendId = getExtendId(program).clone();
var superClass = node.superClass;
var constructorMethod = !!definitions.search('> #MethodDefinition > key[name=constructor]').length;
if (!constructorMethod) {
definitions.unshift(new nodes.MethodDefinition({
key: new nodes.Identifier({ name: 'constructor' }),
value: express('(function () {\n var proto = ' + getPrototypeOfNamePrototype + ';\n if (proto !== null) proto.constructor.apply(this, arguments);\n })').expression
}));
}
var q = [
'>> #CallExpression > callee#MemberExpression[computed=false] > object#Identifier[name=super]',
'>> #CallExpression > callee#Identifier[name=super]'
];
definitions.search(q).forEach(function (id) {
var definition = id.parent('#MethodDefinition');
var parentNode = id.parentNode;
var callExpression, methodName;
if (parentNode.type === syntax.MemberExpression) {
callExpression = parentNode.parentNode;
methodName = parentNode.property.name;
} else {
callExpression = parentNode;
methodName = definition.key.name;
}
var superMethodXp = definition.static ? express(getPrototypeOfName + '.' + methodName).expression : express(getPrototypeOfNamePrototype + '.' + methodName).expression;
var selfId;
var definitionFunction = definition.value;
selfId = id.scope() !== definitionFunction ? getSelfId(definitionFunction).clone() : new nodes.ThisExpression();
callExpression.callee = superMethodXp;
applyContext(callExpression, selfId);
});
var constructorFunction = definitions.search('> #MethodDefinition > key[name=constructor] < * > value')[0];
constructorFunction.id = new nodes.Identifier({ name: name });
definitions.removeChild(constructorFunction.parentNode);
constructorFunction = new nodes.FunctionDeclaration(constructorFunction);
if (!superClass) {
superClass = new nodes.Identifier({ name: 'Object' });
}
var prototype = new nodes.ObjectExpression();
var members = new nodes.ObjectExpression();
definitions.forEach(function (definition) {
(definition.static ? members : prototype).properties.push(new nodes.Property({
key: definition.key,
value: definition.value,
kind: definition.kind || 'init'
}));
});
var extendExpression = express(extendId.name + '()');
var args = extendExpression.expression.arguments;
if (node.type === syntax.ClassExpression) {
var wrapper = express('(function(){})()').expression;
wrapper.arguments.push(superClass);
var body = wrapper.callee.body.body;
var returnStatement = new nodes.ReturnStatement({ argument: extendExpression.expression });
body.push(constructorFunction);
body.push(returnStatement);
node.parentNode.replaceChild(node, wrapper);
superClass = getUniqueId(wrapper, 'Super' + upper(constructorFunction.id.name));
wrapper.callee.params.push(superClass.clone());
} else {
node.parentNode.replaceChild(node, constructorFunction);
insertAfter(constructorFunction, extendExpression);
}
args.push(superClass, constructorFunction.id.clone(), prototype);
if (members.properties.length) {
args.push(members);
}
});
}
exports.transform = classify; |