diff --git a/lib/jsdoc/tag/type.js b/lib/jsdoc/tag/type.js
index 4f6ac507..9eab4fbe 100644
--- a/lib/jsdoc/tag/type.js
+++ b/lib/jsdoc/tag/type.js
@@ -168,7 +168,10 @@ function parseName(tagInfo) {
}
/** @private */
-function getTypeStrings(parsedType) {
+function getTypeStrings(parsedType, isOutermostType) {
+ var applications;
+ var typeString;
+
var types = [];
var catharsis = require('catharsis');
@@ -192,7 +195,19 @@ function getTypeStrings(parsedType) {
types.push('Object');
break;
case TYPES.TypeApplication:
- types.push( catharsis.stringify(parsedType) );
+ // if this is the outermost type, we strip the modifiers; otherwise, we keep them
+ if (isOutermostType) {
+ applications = parsedType.applications.map(function(application) {
+ return getTypeStrings(application);
+ }).join(', ');
+ typeString = util.format( '%s.<%s>', getTypeStrings(parsedType.expression),
+ applications );
+
+ types.push(typeString);
+ }
+ else {
+ types.push( catharsis.stringify(parsedType) );
+ }
break;
case TYPES.TypeUnion:
parsedType.elements.forEach(function(element) {
@@ -244,7 +259,7 @@ function parseTypeExpression(tagInfo) {
}
if (parsedType) {
- tagInfo.type = tagInfo.type.concat( getTypeStrings(parsedType) );
+ tagInfo.type = tagInfo.type.concat( getTypeStrings(parsedType, true) );
// Catharsis and JSDoc use the same names for 'optional' and 'nullable'...
['optional', 'nullable'].forEach(function(key) {
diff --git a/lib/jsdoc/util/templateHelper.js b/lib/jsdoc/util/templateHelper.js
index bdf246cb..876ae8b8 100644
--- a/lib/jsdoc/util/templateHelper.js
+++ b/lib/jsdoc/util/templateHelper.js
@@ -519,6 +519,13 @@ exports.getAttribs = function(d) {
attribs.push('constant');
}
+ if (d.nullable === true) {
+ attribs.push('nullable');
+ }
+ else if (d.nullable === false) {
+ attribs.push('non-null');
+ }
+
return attribs;
};
diff --git a/templates/default/publish.js b/templates/default/publish.js
index 43266d46..f7aa3374 100644
--- a/templates/default/publish.js
+++ b/templates/default/publish.js
@@ -7,6 +7,7 @@ var template = require('jsdoc/template'),
taffy = require('taffydb').taffy,
logger = require('jsdoc/util/logger'),
helper = require('jsdoc/util/templateHelper'),
+ util = require('util'),
htmlsafe = helper.htmlsafe,
linkto = helper.linkto,
resolveAuthorLinks = helper.resolveAuthorLinks,
@@ -58,33 +59,125 @@ function needsSignature(doclet) {
return needsSig;
}
-function addSignatureParams(f) {
- var params = helper.getSignatureParams(f, 'optional');
+function getSignatureAttributes(item) {
+ var attributes = [];
- f.signature = (f.signature || '') + '('+params.join(', ')+')';
+ if (item.optional) {
+ attributes.push('opt');
+ }
+
+ if (item.nullable === true) {
+ attributes.push('nullable');
+ }
+ else if (item.nullable === false) {
+ attributes.push('non-null');
+ }
+
+ return attributes;
+}
+
+function updateItemName(item) {
+ var attributes = getSignatureAttributes(item);
+ var itemName = item.name || '';
+
+ if (item.variable) {
+ itemName = '…' + itemName;
+ }
+
+ if (attributes && attributes.length) {
+ itemName = util.format( '%s%s', itemName,
+ attributes.join(', ') );
+ }
+
+ return itemName;
+}
+
+function addParamAttributes(params) {
+ return params.map(updateItemName);
+}
+
+function buildItemTypeStrings(item) {
+ var types = [];
+
+ if (item.type && item.type.names) {
+ item.type.names.forEach(function(name) {
+ types.push( linkto(name, htmlsafe(name)) );
+ });
+ }
+
+ return types;
+}
+
+function buildAttribsString(attribs) {
+ var attribsString = '';
+
+ if (attribs && attribs.length) {
+ attribsString = htmlsafe( util.format('(%s) ', attribs.join(', ')) );
+ }
+
+ return attribsString;
+}
+
+function addNonParamAttributes(items) {
+ var types = [];
+
+ items.forEach(function(item) {
+ types = types.concat( buildItemTypeStrings(item) );
+ });
+
+ return types;
+}
+
+function addSignatureParams(f) {
+ var params = f.params ? addParamAttributes(f.params) : [];
+
+ f.signature = util.format( '%s(%s)', (f.signature || ''), params.join(', ') );
}
function addSignatureReturns(f) {
- var returnTypes = helper.getSignatureReturns(f);
+ var attribs = [];
+ var attribsString = '';
+ var returnTypes = [];
+ var returnTypesString = '';
+
+ // jam all the return-type attributes into an array. this could create odd results (for example,
+ // if there are both nullable and non-nullable return types), but let's assume that most people
+ // who use multiple @return tags aren't using Closure Compiler type annotations, and vice-versa.
+ if (f.returns) {
+ f.returns.forEach(function(item) {
+ helper.getAttribs(item).forEach(function(attrib) {
+ if (attribs.indexOf(attrib) === -1) {
+ attribs.push(attrib);
+ }
+ });
+ });
+
+ attribsString = buildAttribsString(attribs);
+ }
+
+ if (f.returns) {
+ returnTypes = addNonParamAttributes(f.returns);
+ }
+ if (returnTypes.length) {
+ returnTypesString = util.format( ' → %s{%s}', attribsString, returnTypes.join('|') );
+ }
f.signature = '' + (f.signature || '') + '' +
- '' +
- (returnTypes && returnTypes.length ? ' → {' + returnTypes.join('|') + '}' : '') +
- '';
+ '' + returnTypesString + '';
}
function addSignatureTypes(f) {
- var types = helper.getSignatureTypes(f);
+ var types = f.type ? buildItemTypeStrings(f) : [];
- f.signature = (f.signature || '') + ''+(types.length? ' :'+types.join('|') : '')+'';
+ f.signature = (f.signature || '') + '' +
+ (types.length ? ' :' + types.join('|') : '') + '';
}
function addAttribs(f) {
var attribs = helper.getAttribs(f);
+ var attribsString = buildAttribsString(attribs);
- f.attribs = '' + htmlsafe(attribs.length ?
- // we want the template output to say 'abstract', not 'virtual'
- '<' + attribs.join(', ').replace('virtual', 'abstract') + '> ' : '') + '';
+ f.attribs = util.format('%s', attribsString);
}
function shortenPaths(files, commonPrefix) {
diff --git a/templates/default/static/styles/jsdoc-default.css b/templates/default/static/styles/jsdoc-default.css
index bf6b51cf..124ef6c7 100644
--- a/templates/default/static/styles/jsdoc-default.css
+++ b/templates/default/static/styles/jsdoc-default.css
@@ -58,8 +58,7 @@ section
display: none;
}
-.optional:after {
- content: "opt";
+.signature-attributes {
font-size: 60%;
color: #aaa;
font-style: italic;