diff --git a/lib/jsdoc/name.js b/lib/jsdoc/name.js index 695c37f6..5157aff1 100644 --- a/lib/jsdoc/name.js +++ b/lib/jsdoc/name.js @@ -123,6 +123,7 @@ function quoteUnsafe(name, kind) { // docspaced names may have unsafe characters return name; } +// TODO: make this a private method, or remove it if possible RegExp.escape = RegExp.escape || function(str) { var specials = new RegExp("[.*+?|()\\[\\]{}\\\\]", "g"); // .*+?|()[]{}\ return str.replace(specials, "\\$&"); @@ -216,44 +217,17 @@ exports.shorten = function(longname, forcedMemberof) { }; /** - Split a string that starts with a name and ends with a description, into its parts. + Split a string that starts with a name and ends with a description into its parts. @param {string} nameDesc @returns {object} Hash with "name" and "description" properties. */ exports.splitName = function(nameDesc) { - var name = '', - desc = '', - thisChar = '', - inQuote = false; - - for (var i = 0, len = nameDesc.length; i < len; i++) { - thisChar = nameDesc.charAt(i); - - if (thisChar === '\\') { - name += thisChar + nameDesc.charAt(++i); - continue; - } - - if (thisChar === '"') { - inQuote = !inQuote; - } - - if (inQuote) { - name += thisChar; - continue; - } - - if (!inQuote) { - if ( /\s/.test(thisChar) ) { - desc = nameDesc.substr(i); - desc = desc.replace(/^[\s\-\s]+/, '').trim(); - break; - } - else { - name += thisChar; - } - } - } - - return { name: name, description: desc }; + // like: name, [name], name text, [name] text, name - text, or [name] - text + // the hyphen must be on the same line as the name; this prevents us from treating a Markdown + // dash as a separator + nameDesc.match(/^(\[[^\]]+\]|\S+)((?:[ \t]*\-\s*|\s+)(\S[\s\S]*))?$/); + return { + name: RegExp.$1, + description: RegExp.$3 + }; }; diff --git a/lib/jsdoc/tag/type.js b/lib/jsdoc/tag/type.js index d36b6820..e2d384a2 100644 --- a/lib/jsdoc/tag/type.js +++ b/lib/jsdoc/tag/type.js @@ -6,6 +6,13 @@ * @license Apache License 2.0 - See file 'LICENSE.md' in this project. */ +var jsdoc = { + name: require('jsdoc/name'), + tag: { + inline: require('jsdoc/tag/inline') + } +}; + /** * Information about a type expression extracted from tag text. * @@ -83,6 +90,7 @@ function getTagInfo(tagValue, canHaveName, canHaveType) { var typeExpression = ''; var text = tagValue; var expressionAndText; + var nameAndDescription; var typeOverride; if (canHaveType) { @@ -92,15 +100,14 @@ function getTagInfo(tagValue, canHaveName, canHaveType) { } if (canHaveName) { - // like: name, [name], name text, [name] text, name - text, or [name] - text - text.match(/^(\[[^\]]+\]|\S+)((?:\s*\-\s*|\s+)(\S[\s\S]*))?$/); - name = RegExp.$1; - text = RegExp.$3; + nameAndDescription = jsdoc.name.splitName(text); + name = nameAndDescription.name; + text = nameAndDescription.description; } // an inline @type tag, like {@type Foo}, overrides the type expression if (canHaveType) { - typeOverride = require('jsdoc/tag/inline').extractInlineTag(text, 'type'); + typeOverride = jsdoc.tag.inline.extractInlineTag(text, 'type'); if (typeOverride.tags && typeOverride.tags[0]) { typeExpression = typeOverride.tags[0].text || typeExpression; } @@ -134,6 +141,7 @@ function getTagInfo(tagValue, canHaveName, canHaveType) { * can vary (for example, in a function that accepts any number of parameters). */ +// TODO: move to module:jsdoc/name? /** * Extract JSDoc-style type information from the name specified in the tag info, including the * member name; whether the member is optional; and the default value of the member. diff --git a/test/specs/jsdoc/name.js b/test/specs/jsdoc/name.js index f8ba382b..21e3d720 100644 --- a/test/specs/jsdoc/name.js +++ b/test/specs/jsdoc/name.js @@ -85,7 +85,7 @@ describe("jsdoc/name", function() { expect(parts.memberof).toEqual('channels."#ops"'); expect(parts.scope).toEqual('#'); - startName = 'channels["#bots"]["log.max"]', + startName = 'channels["#bots"]["log.max"]'; parts = jsdoc.name.shorten(startName); expect(parts.name).toEqual('"log.max"'); @@ -174,6 +174,22 @@ describe("jsdoc/name", function() { expect(parts.name, 'ns.Page#"last \\"sentence\\"".words~sort(2)'); expect(parts.description, 'This is a description.'); }); + + it('should strip the separator when the separator starts on the same line as the name', function() { + var startName = 'socket - The networking kind, not the wrench.'; + var parts = jsdoc.name.splitName(startName); + + expect(parts.name).toBe('socket'); + expect(parts.description).toBe('The networking kind, not the wrench.'); + }); + + it('should not strip a separator that is preceded by a line break', function() { + var startName = 'socket\n - The networking kind, not the wrench.'; + var parts = jsdoc.name.splitName(startName); + + expect(parts.name).toBe('socket'); + expect(parts.description).toBe('- The networking kind, not the wrench.'); + }); }); describe("resolve", function() {