thirdparty/jsdoctoolkit/app/lib/JSDOC/SymbolSet.js
author Lennard de Rijk <ljvderijk@gmail.com>
Sun, 25 Oct 2009 18:43:23 -0700
changeset 3050 5f135cfac194
parent 3041 c8f47f0b6697
permissions -rw-r--r--
Reworked the redirects to work with the new Request model. Also made use of the collection of Role Views in the Role View in combination with the role property in the Request model, to facilitate the redirects.

/** @constructor */
JSDOC.SymbolSet = function() {
	this.init();
}

JSDOC.SymbolSet.prototype.init = function() {
	this._index = new Hash();
}

JSDOC.SymbolSet.prototype.keys = function() {
	return this._index.keys();
}

JSDOC.SymbolSet.prototype.hasSymbol = function(alias) {
	return this._index.hasKey(alias);
}

JSDOC.SymbolSet.prototype.addSymbol = function(symbol) {
	if (this.hasSymbol(symbol.alias)) {
		LOG.warn("Overwriting symbol documentation for: "+symbol.alias + ".");
	}
	this._index.set(symbol.alias, symbol);
}

JSDOC.SymbolSet.prototype.getSymbol = function(alias) {
	if (this.hasSymbol(alias)) return this._index.get(alias);
}

JSDOC.SymbolSet.prototype.getSymbolByName = function(name) {
	for (var p = this._index.first(); p; p = this._index.next()) {
		var symbol = p.value;
		if (symbol.name == name) return symbol;
	}
}

JSDOC.SymbolSet.prototype.toArray = function() {
	return this._index.values();
}

JSDOC.SymbolSet.prototype.deleteSymbol = function(alias) {
	if (!this.hasSymbol(alias)) return;
	this._index.drop(alias);
}

JSDOC.SymbolSet.prototype.renameSymbol = function(oldName, newName) {
	// todo: should check if oldname or newname already exist
	this._index.replace(oldName, newName);
	this._index.get(newName).alias = newName;
	return newName;
}

JSDOC.SymbolSet.prototype.relate = function() {
	this.resolveBorrows();
	this.resolveMemberOf();
	this.resolveAugments();
}

