From 15cc0e57ca9b674ed68156ddb88139d93fcd771d Mon Sep 17 00:00:00 2001 From: Michael Mathews Date: Sat, 24 Jul 2010 12:02:13 +0100 Subject: [PATCH] Added isScalar attribute of tag. --- modules/jsdoc/doclet.js | 76 +++++++++++++++++----------------- modules/jsdoc/name.js | 4 +- modules/jsdoc/tag.js | 39 ++++++++++++++++- modules/jsdoc/tagdictionary.js | 38 +++++++++++------ 4 files changed, 102 insertions(+), 55 deletions(-) diff --git a/modules/jsdoc/doclet.js b/modules/jsdoc/doclet.js index 0f4f95c4..25518a2c 100644 --- a/modules/jsdoc/doclet.js +++ b/modules/jsdoc/doclet.js @@ -85,8 +85,12 @@ @returns {*} The value of the found tag. */ Doclet.prototype.tagValue = function(tagName) { + var tagAbout = tagDictionary.lookUp(tagName); for (var i = 0, leni = this.tags.length; i < leni; i++) { if (this.tags[i].name === tagName) { + if (tagAbout.isScalar && this.tags[i].value.push) { + return this.tags[i].value[0]; + } return this.tags[i].value; } } @@ -109,7 +113,7 @@ } } - this.tags[this.tags.length] = parse_tag.fromText(tagName + ' ' + tagValue); + this.addTag(tagName, tagValue); } /** @@ -120,7 +124,7 @@ @returns {Tag} The new tag. */ Doclet.prototype.addTag = function(tagName, tagValue) { - this.tags[this.tags.length] = parse_tag.fromText(tagName + ' ' + tagValue); + return this.tags.addTag(tagName, tagValue); } /** @@ -146,13 +150,7 @@ @returns {boolean} True if the tag is found, false otherwise. */ Doclet.prototype.hasTag = function(tagName) { - var i = this.tags.length; - while(i--) { - if (this.tags[i].name === tagName) { - return true; - } - } - return false; + return this.tags.hasTag(tagName); } /** @@ -212,23 +210,23 @@ } return o; } - - // TODO need to simplify this string or array business. maybe define some props as scalar? - Doclet.prototype.getScope = function() { - var scope = this.tagValue('scope'); - - if (!scope) { - return ''; - } - else if (typeof scope === 'string' && ['inner', 'static', 'instance'].indexOf(scope) > -1) { - return scope; - } - else { - if (scope.indexOf('instance') > -1) { return 'instance'; } - else if (scope.indexOf('inner') > -1) { return 'inner'; } - else if (scope.indexOf('static') > -1) { return 'static'; } - } - } +// +// // TODO need to simplify this string or array business. maybe define some props as scalar? +// Doclet.prototype.getScope = function() { +// var scope = this.tagValue('scope'); +// +// if (!scope) { +// return ''; +// } +// else if (typeof scope === 'string' && ['inner', 'static', 'instance'].indexOf(scope) > -1) { +// return scope; +// } +// else { +// if (scope.indexOf('instance') > -1) { return 'instance'; } +// else if (scope.indexOf('inner') > -1) { return 'inner'; } +// else if (scope.indexOf('static') > -1) { return 'static'; } +// } +// } /** Remove JsDoc comment slash-stars. Trims white space. @@ -288,23 +286,23 @@ tagAbout = tagDictionary.lookUp(tags[i].name); if (tagAbout.setsDocletAttrib) { - tags[tags.length] = parse_tag.fromText('attrib '+tags[i].name); + tags.addTag('attrib', tags[i].name); } if (tagAbout.setsDocletAccess) { - tags[tags.length] = parse_tag.fromText('access '+tags[i].name); + tags.addTag('access', tags[i].name); } if (tagAbout.setsDocletScope) { - tags[tags.length] = parse_tag.fromText('scope '+tags[i].name); + tags.addTag('scope', tags[i].name); } if (tagAbout.impliesTag) { // TODO allow a template string? - tags[tags.length] = parse_tag.fromText(tagAbout.impliesTag); + tags.addTag(tagAbout.impliesTag); } if (tagAbout.setsDocletDesc) { - tags[tags.length] = parse_tag.fromText('desc '+tags[i].value); + tags.addTag('desc', tags[i].value); } if (tags[i].name === 'name') { @@ -343,7 +341,7 @@ } if (tags[i].pdesc) { - tags[tags.length] = parse_tag.fromText('desc ' + tags[i].pdesc); + tags.addTag('desc', tags[i].pdesc); } if (kind && kind !== tags[i].name) { @@ -355,19 +353,19 @@ } if (name && !taggedName) { - tags[tags.length] = parse_tag.fromText('name ' + name); + tags.addTag('name', name); } if ( isFile && !(name || taggedName) ) { - tags[tags.length] = parse_tag.fromText('name file:'+meta.file+''); + tags.addTag('name', 'file:'+meta.file); } if (kind && !taggedIsa) { - tags[tags.length] = parse_tag.fromText('kind ' + kind); + tags.addTag('kind', kind); } if (memberof && !taggedMemberof) { - tags[tags.length] = parse_tag.fromText('memberof ' + memberof); + tags.addTag('memberof', memberof); } } @@ -384,13 +382,13 @@ // class tags imply a constructor tag if (tags[i].name === 'class' && !doclet.hasTag('constructor') ) { - doclet.tags[doclet.tags.length] = parse_tag.fromText('kind constructor'); + tags.addTag('kind', 'constructor'); } // enums have a defualt type of number if (tags[i].name === 'enum') { if ( !doclet.hasTag('type') ) { - doclet.tags[doclet.tags.length] = parse_tag.fromText('type number'); + tags.addTag('type', 'number'); } } @@ -404,7 +402,7 @@ else docletTypes = tags[i].type; for (var i = 0, leni = docletTypes.length; i < leni; i++) { - doclet.tags[doclet.tags.length] = parse_tag.fromText('type '+docletTypes[i]); + tags.addTag('type', docletTypes[i]); } } } diff --git a/modules/jsdoc/name.js b/modules/jsdoc/name.js index d1fd9c48..da7bd038 100644 --- a/modules/jsdoc/name.js +++ b/modules/jsdoc/name.js @@ -55,7 +55,7 @@ if (name) { doclet.addTag('scope', puncToScope[scope]); } } else { - scope = doclet.getScope(); + scope = doclet.tagValue('scope'); if (!scope) { scope = 'static'; // default scope is static @@ -168,7 +168,7 @@ enclosingDoc = exports.docFromNode(enclosing); if (enclosingDoc) { - if (enclosingDoc.getScope() === 'inner') memberof = ''; // inner functions have `this` scope of global + if (enclosingDoc.tagValue('scope') === 'inner') memberof = ''; // inner functions have `this` scope of global else memberof = enclosingDoc.tagValue('path'); } else { diff --git a/modules/jsdoc/tag.js b/modules/jsdoc/tag.js index 9714a7b9..d288fe54 100644 --- a/modules/jsdoc/tag.js +++ b/modules/jsdoc/tag.js @@ -98,6 +98,41 @@ } } + /** + @param {string|Tag} tagOrTagName + @param {*} [tagValue] + */ + function addTag(tagName, tagValue) { + var tag; + if (tagName.name) { + tag = tagName; + tagName = tagName.name; + } + + var tagAbout = tagDictionary.lookUp(tagName); + if (tagAbout.isScalar && this.hasTag(tagName)) { + return false; + } + if (typeof tagValue === 'undefined') { + // TODO this could obviously be more efficient + this[this.length] = tag || exports.fromText(tagName); + } + else { + this[this.length] = tag || exports.fromText(tagName + ' ' + tagValue); + } + return true; + } + + function hasTag(tagName, tagValue) { + var i = this.length; + while(i--) { + if (this[i].name === tagName) { + return true; + } + } + return false; + } + /** Given the source of a jsdoc comment, finds the tags. @private @@ -107,6 +142,8 @@ */ exports.parse = function(commentSrc) { var tags = []; + tags.addTag = addTag; + tags.hasTag = hasTag; // split out the basic tags, keep surrounding whitespace commentSrc @@ -115,7 +152,7 @@ .forEach(function($) { var newTag = exports.fromText($); - if (newTag.name) { tags.push(newTag); } + if (newTag.name) { tags.addTag(newTag); } }); return tags; diff --git a/modules/jsdoc/tagdictionary.js b/modules/jsdoc/tagdictionary.js index 130f96e6..65de21e4 100644 --- a/modules/jsdoc/tagdictionary.js +++ b/modules/jsdoc/tagdictionary.js @@ -65,7 +65,7 @@ // default properties of all tags TagDefinition.prototype = { isExported : false, // this tag should appear as a top level property in the doclet? - setsDocletKind : false, // the name of this tag is used to define the doclet's kind property + setsDocletKind : false, // the name of this tag is used to define the doclet's kind property setsDocletDesc : false, setsDocletName : false, // this tag can be used to name the doclet setsDocletAttrib : false, // the name of this tag becomes the attribute of the doclet @@ -76,7 +76,8 @@ canHavePname : false, // this tag can have a parameter-type name canHavePdesc : false, // this tag can have a parameter-type desc keepsWhitespace : false, // don't try to tidy up the whitespace in this tag? - impliesTag : false // this tag implies another tag + impliesTag : false, // this tag implies another tag + isScalar : false // can only have a single value (first wins) }; /** Syntax: @access (private|public|protected) @@ -86,7 +87,8 @@ @memberOf module:jsdoc/tagdictionary.tagDefinitions */ new TagDefinition('access', { - isExported: true + isExported: true, + isScalar: true }); /** Syntax: @scope (global|static|inner|instance) @@ -96,7 +98,8 @@ @memberOf module:jsdoc/tagdictionary.tagDefinitions */ new TagDefinition('scope', { - isExported: true + isExported: true, + isScalar: true }); /** Syntax: @desc @@ -105,7 +108,8 @@ @memberOf module:jsdoc/tagdictionary.tagDefinitions */ new TagDefinition('desc', { // t - isExported: true + isExported: true, + isScalar: true }); /** Syntax: @kind @@ -115,7 +119,8 @@ @memberOf module:jsdoc/tagdictionary.tagDefinitions */ new TagDefinition('kind', { - isExported: true + isExported: true, + isScalar: true }); /** Syntax: @name @@ -124,7 +129,8 @@ @memberOf module:jsdoc/tagdictionary.tagDefinitions */ new TagDefinition('name', { - isExported: true + isExported: true, + isScalar: true }); /** Syntax: @path @@ -134,7 +140,8 @@ @memberOf module:jsdoc/tagdictionary.tagDefinitions */ new TagDefinition('path', { - isExported: true + isExported: true, + isScalar: true }); /** Syntax: @memberOf @@ -175,7 +182,8 @@ */ new TagDefinition('classdesc', { //t isExported: true, - impliesTag: 'constructor' + impliesTag: 'constructor', + isScalar: true }); /** Syntax: @constant|const @@ -313,7 +321,8 @@ new TagDefinition('thisobj', { //t isExported: true, canHaveType: true, - canHavePdesc: true + canHavePdesc: true, + isScalar: true }); /** Syntax: @attrib (readonly) @@ -442,7 +451,8 @@ @memberOf module:jsdoc/tagdictionary.tagDefinitions */ new TagDefinition('since', { - isExported: true + isExported: true, + isScalar: true }); /** Syntax: @version @@ -451,7 +461,8 @@ @memberOf module:jsdoc/tagdictionary.tagDefinitions */ new TagDefinition('version', { - isExported: true + isExported: true, + isScalar: true }); /** Syntax: @requires @@ -480,7 +491,8 @@ @memberOf module:jsdoc/tagdictionary.tagDefinitions */ new TagDefinition('deprecated', { - isExported: true + isExported: true, + isScalar: true }); /** Syntax: @see