thirdparty/jsdoctoolkit/app/lib/JSDOC/DocTag.js
changeset 3041 c8f47f0b6697
equal deleted inserted replaced
3040:8f9580309846 3041:c8f47f0b6697
       
     1 if (typeof JSDOC == "undefined") JSDOC = {};
       
     2 
       
     3 /**
       
     4 	@constructor
       
     5  */
       
     6 JSDOC.DocTag = function(src) {
       
     7 	this.init();
       
     8 	if (typeof src != "undefined") {
       
     9 		this.parse(src);
       
    10 	}
       
    11 }
       
    12 
       
    13 /**
       
    14 	Create and initialize the properties of this.
       
    15  */
       
    16 JSDOC.DocTag.prototype.init = function() {
       
    17 	this.title        = "";
       
    18 	this.type         = "";
       
    19 	this.name         = "";
       
    20 	this.isOptional   = false;
       
    21 	this.defaultValue = "";
       
    22 	this.desc         = "";
       
    23 	
       
    24 	return this;
       
    25 }
       
    26 
       
    27 /**
       
    28 	Populate the properties of this from the given tag src.
       
    29 	@param {string} src
       
    30  */
       
    31 JSDOC.DocTag.prototype.parse = function(src) {
       
    32 	if (typeof src != "string") throw "src must be a string not "+(typeof src);
       
    33 
       
    34 	try {
       
    35 		src = this.nibbleTitle(src);
       
    36 		if (JSDOC.PluginManager) {
       
    37 			JSDOC.PluginManager.run("onDocTagSynonym", this);
       
    38 		}
       
    39 		
       
    40 		src = this.nibbleType(src);
       
    41 		
       
    42 		// only some tags are allowed to have names.
       
    43 		if (this.title == "param" || this.title == "property" || this.title == "config") { // @config is deprecated
       
    44 			src = this.nibbleName(src);
       
    45 		}
       
    46 	}
       
    47 	catch(e) {
       
    48 		if (LOG) LOG.warn(e);
       
    49 		else throw e;
       
    50 	}
       
    51 	this.desc = src; // whatever is left
       
    52 	
       
    53 	// example tags need to have whitespace preserved
       
    54 	if (this.title != "example") this.desc = this.desc.trim();
       
    55 	
       
    56 	if (JSDOC.PluginManager) {
       
    57 		JSDOC.PluginManager.run("onDocTag", this);
       
    58 	}
       
    59 }
       
    60 
       
    61 /**
       
    62 	Automatically called when this is stringified.
       
    63  */
       
    64 JSDOC.DocTag.prototype.toString = function() {
       
    65 	return this.desc;
       
    66 }
       
    67 
       
    68 /*t:
       
    69 	plan(1, "testing JSDOC.DocTag#toString");
       
    70 	
       
    71 	var tag = new JSDOC.DocTag("param {object} date A valid date.");
       
    72 	is(""+tag, "A valid date.", "stringifying a tag returns the desc.");
       
    73  */
       
    74 
       
    75 /**
       
    76 	Find and shift off the title of a tag.
       
    77 	@param {string} src
       
    78 	@return src
       
    79  */
       
    80 JSDOC.DocTag.prototype.nibbleTitle = function(src) {
       
    81 	if (typeof src != "string") throw "src must be a string not "+(typeof src);
       
    82 	
       
    83 	var parts = src.match(/^\s*(\S+)(?:\s([\s\S]*))?$/);
       
    84 
       
    85 	if (parts && parts[1]) this.title = parts[1];
       
    86 	if (parts && parts[2]) src = parts[2];
       
    87 	else src = "";
       
    88 	
       
    89 	return src;
       
    90 }
       
    91 
       
    92 /*t:
       
    93 	plan(8, "testing JSDOC.DocTag#nibbleTitle");
       
    94 	
       
    95 	var tag = new JSDOC.DocTag();
       
    96 	
       
    97 	tag.init().nibbleTitle("aTitleGoesHere");
       
    98 	is(tag.title, "aTitleGoesHere", "a title can be found in a single-word string.");
       
    99 	
       
   100 	var src = tag.init().nibbleTitle("aTitleGoesHere and the rest");
       
   101 	is(tag.title, "aTitleGoesHere", "a title can be found in a multi-word string.");
       
   102 	is(src, "and the rest", "the rest is returned when the title is nibbled off.");
       
   103 	
       
   104 	src = tag.init().nibbleTitle("");
       
   105 	is(tag.title, "", "given an empty string the title is empty.");
       
   106 	is(src, "", "the rest is empty when the tag is empty.");
       
   107 
       
   108 	var src = tag.init().nibbleTitle(" aTitleGoesHere\n  a description");
       
   109 	is(tag.title, "aTitleGoesHere", "leading and trailing spaces are not part of the title.");
       
   110 	is(src, "  a description", "leading spaces (less one) are part of the description.");
       
   111 
       
   112 	tag.init().nibbleTitle("a.Title::Goes_Here foo");
       
   113 	is(tag.title, "a.Title::Goes_Here", "titles with punctuation are allowed.");
       
   114  */
       
   115 
       
   116 /**
       
   117 	Find and shift off the type of a tag.
       
   118 	@requires frame/String.js
       
   119 	@param {string} src
       
   120 	@return src
       
   121  */
       
   122 JSDOC.DocTag.prototype.nibbleType = function(src) {
       
   123 	if (typeof src != "string") throw "src must be a string not "+(typeof src);
       
   124 	
       
   125 	if (src.match(/^\s*\{/)) {
       
   126 		var typeRange = src.balance("{", "}");
       
   127 		if (typeRange[1] == -1) {
       
   128 			throw "Malformed comment tag ignored. Tag type requires an opening { and a closing }: "+src;
       
   129 		}
       
   130 		this.type = src.substring(typeRange[0]+1, typeRange[1]).trim();
       
   131 		this.type = this.type.replace(/\s*,\s*/g, "|"); // multiples can be separated by , or |
       
   132 		src = src.substring(typeRange[1]+1);
       
   133 	}
       
   134 	
       
   135 	return src;
       
   136 }
       
   137 
       
   138 /*t:
       
   139 	plan(5, "testing JSDOC.DocTag.parser.nibbleType");
       
   140 	requires("../frame/String.js");
       
   141 	
       
   142 	var tag = new JSDOC.DocTag();
       
   143 	
       
   144 	tag.init().nibbleType("{String[]} aliases");
       
   145 	is(tag.type, "String[]", "type can have non-alpha characters.");
       
   146 	
       
   147 	tag.init().nibbleType("{ aTypeGoesHere  } etc etc");
       
   148 	is(tag.type, "aTypeGoesHere", "type is trimmed.");
       
   149 	
       
   150 	tag.init().nibbleType("{ oneType, twoType ,\n threeType  } etc etc");
       
   151 	is(tag.type, "oneType|twoType|threeType", "multiple types can be separated by commas.");
       
   152 	
       
   153 	var error;
       
   154 	try { tag.init().nibbleType("{widget foo"); }
       
   155 	catch(e) { error = e; }
       
   156 	is(typeof error, "string", "malformed tag type throws error.");
       
   157 	isnt(error.indexOf("Malformed"), -1, "error message tells tag is malformed.");
       
   158  */
       
   159 
       
   160 /**
       
   161 	Find and shift off the name of a tag.
       
   162 	@requires frame/String.js
       
   163 	@param {string} src
       
   164 	@return src
       
   165  */
       
   166 JSDOC.DocTag.prototype.nibbleName = function(src) {
       
   167 	if (typeof src != "string") throw "src must be a string not "+(typeof src);
       
   168 	
       
   169 	src = src.trim();
       
   170 	
       
   171 	// is optional?
       
   172 	if (src.charAt(0) == "[") {
       
   173 		var nameRange = src.balance("[", "]");
       
   174 		if (nameRange[1] == -1) {
       
   175 			throw "Malformed comment tag ignored. Tag optional name requires an opening [ and a closing ]: "+src;
       
   176 		}
       
   177 		this.name = src.substring(nameRange[0]+1, nameRange[1]).trim();
       
   178 		this.isOptional = true;
       
   179 		
       
   180 		src = src.substring(nameRange[1]+1);
       
   181 		
       
   182 		// has default value?
       
   183 		var nameAndValue = this.name.split("=");
       
   184 		if (nameAndValue.length) {
       
   185 			this.name = nameAndValue.shift().trim();
       
   186 			this.defaultValue = nameAndValue.join("=");
       
   187 		}
       
   188 	}
       
   189 	else {
       
   190 		var parts = src.match(/^(\S+)(?:\s([\s\S]*))?$/);
       
   191 		if (parts) {
       
   192 			if (parts[1]) this.name = parts[1];
       
   193 			if (parts[2]) src = parts[2].trim();
       
   194 			else src = "";
       
   195 		}
       
   196 	}	
       
   197 
       
   198 	return src;
       
   199 }
       
   200 
       
   201 /*t:
       
   202 	requires("../frame/String.js");
       
   203 	plan(9, "testing JSDOC.DocTag.parser.nibbleName");
       
   204 	
       
   205 	var tag = new JSDOC.DocTag();
       
   206 	
       
   207 	tag.init().nibbleName("[foo] This is a description.");
       
   208 	is(tag.isOptional, true, "isOptional syntax is detected.");
       
   209 	is(tag.name, "foo", "optional param name is found.");
       
   210  	
       
   211 	tag.init().nibbleName("[foo] This is a description.");
       
   212 	is(tag.isOptional, true, "isOptional syntax is detected when no type.");
       
   213 	is(tag.name, "foo", "optional param name is found when no type.");
       
   214 	
       
   215 	tag.init().nibbleName("[foo=7] This is a description.");
       
   216  	is(tag.name, "foo", "optional param name is found when default value.");
       
   217  	is(tag.defaultValue, 7, "optional param default value is found when default value.");
       
   218  	
       
   219  	//tag.init().nibbleName("[foo= a value] This is a description.");
       
   220  	//is(tag.defaultValue, " a value", "optional param default value is found when default value has spaces (issue #112).");
       
   221  	
       
   222  	tag.init().nibbleName("[foo=[]] This is a description.");
       
   223  	is(tag.defaultValue, "[]", "optional param default value is found when default value is [] (issue #95).");
       
   224  	
       
   225  	tag.init().nibbleName("[foo=a=b] This is a description.");
       
   226  	is(tag.name, "foo", "optional param name is found when default value is a=b.");
       
   227  	is(tag.defaultValue, "a=b", "optional param default value is found when default value is a=b.")
       
   228  */
       
   229 
       
   230 /*t:
       
   231 	plan(32, "Testing JSDOC.DocTag.parser.");
       
   232 	requires("../frame/String.js");
       
   233 	
       
   234  	var tag = new JSDOC.DocTag();
       
   235  	
       
   236  	is(typeof tag, "object", "JSDOC.DocTag.parser with an empty string returns an object.");
       
   237  	is(typeof tag.title, "string", "returned object has a string property 'title'.");
       
   238  	is(typeof tag.type, "string", "returned object has a string property 'type'.");
       
   239  	is(typeof tag.name, "string", "returned object has a string property 'name'.");
       
   240  	is(typeof tag.defaultValue, "string", "returned object has a string property 'defaultValue'.");
       
   241  	is(typeof tag.isOptional, "boolean", "returned object has a boolean property 'isOptional'.");
       
   242  	is(typeof tag.desc, "string", "returned object has a string property 'desc'.");
       
   243   
       
   244   	tag = new JSDOC.DocTag("param {widget} foo");
       
   245   	is(tag.title, "param", "param title is found.");
       
   246   	is(tag.name, "foo", "param name is found when desc is missing.");
       
   247  	is(tag.desc, "", "param desc is empty when missing.");
       
   248  	
       
   249  	tag = new JSDOC.DocTag("param {object} date A valid date.");
       
   250  	is(tag.name, "date", "param name is found with a type.");
       
   251  	is(tag.type, "object", "param type is found.");
       
   252  	is(tag.desc, "A valid date.", "param desc is found with a type.");
       
   253  	
       
   254   	tag = new JSDOC.DocTag("param aName a description goes\n    here.");
       
   255 	is(tag.name, "aName", "param name is found without a type.");
       
   256  	is(tag.desc, "a description goes\n    here.", "param desc is found without a type.");
       
   257  	
       
   258  	tag = new JSDOC.DocTag("param {widget}");
       
   259  	is(tag.name, "", "param name is empty when it is not given.");
       
   260 	
       
   261 	tag = new JSDOC.DocTag("param {widget} [foo] This is a description.");
       
   262 	is(tag.name, "foo", "optional param name is found.");
       
   263 	
       
   264 	tag = new JSDOC.DocTag("return {aType} This is a description.");
       
   265 	is(tag.type, "aType", "when return tag has no name, type is found.");
       
   266 	is(tag.desc, "This is a description.", "when return tag has no name, desc is found.");
       
   267 	
       
   268 	tag = new JSDOC.DocTag("author Joe Coder <jcoder@example.com>");
       
   269 	is(tag.title, "author", "author tag has a title.");
       
   270 	is(tag.type, "", "the author tag has no type.");
       
   271 	is(tag.name, "", "the author tag has no name.");
       
   272 	is(tag.desc, "Joe Coder <jcoder@example.com>", "author tag has desc.");
       
   273 	
       
   274 	tag = new JSDOC.DocTag("private \t\n  ");
       
   275 	is(tag.title, "private", "private tag has a title.");
       
   276 	is(tag.type, "", "the private tag has no type.");
       
   277 	is(tag.name, "", "the private tag has no name.");
       
   278 	is(tag.desc, "", "private tag has no desc.");
       
   279 
       
   280 	tag = new JSDOC.DocTag("example\n   example(code);\n   more();");
       
   281 	is(tag.desc, "   example(code);\n   more();", "leading whitespace (less one) in examples code is preserved.");
       
   282 	
       
   283 	tag = new JSDOC.DocTag("param theName  \n");
       
   284 	is(tag.name, "theName", "name only is found.");
       
   285 	
       
   286 	tag = new JSDOC.DocTag("type theDesc  \n");
       
   287 	is(tag.desc, "theDesc", "desc only is found.");
       
   288 	
       
   289 	tag = new JSDOC.DocTag("type {theType} \n");
       
   290 	is(tag.type, "theType", "type only is found.");
       
   291 	
       
   292 	tag = new JSDOC.DocTag("");
       
   293 	is(tag.title, "", "title is empty when tag is empty.");
       
   294  */