PageRenderTime 40ms CodeModel.GetById 9ms app.highlight 25ms RepoModel.GetById 1ms app.codeStats 1ms

/branches/version1.x/app/Symbol.js

http://jsdoc-toolkit.googlecode.com/
JavaScript | 332 lines | 276 code | 40 blank | 16 comment | 102 complexity | dbf52447276f6d541ed265086820be7a MD5 | raw file
  1/**
  2 * @fileOverview
  3 * @name Symbol
  4 * @author Michael Mathews micmath@gmail.com
  5 * @url $HeadURL: http://jsdoc-toolkit.googlecode.com/svn/branches/version1.x/app/Symbol.js $
  6 * @revision $Id: Symbol.js 420 2008-01-16 22:59:24Z micmath $
  7 * @license <a href="http://en.wikipedia.org/wiki/MIT_License">X11/MIT License</a>
  8 *          (See the accompanying README file for full details.)
  9 */
 10
 11SYM = {
 12	OBJECT:			"OBJECT",
 13	FUNCTION:		"FUNCTION",
 14	CONSTRUCTOR:	"CONSTRUCTOR",
 15	VIRTUAL:		"VIRTUAL",
 16    EVENT:          "EVENT"
 17};
 18
 19RegExp.escapeMeta = function(str) {
 20	return str.replace(/([$^\\\/()|?+*\[\]{}.-])/g, "\\$1");
 21}
 22
 23/**
 24	@class Represents an atomic unit of code.
 25	@constructor
 26*/
 27function Symbol(name, params, isa, comment) {
 28	if (isa == "META") {
 29		if (comment.indexOf("/**#@+") == 0) { // start of shared doclet
 30			Symbol.shared = Doclet.unwrapComment(comment.replace("/**#@+", "/**"));
 31		}
 32		else if (comment.indexOf("/**#=+") == 0) { // start of shortcut doclet
 33			eval('Symbol.shortcuts = '+Doclet.unwrapComment(comment).replace('#=+', '').replace(/[\n\r\f]/g, ' '));
 34		}
 35		else if (comment.indexOf("/**#=-") == 0) { // end of shortcut doclet
 36			Symbol.shortcuts = {};
 37		}
 38		else if (comment.indexOf("/**#@-") == 0) { // end of shared doclet
 39			Symbol.shared = "";
 40		}
 41		return;
 42	}
 43	comment = Symbol.shared+"\n"+Doclet.unwrapComment(comment);
 44	for (var n in Symbol.shortcuts) {
 45		var pat = RegExp.escapeMeta(n);
 46		var re = new RegExp("^"+pat+"\\b");
 47		name = name.replace(re, Symbol.shortcuts[n]);
 48	}
 49	name = name.replace(/\.prototype\.?/, '/');
 50	
 51	this.name = name;
 52	this.params = (params || []);
 53	this.isa = (isa || SYM.OBJECT);
 54	this.type = "";
 55	this.alias = name;
 56	this.desc = "";
 57	this.classDesc = "";
 58	this.memberof = "";
 59	this.since = "";
 60	this.version = "";
 61	this.deprecated = "";
 62	this.augments = [];
 63	this.inherits = [];
 64	this._inheritsFrom = [];
 65	this.properties = [];
 66	this.methods = [];
 67	this.file = {};
 68	this.returns = [];
 69	this.exceptions = [];
 70    this.events = [];
 71	this.doc = new Doclet(comment);
 72	this.comment = comment;
 73	this.see = [];
 74	
 75	// move certain data out of the tags and into the Symbol
 76	var overviews;
 77	if ((overviews = this.doc.getTag("overview")) && overviews.length) {
 78		var libraries;
 79		if ((libraries = this.doc.getTag("name")) && libraries.length) {
 80			this.name = libraries[0].desc;
 81			this.doc._dropTag("name");
 82		}
 83		else {
 84			this.name = Util.fileName(this.alias)
 85		}
 86		
 87		this.desc = overviews[0].desc;
 88		this.doc._dropTag("overview");
 89	}
 90	else {
 91		var since;
 92		if ((since = this.doc.getTag("since")) && since.length) {
 93			this.since = since[0].desc;
 94		}
 95		
 96		var version;
 97		if ((version = this.doc.getTag("version")) && version.length) {
 98			this.version = version[0].desc;
 99		}
100		
101		var deprecated;
102		if ((deprecated = this.doc.getTag("deprecated")) && deprecated.length) {
103			this.deprecated = deprecated[0];
104			this.doc._dropTag("deprecated");
105		}
106		
107		var see;
108		if ((see = this.doc.getTag("see")) && version.length) {
109			this.see = see;
110			this.doc._dropTag("see");
111		}
112		
113		var descs;
114		if ((descs = this.doc.getTag("desc")) && descs.length) {
115			this.desc = descs.join("\n"); // multiple descriptions are concatenated into one
116			this.doc._dropTag("desc");
117		}
118		
119		var params;
120		if ((params = this.doc.getTag("param")) && params.length) { // user defined params override those defined by parser
121			this.params = params;
122			this.doc._dropTag("param");
123		}
124		else { // promote parser params into DocTag objects
125			for (var i = 0; i < this.params.length; i++) {
126				this.params[i] = new DocTag("param "+this.params[i]);
127			}
128		}
129		
130		var constructors;
131		if ((constructors = this.doc.getTag("constructor")) && constructors.length) {
132			this.isa = SYM.CONSTRUCTOR;
133			this.doc._dropTag("constructor");
134		}
135		
136		var functions;
137		if ((functions = this.doc.getTag("function")) && functions.length) {
138			this.isa = SYM.FUNCTION;
139			this.doc._dropTag("function");
140		}
141        
142        var events;
143		if ((events = this.doc.getTag("event")) && events.length) {
144			this.isa = SYM.EVENT;
145			this.doc._dropTag("event");
146		}
147		
148		var methods;
149		if ((functions = this.doc.getTag("method")) && functions.length) {
150			this.isa = SYM.FUNCTION;
151			this.doc._dropTag("method");
152		}
153		
154		var names;
155		if ((names = this.doc.getTag("name")) && names.length) {
156			this.name = names[0].desc;
157			this.doc._dropTag("name");
158		}
159		
160		var properties;
161		if ((properties = this.doc.getTag("property")) && properties.length) {
162			for (var i = 0; i < properties.length; i++) {
163				properties[i].alias = this.alias+"."+properties[i].name;
164				this.properties.push(properties[i]);
165			}
166			this.doc._dropTag("property");
167		}
168		
169		var returns;
170		if ((returns = this.doc.getTag("return")) && returns.length) {
171			for (var i = 0; i < returns.length; i++) {
172				this.returns.push(returns[i]);
173			}
174			this.doc._dropTag("return");
175		}
176		
177		var exceptions;
178		if ((exceptions = this.doc.getTag("throws")) && exceptions.length) {
179			for (var i = 0; i < exceptions.length; i++) {
180				this.exceptions.push(exceptions[i]);
181			}
182			this.doc._dropTag("throws");
183		}
184		
185		if (this.is("VIRTUAL")) this.isa = SYM.OBJECT;
186		
187		var types;
188		if ((types = this.doc.getTag("type")) && types.length) {
189			if (this.is("OBJECT"))
190				this.type = (types[0].desc || ""); // multiple type tags are ignored
191			this.doc._dropTag("type");
192		}
193		
194		if (this.doc.getTag("static").length > 0) {
195			this.isStatic = true;
196			this.doc._dropTag("static");
197		}
198		
199		if (this.doc.getTag("private").length > 0) {
200			this.isPrivate = true;
201			this.doc._dropTag("private");
202		}
203			
204		var classes;
205		if ((classes = this.doc.getTag("class")) && classes.length) {
206			if (this.doc.getTag("static").length > 0) this.isStatic = true;
207			this.isa = "CONSTRUCTOR"; // a class tag implies a conctuctor doclet
208			
209			this.classDesc += "\n"+classes[0].desc; // multiple class tags are concatenated
210		}
211		
212		var inherits;
213		if ((inherits = this.doc.getTag("inherits")) && inherits.length) {
214			for (var i = 0; i < inherits.length; i++) {
215				if (/^\s*([a-z$0-9_.#]+)(?:\s+as\s+([a-z$0-9_.#]+))?/i.test(inherits[i].desc)) {
216					var inAlias = RegExp.$1;
217					var inAs = RegExp.$2 || inAlias;
218					if (inAs.indexOf(this.alias) != 0) {
219						inAs = this.alias+"."+inAs;
220					}
221					inAs = inAs.replace(/\.this\.?/, "/");
222				}
223
224				this.inherits.push({alias: inAlias, as: inAs});
225			}
226			this.doc._dropTag("inherits");
227		}
228		
229		var augments;
230		if ((augments = this.doc.getTag("augments")) && augments.length) {
231			for (var i = 0; i < augments.length; i++) {
232				this.augments.push(augments[i].desc);
233			}
234			this.doc._dropTag("augments");
235		}
236		
237		Symbol.index[this.alias] = this;
238	}
239}
240Symbol.shared = ""; // holds shared doclets
241Symbol.shortcuts = {}; // holds map of shortcut names to full names
242Symbol.index = {};
243Symbol.builtins = ['Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object', 'RegExp', 'String'];
244
245Symbol.prototype.is = function(what) {
246    return this.isa === SYM[what];
247}
248
249/** Generate a comma separated list of the parameters. */
250Symbol.prototype.signature = function() {
251    var result = [];
252    for (var i = 0; i < this.params.length; i++) {
253    	if (this.params[i].name.indexOf(".") == -1) // config information does not appear in the signature
254    		result.push(this.params[i].name);
255    }
256    return result.join(", ");
257}
258
259Symbol.prototype.hasMethod = function(name) {
260    for (var i = 0; i < this.methods.length; i++) {
261    	if (this.methods[i].name == name) return true
262    }
263    return false;
264}
265
266Symbol.prototype.hasEvent = function(name) {
267    for (var i = 0; i < this.events.length; i++) {
268    	if (this.events[i].name == name) return true
269    }
270    return false;
271}
272
273Symbol.prototype.hasProperty = function(name) {
274    for (var i = 0; i < this.properties.length; i++) {
275    	if (this.properties[i].name == name) return true
276    }
277    return false;
278}
279
280function isUnique(arr) {
281	var l = arr.length;
282	for(var i = 0; i < l; i++ ) {
283		if (arr.lastIndexOf(arr[i]) > i) return false;
284	}
285	return true;
286}
287
288Symbol.prototype.getInheritedMethods = function(r) {
289	var result = this.methods;
290	for(var i = 0; i < this.augments.length; i++) {
291		var contributer = this.file.fileGroup.getSymbol(this.augments[i]);
292		if (contributer) {
293			this._inheritsFrom.push(contributer.alias);
294			
295			if (!isUnique(this._inheritsFrom)) {
296				LOG.warn("Circular reference: "+this.alias+" inherits from the same symbol more than once.");
297			}
298			else {
299				result = result.concat(contributer.getInheritedMethods(true));
300				this._inheritsFrom = [];
301			}
302		}
303	}
304	// remove overridden
305	for (var i = 0; i < result.length; i++) {
306		var j = i; 
307		while (++j < result.length) {
308			if (result[j].name == result[i].name) result.splice(j, 1);
309		}
310	}
311	
312	if (!r) { // not recursing
313		var s = this;
314		function notLocal(element, index, array) {
315			return (!s.hasMethod(element.name));
316		}
317		result = result.filter(notLocal);
318	}
319	return result;
320}
321
322Symbol.prototype.clone = function() {
323	var dop = new Symbol(this.name, [], this.isa, this.comment);
324	
325	for (var i in this.params) {
326		for (var j in this.params[i]) {
327			if (this.params[i][j].constructor == String)
328				dop.params[i][j] = this.params[i][j];
329		}
330	}
331	return dop;
332}