raptor
Version:
RaptorJS provides an AMD module loader that works in Node, Rhino and the web browser. It also includes various sub-modules to support building optimized web applications.
226 lines (183 loc) • 6.86 kB
JavaScript
var Type = require("raptor/jsdoc/Type");
var logger = require('raptor/logging').logger('resolver-define');
var raptor = require('raptor');
module.exports = function(methodName, node, walker, isClass, isExtend, isEnum) {
"use strict";
var name = null,
label = null,
args = node['arguments'],
modifiers = null,
def = null,
type = null,
extension = null,
isModule = false;
if (node.comment) {
if (node.comment.hasTag("extension")) {
extension = node.comment.getTagValue("extension");
}
if (node.comment.hasTag("module")) {
isModule = true;
}
}
var factoryArgs = [];
args.forEach(function(arg, i) {
if (arg.type === 'FunctionExpression') {
def = arg;
}
else if (arg.type === 'Literal') {
if (i !== 0) {
modifiers = {
superclass: arg.value
};
}
else {
label = arg.value;
name = raptor.normalize(arg.value);
if (extension) {
name += "_" + extension;
}
}
}
else if (arg.type === 'ObjectExpression') {
var objectType = walker.resolveType(arg);
if (modifiers || i === args.length-1) {
type = objectType;
}
else {
modifiers = objectType;
}
}
else if (arg.type === 'ArrayExpression') {
arg.elements.forEach(function(dependency) {
if (dependency.value === 'require') {
type = new Type("function");
type.resolver = function(id) {
//TODO Come up with a way to resolve dependencies
};
}
else {
factoryArgs.push(new Type("object"));
}
}, this);
}
});
if (!def) {
logger.warn('Invalid args to "' + methodName + '". Definition argument not found. Args: ' + walker.argsToString(args));
}
else if (def.type === 'FunctionExpression') {
var factoryNamedArgs = {};
def.params.forEach(function(param, i) {
if (i < factoryArgs.length) {
factoryNamedArgs[param.name] = factoryArgs[i];
}
});
var scope = walker.invokeFunctionExpression(def, factoryNamedArgs);
type = scope.returnType;
if (name) {
/*
* Register any anonymous classes
*/
scope.forEachLocalVar(function(prop) {
var varName = prop.name,
varType = prop.type;
if (varType && varType !== scope.returnType && varType.isJavaScriptFunction() && !varType.raptorName && varType.hasProperty("prototype")) {
var varComment = varType.getComment();
var innerSymbolName = name + "/" + varName;
if (!walker.getSymbols().hasSymbol(innerSymbolName)) {
varType.setName(innerSymbolName);
varType.setLabel(label + "/" + varName);
varType.extension = extension;
varType.setAnonymous(true);
if (varComment && varComment.hasTag("name")) {
varType.setLabel(varComment.getTagValue("name"));
}
walker.getSymbols().addSymbol(innerSymbolName, varType);
}
}
}, this);
}
}
if (type) {
if (type.isJavaScriptFunction() && !isModule) {
if (!type.hasProperty("prototype")) {
type.setProperty({ //Make it clear that this a class and not just a regular function
name: "prototype",
type: new Type()
});
}
}
if (!type.isJavaScriptFunction() && isClass) {
/*
* The object being defined is a class defined using
* define.Class, but the class definition object
* is an object. We need to convert it to a
* function type to make it clear that it is a
* class
*/
var initProp = type.getProperty("init"),
classType;
if (initProp) {
classType = initProp.type;
if (initProp.comment) {
classType.setComment(initProp.comment);
}
}
else {
classType = new Type("function");
}
var protoType = new Type("object");
classType.setProperty({
name: "prototype",
type: protoType
});
type.forEachProperty(function(prop) {
if (prop.name === 'init' && prop.type.isJavaScriptFunction()) {
prop.type.forEachFunctionParam(function(ctorParam) {
classType.addFunctionParam(ctorParam);
}, this);
}
else {
protoType.setProperty(prop);
}
});
type = classType;
}
if (node.comment) {
//Attach the comment or the main node to the type
type.raptorDefineComment = node.comment;
if (extension) {
type.extension = extension;
}
}
if (modifiers) {
type.superclassName = modifiers.superclass;
type.raptorModifiers = modifiers;
}
type.setName(name);
type.raptorName = name;
type.raptorDefineMethod = methodName;
if (isModule) {
type.raptorType = 'module';
}
else if (type.isJavaScriptFunction()) {
type.raptorType = 'class';
}
else {
if (methodName === 'define.Class') {
type.raptorType = 'class';
}
else {
type.raptorType = 'module';
}
}
if (name) {
walker.getSymbols().addSymbol(name, type);
}
type.label = label;
if (type && !(type instanceof Type)) {
throw new Error('Invalid type being returned: ' + type);
}
//TODO: Handle enums and mixins
}
return type;
};