JSDOC.SymbolSet.prototype.resolveBorrows = function() {
	for (var p = this._index.first(); p; p = this._index.next()) {
		var symbol = p.value;
		if (symbol.is("FILE") || symbol.is("GLOBAL")) continue;
		
		var borrows = symbol.inherits;
		for (var i = 0; i < borrows.length; i++) {
		
if (/#$/.test(borrows[i].alias)) {
	LOG.warn("Attempted to borrow entire instance of "+borrows[i].alias+" but that feature is not yet implemented.");
	return;
}
			var borrowed = this.getSymbol(borrows[i].alias);
			
			if (!borrowed) {
				LOG.warn("Can't borrow undocumented "+borrows[i].alias+".");
				continue;
			}

			if (borrows[i].as == borrowed.alias) {
				var assumedName = borrowed.name.split(/([#.-])/).pop();
				borrows[i].as = symbol.name+RegExp.$1+assumedName;
				LOG.inform("Assuming borrowed as name is "+borrows[i].as+" but that feature is experimental.");
			}
			
			var borrowAsName = borrows[i].as;
			var borrowAsAlias = borrowAsName;
			if (!borrowAsName) {
				LOG.warn("Malformed @borrow, 'as' is required.");
				continue;
			}
			
			if (borrowAsName.length > symbol.alias.length && borrowAsName.indexOf(symbol.alias) == 0) {
				borrowAsName = borrowAsName.replace(borrowed.alias, "")
			}
			else {
				var joiner = "";
				if (borrowAsName.charAt(0) != "#") joiner = ".";
				borrowAsAlias = borrowed.alias + joiner + borrowAsName;
			}
			
			borrowAsName = borrowAsName.replace(/^[#.]/, "");
					
			if (this.hasSymbol(borrowAsAlias)) continue;

			var clone = borrowed.clone();
			clone.name = borrowAsName;
			clone.alias = borrowAsAlias;
			this.addSymbol(clone);
		}
	}
}

JSDOC.SymbolSet.prototype.resolveMemberOf = function() {
	for (var p = this._index.first(); p; p = this._index.next()) {
		var symbol = p.value;
		if (symbol.is("FILE") || symbol.is("GLOBAL")) continue;
		
		// the memberOf value was provided in the @memberOf tag
		else if (symbol.memberOf) {
			
			// like foo.bar is a memberOf foo
			if (symbol.alias.indexOf(symbol.memberOf) == 0) {
				var memberMatch = new RegExp("^("+symbol.memberOf+")[.#-]?(.+)$");
				var aliasParts = symbol.alias.match(memberMatch);
				
				if (aliasParts) {
					symbol.memberOf = aliasParts[1];
					symbol.name = aliasParts[2];
				}
				
				var nameParts = symbol.name.match(memberMatch);

				if (nameParts) {
					symbol.name = nameParts[2];
				}
			}
			// like bar is a memberOf foo
			else {
				var joiner = symbol.memberOf.charAt(symbol.memberOf.length-1);
				if (!/[.#-]/.test(joiner)) symbol.memberOf += ".";
				this.renameSymbol(symbol.alias, symbol.memberOf + symbol.name);
			}
		}
		// the memberOf must be calculated
		else {
			var parts = symbol.alias.match(/^(.*[.#-])([^.#-]+)$/);
			if (parts) {
				symbol.memberOf = parts[1];
				symbol.name = parts[2];				
			}
		}

		// set isStatic, isInner
		if (symbol.memberOf) {
			switch (symbol.memberOf.charAt(symbol.memberOf.length-1)) {
				case '#' :
					symbol.isStatic = false;
					symbol.isInner = false;
				break;
				case '.' :
					symbol.isStatic = true;
					symbol.isInner = false;
				break;
				case '-' :
					symbol.isStatic = false;
					symbol.isInner = true;
				break;
				default: // memberOf ends in none of the above
					symbol.isStatic = true;
				break;
			}
		}
		
		// unowned methods and fields belong to the global object
		if (!symbol.is("CONSTRUCTOR") && !symbol.isNamespace && symbol.memberOf == "") {
			symbol.memberOf = "_global_";
		}

		// clean up
		if (symbol.memberOf.match(/[.#-]$/)) {
			symbol.memberOf = symbol.memberOf.substr(0, symbol.memberOf.length-1);
		}
		// add to parent's methods or properties list
		if (symbol.memberOf) {

			var container = this.getSymbol(symbol.memberOf);
			if (!container) {
				if (JSDOC.Lang.isBuiltin(symbol.memberOf)) container = JSDOC.Parser.addBuiltin(symbol.memberOf);
				else {
					LOG.warn("Trying to document "+symbol.name +" as a member of undocumented symbol "+symbol.memberOf+".");
				}
			}
			
			if (container) container.addMember(symbol);
		}
	}
}

JSDOC.SymbolSet.prototype.resolveAugments = function() {
	for (var p = this._index.first(); p; p = this._index.next()) {
		var symbol = p.value;
		
		if (symbol.alias == "_global_" || symbol.is("FILE")) continue;
		JSDOC.SymbolSet.prototype.walk.apply(this, [symbol]);
	}
}

JSDOC.SymbolSet.prototype.walk = function(symbol) {
	var augments = symbol.augments;
	for(var i = 0; i < augments.length; i++) {
		var contributer = this.getSymbol(augments[i]);
		if (!contributer && JSDOC.Lang.isBuiltin(''+augments[i])) {
			contributer = new JSDOC.Symbol("_global_."+augments[i], [], augments[i], new JSDOC.DocComment("Built in."));
			contributer.isNamespace = true;
			contributer.srcFile = "";
			contributer.isPrivate = false;
			JSDOC.Parser.addSymbol(contributer);
		}
		
		if (contributer) {			
			if (contributer.augments.length) {
				JSDOC.SymbolSet.prototype.walk.apply(this, [contributer]);
			}
			
			symbol.inheritsFrom.push(contributer.alias);
			//if (!isUnique(symbol.inheritsFrom)) {
			//	LOG.warn("Can't resolve augments: Circular reference: "+symbol.alias+" inherits from "+contributer.alias+" more than once.");
			//}
			//else {
				var cmethods = contributer.methods;
				var cproperties = contributer.properties;
				
				for (var ci = 0, cl = cmethods.length; ci < cl; ci++) {
					if (!cmethods[ci].isStatic) symbol.inherit(cmethods[ci]);
				}
				for (var ci = 0, cl = cproperties.length; ci < cl; ci++) {
					if (!cproperties[ci].isStatic) symbol.inherit(cproperties[ci]);
				}	
			//}
		}
		else LOG.warn("Can't augment contributer: "+augments[i]+", not found.");
	}
}