diff --git a/modules/jsdoc/doclet.js b/modules/jsdoc/doclet.js index bbc8dcda..11d9060c 100644 --- a/modules/jsdoc/doclet.js +++ b/modules/jsdoc/doclet.js @@ -137,49 +137,48 @@ tagName = tag.name; tagValue = {}; - -// if (tag.type && tag.type.length) { -// tagValue.type = tag.type; -// // not a long tag -// if (!tag.pname && tag.text) { tagValue.text = tag.text; } -// } // a long tag - if (tag.pname) { + if (tag.pname || tag.pdesc) { // TODO: should check the list instead? - if ( /^\[(.+)\]$/.test(tag.pname) ) { - tagValue.name = RegExp.$1; - tag.poptional = true; + if (tag.pname) { + if ( /^\[(.+)\]$/.test(tag.pname) ) { + tagValue.name = RegExp.$1; + tag.poptional = true; + } + else { + tagValue.name = tag.pname; + } } - else { - tagValue.name = tag.pname; + + if (tag.type && tag.type.length) { + tagValue.type = tag.type; } - tagValue.type = tag.type; -// print('```` name is '+tagName+': '+tagValue); } if (tag.pdesc) { tagValue.desc = tag.pdesc; } if (typeof tag.poptional === 'boolean') { tagValue.optional = tag.poptional; } if (typeof tag.pnullable === 'boolean') { tagValue.nullable = tag.pnullable; } // tag value is not an object, it's just a simple string - if (!tag.pname) { + if (!tag.pname && !tag.pdesc) { // TODO: should check the list instead? tagValue = tag.text; } - - if (typeof o[tagName] === 'undefined') { // not defined - o[tagName] = tagValue; - } - else if (o[tagName].push) { // is an array - o[tagName].push(tagValue); - } - else { // is a string, but needs to be an array - o[tagName] = [ o[tagName] ]; - o[tagName].push(tagValue); + + if (tagValue) { + if (typeof o[tagName] === 'undefined') { // not defined + o[tagName] = tagValue; + } + else if (o[tagName].push) { // is an array + o[tagName].push(tagValue); + } + else { // is a string, but needs to be an array + o[tagName] = [ o[tagName] ]; + o[tagName].push(tagValue); + } } o.meta = this.meta; } - return o; } @@ -265,6 +264,9 @@ else if (tags[i].name === 'protected') { tags[tags.length] = tag.fromTagText('access protected'); } + else if (tags[i].name === 'public') { + tags[tags.length] = tag.fromTagText('access public'); + } else if (tags[i].name === 'const') { tags[tags.length] = tag.fromTagText('attribute constant'); } diff --git a/modules/jsdoc/parser.js b/modules/jsdoc/parser.js index 8fff30bd..20fecc16 100644 --- a/modules/jsdoc/parser.js +++ b/modules/jsdoc/parser.js @@ -134,7 +134,7 @@ throw 'module:jsdoc/parser.parseFiles requires argument sourceFiles(none provided).'; } - if (typeof sourceFiles[0] === 'string') { sourceFiles = [sourceFiles]; } + if (typeof sourceFiles === 'string') { sourceFiles = [sourceFiles]; } for (i = 0, leni = sourceFiles.length; i < leni; i++) { try { diff --git a/modules/jsdoc/tag.js b/modules/jsdoc/tag.js index b6412092..01b9751b 100644 --- a/modules/jsdoc/tag.js +++ b/modules/jsdoc/tag.js @@ -37,7 +37,8 @@ return new Tag(tagText); } - var longTags = ['param', 'constructor', 'const', 'module', 'event', 'namespace', 'method', 'member', 'function', 'variable', 'enum']; + var longTags = ['param', 'constructor', 'const', 'module', 'event', 'namespace', 'method', 'member', 'function', 'variable', 'enum', 'returns']; + var anonTags = ['returns']; /** @private @constructor Tag @@ -56,11 +57,14 @@ if (bits) { this.name = (bits[1] || '').toLowerCase(); // like @name - this.name = synonym(this.name); + this.name = trim( resolveSynonyms(this.name) ); - this.text = bits[2] || ''; // all the rest of the tag + this.text = trim( bits[2] ) || ''; // all the rest of the tag - var type, text, optional, nullable; + var /*Array.*/ type, + /*string*/ text, + /*?boolean*/ optional, + /*?boolean*/ nullable; [type, text, optional, nullable] = jsdoc_type.parse(this.text); // @type tags are the only tag that is not allowed to have a {type}! @@ -69,17 +73,21 @@ type = []; } - if (type && type.length) { - this.type = type; - } + // don't add an empty type or null attributes + if (type && type.length) { this.type = type; } if (optional !== null) { this.poptional = optional; } if (nullable !== null) { this.pnullable = nullable; } this.text = text; if (longTags.indexOf(this.name) > -1) { // is a tag that uses the long format - var [pname, pdesc] = parsePname(this.text); - this.pname = pname; - this.pdesc = pdesc; + if (anonTags.indexOf(this.name) > -1) { + this.pdesc = this.text; + } + else { + var [pname, pdesc] = parsePname(this.text); + this.pname = pname; + this.pdesc = pdesc; + } } } } @@ -96,23 +104,31 @@ @returns Array. The pname and the pdesc. */ function parsePname(tagText) { - tagText.match(/^(\S+)(\s+(\S.*))?$/); + tagText.match(/^(\S+)(\s+(\S[\s\S]*))?$/); return [RegExp.$1, RegExp.$3]; } - function synonym(name) { - if ( synonym.map.hasOwnProperty(name) ) { - return synonym.map[name]; + function resolveSynonyms(name) { + if ( exports.synonyms.hasOwnProperty(name) ) { + return exports.synonyms[name]; } else { return name; } } - synonym.map = { + exports.synonyms = { 'description': 'desc', - 'function': 'method', - 'variable': 'member' + 'function': 'method', + 'variable': 'member', + 'return': 'returns' + } + + //TODO: move into a shared module? + /** @private */ + function trim(text) { + if (!text) { return ''; } + return text.replace(/^\s+|\s+$/g, ''); } })(); \ No newline at end of file diff --git a/modules/jsdoc/type.js b/modules/jsdoc/type.js index 199ee52f..ca3e2930 100644 --- a/modules/jsdoc/type.js +++ b/modules/jsdoc/type.js @@ -17,7 +17,6 @@ exports.parse = function(tagText) { if (typeof tagText !== 'string') { tagText = ''; } var type = '', - types = [], text = '', count = 0; @@ -43,9 +42,9 @@ [type, optional] = parseOptional(type); [type, nullable] = parseNullable(type); - types = parseTypes(type); // make it into an array - - return [types, text, optional, nullable]; + type = parseTypes(type); // make it into an array + + return [type, text, optional, nullable]; } function parseOptional(type) { diff --git a/tests/tag_param.js b/tests/tag_param.js index b96bf4ce..6f73b33a 100644 --- a/tests/tag_param.js +++ b/tests/tag_param.js @@ -1,105 +1,130 @@ -(function() { - var jsdoc = { parser: require('jsdoc/parser') }; - - jsdoc.parser.parseFiles(BASEDIR + 'tests/tag_param.js'); - var docset = jsdoc.parser.result; - - var testSuite = { - suiteName: 'tag_param', - - setUp: function() { - }, - - tearDown: function() { - }, - - testParamWithSimpleType: function() { - var docs = docset.getDocsByPath('Shape'); - - assertEqual(docs.length, 1, 'All constructor doclets by that path name are found.'); - - var doc = docs[0].toObject(), - params = doc.param; -//print('>>> doc is '+doc.toSource()); -//print('>>> params is '+params.toSource()); - assertEqual(params[0].name, 'top', 'The found parameter has the correct name.'); - assertEqual(typeof params[0].type, 'object', 'The found parameter has types.'); - assertEqual(params[0].type.length, 1, 'The found parameter has the correct number of types.'); - assertEqual(params[0].type[0], 'number', 'The found parameter has the correct type value.'); - - }, - - testParamWithNullableType: function() { - var docs = docset.getDocsByPath('Shape'); - - assertEqual(docs.length, 1, 'All constructor doclets by that path name are found.'); - - var doc = docs[0].toObject(), - params = doc.param; - - assertEqual(params[1].name, 'left', 'The found parameter has the correct name.'); - assertEqual(typeof params[1].type, 'object', 'The found parameter has types.'); - assertEqual(params[1].type.length, 1, 'The found parameter has the correct number of types.'); - assertEqual(params[1].type[0], 'number', 'The found parameter has the correct type value.'); - assertEqual(params[1].nullable, false, 'The found parameter has the correct !nullable value.'); - assertEqual(params[2].nullable, true, 'The found parameter has the correct ?nullable value.'); - }, - - testParamWithOptionalType: function() { - var docs = docset.getDocsByPath('Shape'); - - assertEqual(docs.length, 1, 'All doclets by that path name are found.'); - - var doc = docs[0].toObject(), - params = doc.param; - - assertEqual(params[3].name, 'fixed', 'The found parameter has the correct name.'); - assertEqual(typeof params[1].type, 'object', 'The found parameter has types.'); - assertEqual(params[3].type.length, 1, 'The found parameter has the correct number of types.'); - assertEqual(params[3].type[0], 'boolean', 'The found parameter has the correct type value.'); - assertEqual(params[3].nullable, undefined, 'The found parameter has the default nullable value.'); - assertEqual(params[3].optional, true, 'The found parameter has the correct optional value.'); - }, - - testParamWithMultipleType: function() { - var docs = docset.getDocsByPath('rotate'); - - assertEqual(docs.length, 1, 'All doclets by that path name are found.'); - - var doc = docs[0].toObject(), - params = doc.param; - - assertEqual(params[0].name, 'deg', 'The found parameter has the correct name.'); - assertEqual(typeof params[0].type, 'object', 'The found parameter has types.'); - assertEqual(params[0].type.length, 2, 'The found parameter has the correct number of types.'); - assertEqual(params[0].type[0], 'Degree', 'The found parameter has the correct type[0] value.'); - assertEqual(params[0].type[1], 'number', 'The found parameter has the correct type[1] value.'); - - assertEqual(params[1].name, 'axis', 'The found parameter has the correct name.'); - assertEqual(params[1].optional, true, 'The found parameter has the correct optional.'); - - } - }; - - testSuites.push(testSuite); -})(); - -function sample() { - - /** @constructor - @param {number} top - @param {!number} left - @param {?number} sides - @param {boolean=} fixed - */ - function Shape(top, left, sides, fixed) { - } - - /** @method - @param {Degree|number} deg - @param [axis] - */ - function rotate(deg, axis) { - - } -} +(function() { + var jsdoc = { parser: require('jsdoc/parser') }; + + jsdoc.parser.parseFiles(BASEDIR + 'tests/tag_param.js'); + var docset = jsdoc.parser.result; + + var testSuite = { + suiteName: 'tag_param', + + setUp: function() { + }, + + tearDown: function() { + }, + + testParamWithSimpleType: function() { + var docs = docset.getDocsByPath('Shape'); + + assertEqual(docs.length, 1, 'All constructor doclets by that path name are found.'); + + var doc = docs[0].toObject(), + params = doc.param; +//print('>>> doc is '+doc.toSource()); +//print('>>> params is '+params.toSource()); + assertEqual(params[0].name, 'top', 'The found parameter has the correct name.'); + assertEqual(typeof params[0].type, 'object', 'The found parameter has types.'); + assertEqual(params[0].type.length, 1, 'The found parameter has the correct number of types.'); + assertEqual(params[0].type[0], 'number', 'The found parameter has the correct type value.'); + + }, + + testParamWithNullableType: function() { + var docs = docset.getDocsByPath('Shape'); + + assertEqual(docs.length, 1, 'All constructor doclets by that path name are found.'); + + var doc = docs[0].toObject(), + params = doc.param; + + assertEqual(params[1].name, 'left', 'The found parameter has the correct name.'); + assertEqual(typeof params[1].type, 'object', 'The found parameter has types.'); + assertEqual(params[1].type.length, 1, 'The found parameter has the correct number of types.'); + assertEqual(params[1].type[0], 'number', 'The found parameter has the correct type value.'); + assertEqual(params[1].nullable, false, 'The found parameter has the correct !nullable value.'); + assertEqual(params[2].nullable, true, 'The found parameter has the correct ?nullable value.'); + }, + + testParamWithOptionalType: function() { + var docs = docset.getDocsByPath('Shape'); + + assertEqual(docs.length, 1, 'All doclets by that path name are found.'); + + var doc = docs[0].toObject(), + params = doc.param; + + assertEqual(params[3].name, 'fixed', 'The found parameter has the correct name.'); + assertEqual(typeof params[1].type, 'object', 'The found parameter has types.'); + assertEqual(params[3].type.length, 1, 'The found parameter has the correct number of types.'); + assertEqual(params[3].type[0], 'boolean', 'The found parameter has the correct type value.'); + assertEqual(params[3].nullable, undefined, 'The found parameter has the default nullable value.'); + assertEqual(params[3].optional, true, 'The found parameter has the correct optional value.'); + }, + + testParamWithMultipleType: function() { + var docs = docset.getDocsByPath('rotate'); + + assertEqual(docs.length, 1, 'All doclets by that path name are found.'); + + var doc = docs[0].toObject(), + params = doc.param; + + assertEqual(params[0].name, 'deg', 'The found parameter has the correct name.'); + assertEqual(typeof params[0].type, 'object', 'The found parameter has types.'); + assertEqual(params[0].type.length, 2, 'The found parameter has the correct number of types.'); + assertEqual(params[0].type[0], 'Degree', 'The found parameter has the correct type[0] value.'); + assertEqual(params[0].type[1], 'number', 'The found parameter has the correct type[1] value.'); + + assertEqual(params[1].name, 'axis', 'The found parameter has the correct name.'); + assertEqual(params[1].optional, true, 'The found parameter has the correct optional.'); + + }, + + testParamDesc: function() { + var docs = docset.getDocsByPath('resize'); + + assertEqual(docs.length, 1, 'All doclets by that path name are found.'); + + var doc = docs[0].toObject(), + param = doc.param; + + assertEqual(typeof param, 'object', 'The found parameter has the expected type.'); + assertEqual(param.name, 'ratio', 'The found parameter has the correct name.'); + assertEqual(typeof param.type, 'object', 'The found parameter has types.'); + assertEqual(param.type.length, 2, 'The found parameter has the correct number of types.'); + assertEqual(param.type[0], 'Function', 'The found parameter has the correct type[0] value.'); + assertEqual(param.type[1], 'number', 'The found parameter has the correct type[1] value.'); + assertEqual(param.desc, 'A number\n or a function.', 'The found parameter has the expected description.'); + } + }; + + testSuites.push(testSuite); +})(); + +function sample() { + + /** @constructor + @param {number} top + @param {!number} left + @param {?number} sides + @param {boolean=} fixed + */ + function Shape(top, left, sides, fixed) { + } + + /** @method + @param {Degree|number} deg + @param [axis] + */ + function rotate(deg, axis) { + + } + + /** @method + @param {Function|number} ratio A number + or a function. + */ + function resize(ratio) { + + } +}