/tags/jsdoc_toolkit-2.2.1/jsdoc-toolkit/app/lib/JSDOC/DocTag.js

http://jsdoc-toolkit.googlecode.com/ · JavaScript · 294 lines · 89 code · 28 blank · 177 comment · 42 complexity · 0baf4099c5c3bd6bd34187b41499e623 MD5 · raw file

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