var template = require('./template'); var helper = require('jsdoc/util/templateHelper'); var markdown = require('jsdoc/util/markdown').getParser(); var supportsParams = function (doclet) { return doclet.kind === 'function' || doclet.kind === 'class' || (doclet.kind === 'typedef' && !!doclet.type && !!doclet.type.names && doclet.type.names.some(function (name) { return name.toLowerCase() === 'function'; })); }; var getLinkText = exports.getLinkText = function(doclet){ var text = doclet.longname; if (["class", "module", "namespace", "mixin", "interface", "event"].indexOf(doclet.kind) !== -1) { text = text.replace("module:", ""); if ("event" === doclet.kind) { text = text.replace("event:", ""); } if ("module" === doclet.kind){ text = text.split('>').pop(); } } else if ("external" === doclet.kind) { text = doclet.name.replace(/(^"|"$)/g, ""); } else if ("tutorial" === doclet.kind || "readme" === doclet.kind || "list" === doclet.kind) { text = doclet.title || doclet.name; } return text; }; exports.getAttribs = function (doclet) { if (supportsParams(doclet) || doclet.kind === 'member' || doclet.kind === 'constant') { var attribs = helper.getAttribs(doclet); return attribs.length ? '' + helper.htmlsafe('<' + attribs.join(', ') + '> ') + '' : ''; } return ''; }; exports.getSignature = function (doclet) { var signature = ''; if (supportsParams(doclet)) { signature += '('; if (doclet.params && doclet.params.length) { signature += ' '; var optionalClose = []; doclet.params.forEach(function (p, i) { if (p.name && p.name.indexOf('.') === -1) { if (!p.optional && optionalClose.length){ signature += optionalClose.pop(); } var name = '' + (p.variable ? '...' + p.name : p.name) + '', separator = i > 0 ? (p.optional ? ' [, ' : ', ') : (p.optional ? '[ ' : ''); signature += separator + name; if (p.optional) optionalClose.push(' ]'); } }); signature += optionalClose.join('') + ' '; } signature += ')'; if (template.options.methodHeadingReturns) { var returnTypes = helper.getSignatureReturns(doclet); signature += '' + (returnTypes.length ? ' → {' + returnTypes.join('|') + '}' : '') + ''; } } else if (doclet.kind === 'member' || doclet.kind === 'constant') { var types = helper.getSignatureTypes(doclet); signature += '' + (types.length ? ' :' + types.join('|') : '') + ''; //todo: check if this is required //doclet.kind = 'member'; } return signature; }; exports.getExamples = function (doclet) { if (!doclet.examples || !doclet.examples.length) return []; return doclet.examples.map(function (example) { // perform parsing of the example content to extract custom inner tags // create a new example object to return as the result of the mapping var result = { caption: '', code: '', lang: 'javascript', run: false }; // parse caption supplied using the default syntax if (example.match(/^\s*?([\s\S]+?)<\/caption>(\s*)([\s\S]+?)$/i)) { example = RegExp.$3; result.caption = markdown(RegExp.$1); } // parse caption supplied using the {@caption } inner tag var caption = /^\s*?\{@caption\s(.*?)}\s*?/.exec(example); if (caption && caption[1]) { example = example.replace(caption[0], ""); result.caption = markdown(caption[1]); // parse markdown and set result value } // parse lang supplied using the {@lang } inner tag, this should be a prism.js supported language to get syntax highlighting. var lang = /\s*?\{@lang\s(.*?)}\s*?/.exec(example); if (lang && lang[1]) { example = example.replace(lang[0], ""); result.lang = lang[1]; } // parse run supplied using the {@run } inner tag, this allows the example to be executed with any console.log calls being piped into a textarea. // NOTE: if lang !== 'javascript' the {@run} inner tag is simply removed from the example code, we only support running javascript. var run = /\s*?\{@run\s(.*?)}\s*?/.exec(example); if (run && run[1]) { example = example.replace(run[0], ""); // if the run tag is supplied it is always true regardless of the value so just test if the lang is javascript and use that value result.run = result.lang === 'javascript'; } // the example should now contain just the code result.code = example; return result; }); }; var expandLongnames = function(longnames, parent){ var results = []; var generated = template.kinds.pages.indexOf(parent.kind) !== -1; var memberof = generated ? parent.longname : parent.memberof; var leftovers = longnames.slice(); template.find({longname: longnames}).forEach(function(doclet){ var linkText = getLinkText(doclet); if (doclet.memberof === memberof){ linkText = linkText.split("~").pop(); } leftovers.splice(leftovers.indexOf(doclet.longname), 1); results.push({ link: template.linkto(doclet.longname, linkText), summary: doclet.summary }); }); leftovers.forEach(function(longname){ results.push({ link: template.linkto(longname), summary: '' }); }); return results; }; exports.getFires = function(doclet){ if (!doclet.fires) return []; return expandLongnames(doclet.fires, doclet); }; exports.getRequires = function(doclet){ if (!doclet.requires) return []; return expandLongnames(doclet.requires, doclet); }; exports.getSummary = function (doclet) { if (!doclet.summary) return ''; return markdown(doclet.summary); }; exports.getParamsOrProps = function (doclet, type) { if (!doclet[type] || !doclet[type].length) return []; var sorted = {}; sorted[type] = []; doclet[type].forEach(function(paramOrProp){ if (!paramOrProp) { return; } var parts = paramOrProp.name.split("."), last = parts.length - 1, base = sorted, parentName = []; parts.forEach(function(part, i){ var index; if (i === last){ paramOrProp.name = paramOrProp.name.replace(parentName.join('.'), '').replace(/^\./, ''); base[type] = base[type] || []; base[type].push(paramOrProp); } else if ((index = base[type].findIndex(function(p){ return p.name === part; })) !== -1) { base = base[type][index]; parentName.push(part); } }); }); return sorted[type].filter(function (paramOrProp) { return !!paramOrProp; }); }; var checkParamsOrProps = exports.checkParamsOrProps = function (parent, type) { if (!parent || !parent[type] || !parent[type].length) return; /* determine if we need extra columns, "attributes" and "default" */ parent[type + 'HasAttributes'] = false; parent[type + 'HasDefaults'] = false; parent[type + 'HasNames'] = false; parent[type].forEach(function (paramOrProp) { if (!paramOrProp) { return; } if (paramOrProp.optional || paramOrProp.nullable || paramOrProp.variable) { parent[type + 'HasAttributes'] = true; } if (paramOrProp.name) { parent[type + 'HasNames'] = true; } if (typeof paramOrProp.defaultvalue !== 'undefined') { parent[type + 'HasDefaults'] = true; } if (paramOrProp[type]) { checkParamsOrProps(paramOrProp, type); } }); }; exports.getPageTitle = function(doclet, sanitized){ var parts = []; if (doclet.attribs){ parts.push(doclet.attribs); } if (template.kinds.pages.indexOf(doclet.kind) !== -1 && template.kinds.custom.indexOf(doclet.kind) === -1 && doclet.ancestors && doclet.ancestors.length){ parts.push(''+doclet.ancestors.join('')+''); } if (doclet.title){ parts.push('' + doclet.title + ''); } else if (doclet.name) { var name = doclet.name; if (doclet.exported){ name = name.replace('module:', '(require("') + '"))'; } parts.push('' + name + ''); } if (template.kinds.pages.indexOf(doclet.kind) === -1 && doclet.signature){ parts.push(doclet.signature); } if (doclet.variation){ parts.push('' + doclet.variation + ''); } var result = parts.join(''); return sanitized ? template.sanitize(result) : result; }; exports.getListTitle = function(doclet, sanitized){ var parts = [], linkClose = false, url = doclet.kind === 'tutorial' ? helper.tutorialToUrl(doclet.longname) : helper.longnameToUrl[doclet.longname]; // only generate links to kinds that have a page generated, others show content inline so there's no need if (url){ parts.push(''); linkClose = true; } if (doclet.kind === 'class'){ parts.push('new '); } if (doclet.ancestors && doclet.ancestors.length){ parts.push(''+template.sanitize(doclet.ancestors.join(''))+''); } if (doclet.attribs){ parts.push(doclet.attribs); } if (doclet.title){ parts.push('' + doclet.title + ''); } else if (doclet.name) { var name = doclet.name; if (doclet.exported){ name = name.replace('module:', '(require("') + '"))'; } parts.push('' + name + ''); } if (doclet.signature){ parts.push(doclet.signature); } if (doclet.variation){ parts.push('' + doclet.variation + ''); } if (linkClose){ parts.push(''); } var result = parts.join(''); return sanitized ? template.sanitize(result) : result; }; exports.getSymbolTitle = function(doclet, sanitized){ var parts = [], linkClose = false, url = doclet.kind === 'tutorial' ? helper.tutorialToUrl(doclet.longname) : helper.longnameToUrl[doclet.longname]; // only generate links to kinds that have a page generated, others show content inline so there's no need if (template.kinds.pages.indexOf(doclet.kind) !== -1 && url){ parts.push(''); linkClose = true; } if (doclet.kind === 'class'){ parts.push('new '); } if (doclet.attribs){ parts.push(doclet.attribs); } if (doclet.title){ parts.push('' + doclet.title + ''); } else if (doclet.name) { var name = doclet.name; if (doclet.exported){ name = name.replace('module:', '(require("') + '"))'; } parts.push('' + name + ''); } if (doclet.signature){ parts.push(doclet.signature); } if (doclet.variation){ parts.push('' + doclet.variation + ''); } if (linkClose){ parts.push(''); } var result = parts.join(''); return sanitized ? template.sanitize(result) : result; }; exports.getPrimaryTitle = function(doclet, sanitized){ var parts = []; if (doclet.kind === 'class'){ parts.push('new '); } if (doclet.attribs){ parts.push(doclet.attribs); } if (doclet.title){ parts.push('' + doclet.title + ''); } else if (doclet.name) { var name = doclet.name; if (doclet.exported){ name = name.replace('module:', '(require("') + '"))'; } parts.push('' + doclet.name + ''); } if (doclet.signature){ parts.push(doclet.signature); } if (doclet.variation){ parts.push('' + doclet.variation + ''); } var result = parts.join(''); return sanitized ? template.sanitize(result) : result; }; exports.getSymbols = function(doclet){ var symbols = {}; if (doclet.longname == helper.globalName){ template.kinds.global.forEach(function(kind){ symbols[kind] = template.find({kind: kind, memberof: { isUndefined: true }}); }); } else { template.kinds.symbols.forEach(function(kind){ symbols[kind] = template.find({kind: kind, memberof: doclet.longname}); }); } return symbols; }; exports.getShowAccessFilter = function(doclet){ var result = typeof doclet.showAccessFilter != 'boolean' ? template.options.showAccessFilter : doclet.showAccessFilter; if (result){ // if we can show the filter check if we should actually show it doclet.has = { inherited: template.find({kind: template.kinds.symbols, memberof: doclet.longname, inherited: true}).length > 0, public: template.find({kind: template.kinds.symbols, memberof: doclet.longname, access: "public"}).length > 0, protected: template.find({kind: template.kinds.symbols, memberof: doclet.longname, access: "protected"}).length > 0, private: template.find({kind: template.kinds.symbols, memberof: doclet.longname, access: "private"}).length > 0 }; var count = (doclet.has.inherited ? 1 : 0) + (doclet.has.public ? 1 : 0) + (doclet.has.protected ? 1 : 0) + (doclet.has.private ? 1 : 0); // only show the filter if there are two or more accessors available result = count > 1; } return result; }; exports.isInherited = function(doclet){ return !!doclet.inherited; }; exports.hasDetails = function (doclet) { return !!(doclet.version || doclet.since || (doclet.inherited && doclet.inherits) || doclet.since || (doclet.implementations && doclet.implementations.length) || (doclet.implements && doclet.implements.length) || (doclet.mixes && doclet.mixes.length) || doclet.deprecated || (doclet.author && doclet.author.length) || doclet.copyright || doclet.license || doclet.defaultvalue || doclet.hasSource || (doclet.tutorials && doclet.tutorials.length) || (doclet.see && doclet.see.length) || (doclet.todo && doclet.todo.length)) };