diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..36ffc1e --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,12 @@ +{ + "env": { + "node": true + }, + "extends": "eslint:recommended", + "rules": { + "indent": ["error", 2, {"SwitchCase": 1}], + "linebreak-style": ["error", "unix"], + "max-len": ["error", {"code": 120}], + "quotes": ["error", "single"] + } +} diff --git a/package.json b/package.json index a78546f..66c4bab 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ }, "dependencies": { "catharsis": "^0.8.7", + "eslint": "^4.14.0", "lodash": "^3.10.0", "moment": "^2.10.6", "taffydb": "https://github.com/hegemonic/taffydb/tarball/7d100bcee0e997ee4977e273cdce60bd8933050e" diff --git a/publish.js b/publish.js index fde73b5..a509846 100644 --- a/publish.js +++ b/publish.js @@ -11,37 +11,31 @@ var template = require('jsdoc/template'); var util = require('util'); var _ = require('lodash'); var catharsis = require('catharsis'); -//var parseMarkdown = require('jsdoc/util/markdown').getParser(); var tutorial = require('jsdoc/tutorial'); - var htmlsafe = helper.htmlsafe; var resolveAuthorLinks = helper.resolveAuthorLinks; -var scopeToPunc = helper.scopeToPunc; var hasOwnProp = Object.prototype.hasOwnProperty; - var data; var view; - var indexdir = path.normalize(env.opts.destination); var outdir = path.join(indexdir, 'docs'); // These next two are lifted out of jsdoc3/util/templateHelper.js - function isComplexTypeExpression(expr) { - // record types, type unions, and type applications all count as "complex" - return /^{.+}$/.test(expr) || /^.+\|.+$/.test(expr) || /^.+<.+>$/.test(expr); + // record types, type unions, and type applications all count as "complex" + return /^{.+}$/.test(expr) || /^.+\|.+$/.test(expr) || /^.+<.+>$/.test(expr); } function parseType(longname) { - var err; + var err; - try { - return catharsis.parse(longname, {jsdoc: true}); - } - catch (e) { - err = new Error('unable to parse ' + longname + ': ' + e.message); - console.error(err); - return longname; - } + try { + return catharsis.parse(longname, {jsdoc: true}); + } + catch (e) { + err = new Error('unable to parse ' + longname + ': ' + e.message); + logger.error(err); + return longname; + } } function headingId(heading) { @@ -50,7 +44,7 @@ function headingId(heading) { function getHeadings(html, level) { var result = []; - var regexString = util.format('(.*)<\/h%s>', level, level); + var regexString = util.format('(.*)', level, level); var regex = new RegExp(regexString, 'gi'); html.replace(regex, function (whole, heading) { result.push(heading); @@ -78,20 +72,13 @@ function formatType(type) { return 'null'; case 'TypeApplication': if (type.expression.name === 'Array') { - return util.format( - '%s[]', - type.applications.map(formatType).join('') - ); + return util.format('%s[]', type.applications.map(formatType).join('')); } - return util.format( - '%s<%s>', - formatType(type.expression), - type.applications.map(formatType).join('') - ); + return util.format('%s<%s>', formatType(type.expression),type.applications.map(formatType).join('')); case 'TypeUnion': return type.elements.map(formatType).join('|'); default: - throw new Error("Unknown type: `" + type.type + "`\nProblematic type:\n" + util.inspect(type, {depth: 10})); + throw new Error('Unknown type: `' + type.type + '`\nProblematic type:\n' + util.inspect(type, {depth: 10})); } } @@ -100,8 +87,8 @@ function generateTutorial(tutorial) { } function createLink(doclet) { - id = _.isString(doclet) ? doclet : elementId(doclet); - return util.format("#%s", id); + var id = _.isString(doclet) ? doclet : elementId(doclet); + return util.format('#%s', id); } function linkto() { @@ -127,18 +114,11 @@ function linkto() { } function sectionId(doclet) { - return util.format( - "section-%s", - elementId(doclet) - ); + return util.format('section-%s', elementId(doclet)); } function subsectionId(doclet, subsection) { - return util.format( - "%s-subsection-%s", - elementId(doclet), - subsection - ); + return util.format('%s-subsection-%s', elementId(doclet), subsection); } function sectionLink(section) { @@ -149,13 +129,6 @@ function subsectionLink(doclet, subsection) { return createLink(subsectionId(doclet, subsection)); } -function constructorId(doclet) { - return util.format( - "%s-constructor", - elementId(doclet) - ); -} - function elementId(doclet) { return (doclet.longname || doclet.name || '') .replace('#event:', '-event-') @@ -165,12 +138,12 @@ function elementId(doclet) { } function find(spec) { - return helper.find(data, spec); + return helper.find(data, spec); } function simplifyName(namepath) { // Doesn't necessarily handle all types yet. Just doing this for events for now. - var regex = /"(.*)"$|[:#~\.](\w*)$/; + var regex = /"(.*)"$|[:#~.](\w*)$/; var matches = namepath.match(regex); return matches[1] || matches[2] || namepath; } @@ -184,21 +157,14 @@ function formattedParent(data) { } } -function tutoriallink(tutorial) { - return helper.toTutorial(tutorial, null, { tag: 'em', classname: 'disabled', prefix: 'Tutorial: ' }); -} - function getAncestorLinks(doclet) { - return helper.getAncestorLinks(data, doclet); + return helper.getAncestorLinks(data, doclet); } function hashToLink(doclet, hash) { - if ( !/^(#.+)/.test(hash) ) { return hash; } - - var url = createLink(doclet); - - url = url.replace(/(#.+|$)/, hash); - return '' + hash + ''; + if (!/^(#.+)/.test(hash)) { return hash; } + var url = createLink(doclet).replace(/(#.+|$)/, hash); + return '' + hash + ''; } function isLodashMethod(doclet) { @@ -208,24 +174,23 @@ function isLodashMethod(doclet) { } function needsFunctionSignature(doclet) { - var needsSig = false; + var needsSig = false; - // function and class definitions always get a signature - if (doclet.kind === 'function' || doclet.kind === 'class') { + // function and class definitions always get a signature + if (doclet.kind === 'function' || doclet.kind === 'class') { + needsSig = true; + } + // typedefs that contain functions get a signature, too + else if (doclet.kind === 'typedef' && doclet.type && doclet.type.names && doclet.type.names.length) { + for (var i = 0, l = doclet.type.names.length; i < l; i++) { + if (doclet.type.names[i].toLowerCase() === 'function') { needsSig = true; + break; + } } - // typedefs that contain functions get a signature, too - else if (doclet.kind === 'typedef' && doclet.type && doclet.type.names && - doclet.type.names.length) { - for (var i = 0, l = doclet.type.names.length; i < l; i++) { - if (doclet.type.names[i].toLowerCase() === 'function') { - needsSig = true; - break; - } - } - } + } - return needsSig; + return needsSig; } function needsEventSignature(doclet) { @@ -233,93 +198,83 @@ function needsEventSignature(doclet) { } function getSignatureAttributes(item) { - var attributes = []; + var attributes = []; - if (item.nullable === true) { - attributes.push('nullable'); - } - else if (item.nullable === false) { - attributes.push('non-null'); - } + if (item.nullable === true) { + attributes.push('nullable'); + } + else if (item.nullable === false) { + attributes.push('non-null'); + } - return attributes; + return attributes; } function updateItemName(item, options) { - options = _.extend({default: false}, options); - var attributes = getSignatureAttributes(item); - var itemName = item.name || ''; + options = _.extend({default: false}, options); + var attributes = getSignatureAttributes(item); + var itemName = item.name || ''; - // Wrap item name in span. - itemName = util.format('%s', itemName); + itemName = util.format('%s', itemName); - // Prefix varargs parameter with ellipsis. - if (item.variable) { - itemName = '' + itemName; - } + // Prefix varargs parameter with ellipsis. + if (item.variable) { + itemName = '' + itemName; + } - if (options.default && !_.isUndefined(item.defaultvalue)) { - itemName += - '' + - '=' + - '' + - item.defaultvalue + - '' + - ''; - } + if (options.default && !_.isUndefined(item.defaultvalue)) { + itemName += '=' + + item.defaultvalue + ''; + } - // Embracket optional param. - if (item.optional) { - itemName = - '[' + - itemName + - ']'; - } + // Embracket optional param. + if (item.optional) { + itemName = '[' + itemName + ']'; + } - if (attributes && attributes.length) { - itemName = util.format( '%s%s', itemName, - attributes.join(' ') ); - } + if (attributes && attributes.length) { + itemName = util.format('%s%s', itemName, attributes.join(' ')); + } - return itemName; + return itemName; } function addParamAttributes(params) { - return params.filter(function(param) { - return param.name && param.name.indexOf('.') === -1; - }).map(updateItemName); + return params.filter(function(param) { + return param.name && param.name.indexOf('.') === -1; + }).map(updateItemName); } function buildItemTypeStrings(item) { - var types = []; + var types = []; - if (item && item.type && item.type.names) { - item.type.names.forEach(function(name) { - types.push( linkto(name, htmlsafe(name)) ); - }); - } + if (item && item.type && item.type.names) { + item.type.names.forEach(function(name) { + types.push( linkto(name, htmlsafe(name)) ); + }); + } - return types; + return types; } function buildAttribsString(attribs) { - var attribsString = ''; + var attribsString = ''; - if (attribs && attribs.length) { - attribsString = htmlsafe( util.format('(%s) ', attribs.join(', ')) ); - } + if (attribs && attribs.length) { + attribsString = htmlsafe( util.format('(%s) ', attribs.join(', ')) ); + } - return attribsString; + return attribsString; } function addNonParamAttributes(items) { - var types = []; + var types = []; - items.forEach(function(item) { - types = types.concat( buildItemTypeStrings(item) ); - }); + items.forEach(function(item) { + types = types.concat( buildItemTypeStrings(item) ); + }); - return types; + return types; } function ensureQuotes(string) { @@ -331,11 +286,7 @@ function stripQuotes(string) { } function paren(isOpening) { - return ( - '' + - (isOpening ? '(' : ')') + - '' - ); + return '' + (isOpening ? '(' : ')') + ''; } function comma() { @@ -352,7 +303,6 @@ function parameterList(params) { } function addEventSignature(doclet) { - var p = parameterList(doclet.params); doclet.signature = util.format( 'on%s%s%s %s =>', paren(true), @@ -364,141 +314,131 @@ function addEventSignature(doclet) { function addSignatureName(doclet) { var target = doclet.isLodashMethod ? doclet.see[0] : doclet.longname ; - doclet.signature = util.format( - '%s%s', - linkto(target, doclet.name), - doclet.signature || '' - ); + doclet.signature = util.format('%s%s', linkto(target, doclet.name), doclet.signature || ''); } function addSignatureParams(f) { - var params = f.params ? addParamAttributes(f.params) : []; f.signature = util.format('%s%s', f.signature, parameterList(f.params)); } function addSignatureReturns(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); - } + 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); + } + }); + }); - if (f.returns) { - returnTypes = addNonParamAttributes(f.returns); - } - if (returnTypes.length) { - returnTypesString = util.format( - ' → %s %s', - attribsString ? util.format('(%s)', attribsString) : '', - returnTypes.join('|') - ); - } + attribsString = buildAttribsString(attribs); + } - f.signature = '' + (f.signature || '') + '' + - '' + returnTypesString + ''; + if (f.returns) { + returnTypes = addNonParamAttributes(f.returns); + } + if (returnTypes.length) { + returnTypesString = util.format( + ' → %s %s', + attribsString ? util.format('(%s)', attribsString) : '', + returnTypes.join('|') + ); + } + + f.signature = '' + (f.signature || '') + '' + + returnTypesString + ''; } function addSignatureTypes(f) { - var types = f.type ? buildItemTypeStrings(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); - - // Manually assign `isStatic`. - f.isStatic = _.contains(attribs, 'static'); - if (f.isStatic) _.pull(attribs, 'static') + var attribs = helper.getAttribs(f); - // Remove `static` from list. TODO: Do this for all 'attributes'. - var attribsString = buildAttribsString(attribs); + // Manually assign `isStatic`. + f.isStatic = _.contains(attribs, 'static'); + if (f.isStatic) _.pull(attribs, 'static'); + // Remove `static` from list. TODO: Do this for all 'attributes'. + var attribsString = buildAttribsString(attribs); - f.attribs = util.format('%s', attribsString); + f.attribs = util.format('%s', attribsString); } function shortenPaths(files, commonPrefix) { - Object.keys(files).forEach(function(file) { - files[file].shortened = files[file].resolved.replace(commonPrefix, '') - // always use forward slashes - .replace(/\\/g, '/'); - }); + Object.keys(files).forEach(function(file) { + // always use forward slashes + files[file].shortened = files[file].resolved.replace(commonPrefix, '').replace(/\\/g, '/'); + }); - return files; + return files; } function getPathFromDoclet(doclet) { - if (!doclet.meta) { - return null; - } + if (!doclet.meta) { + return null; + } - return doclet.meta.path && doclet.meta.path !== 'null' ? - path.join(doclet.meta.path, doclet.meta.filename) : - doclet.meta.filename; + return doclet.meta.path && doclet.meta.path !== 'null' ? + path.join(doclet.meta.path, doclet.meta.filename) : + doclet.meta.filename; } function generate(type, title, docs, filename, resolveLinks, className) { - resolveLinks = resolveLinks === false ? false : true; - - var docData = { - type: type, - title: title, - docs: docs, - className: className, - subdir: type == 'index' ? 'docs/' : '', - rootdir: type == 'index' ? '' : '../' - }; - - var outpath = filename, - html = view.render('container.tmpl', docData); - - if (resolveLinks) { - html = helper.resolveLinks(html); // turn {@link foo} into foo - } + resolveLinks = resolveLinks === false ? false : true; + + var docData = { + type: type, + title: title, + docs: docs, + className: className, + subdir: type == 'index' ? 'docs/' : '', + rootdir: type == 'index' ? '' : '../' + }; + var outpath = filename + var html = view.render('container.tmpl', docData); + + if (resolveLinks) { + html = helper.resolveLinks(html); // turn {@link foo} into foo + } - fs.writeFileSync(outpath, html, 'utf8'); + fs.writeFileSync(outpath, html, 'utf8'); } function generateSourceFiles(sourceFiles, encoding) { - encoding = encoding || 'utf8'; - Object.keys(sourceFiles).forEach(function(file) { - var source; - // links are keyed to the shortened path in each doclet's `meta.shortpath` property - var sourceOutfile = path.join( - 'docs', - helper.getUniqueFilename(sourceFiles[file].shortened) - ); - helper.registerLink(sourceFiles[file].shortened, sourceOutfile); - - try { - source = { - kind: 'source', - code: helper.htmlsafe( fs.readFileSync(sourceFiles[file].resolved, encoding) ) - }; - } - catch(e) { - logger.error('Error while generating source file %s: %s', file, e.message); - } + encoding = encoding || 'utf8'; + Object.keys(sourceFiles).forEach(function(file) { + var source; + // links are keyed to the shortened path in each doclet's `meta.shortpath` property + var sourceOutfile = path.join('docs', helper.getUniqueFilename(sourceFiles[file].shortened)); - generate('Source', sourceFiles[file].shortened, [source], sourceOutfile, false, 'source-page'); - }); + helper.registerLink(sourceFiles[file].shortened, sourceOutfile); + + try { + source = { + kind: 'source', + code: helper.htmlsafe( fs.readFileSync(sourceFiles[file].resolved, encoding) ) + }; + } + catch(e) { + logger.error('Error while generating source file %s: %s', file, e.message); + } + + generate('Source', sourceFiles[file].shortened, [source], sourceOutfile, false, 'source-page'); + }); } /** @@ -513,33 +453,31 @@ function generateSourceFiles(sourceFiles, encoding) { * @param {Array.} modules - The array of module doclets to search. */ function attachModuleSymbols(doclets, modules) { - var symbols = {}; + var symbols = {}; - // build a lookup table - doclets.forEach(function(symbol) { - symbols[symbol.longname] = symbols[symbol.longname] || []; - symbols[symbol.longname].push(symbol); - }); + // build a lookup table + doclets.forEach(function(symbol) { + symbols[symbol.longname] = symbols[symbol.longname] || []; + symbols[symbol.longname].push(symbol); + }); - return modules.map(function(module) { - if (symbols[module.longname]) { - module.modules = symbols[module.longname] - // Only show symbols that have a description. Make an exception for classes, because - // we want to show the constructor-signature heading no matter what. - .filter(function(symbol) { - return symbol.description || symbol.kind === 'class'; - }) - .map(function(symbol) { - symbol = doop(symbol); - - if (symbol.kind === 'class' || symbol.kind === 'function') { - symbol.name = symbol.name.replace('module:', '(require("') + '"))'; - } - - return symbol; - }); + return modules.map(function(module) { + if (symbols[module.longname]) { + module.modules = symbols[module.longname].filter(function(symbol) { + // Only show symbols that have a description. Make an exception for classes, because + // we want to show the constructor-signature heading no matter what. + return symbol.description || symbol.kind === 'class'; + }).map(function(symbol) { + symbol = doop(symbol); + + if (symbol.kind === 'class' || symbol.kind === 'function') { + symbol.name = symbol.name.replace('module:', '(require("') + '"))'; } - }); + + return symbol; + }); + } + }); } function buildSubsectionLink(doclet, subsection, title) { @@ -559,16 +497,13 @@ function buildNavItemList(items, className, linktoFn) { } function buildTutorialsNav(tutorials) { - return tutorials.map(function(tutorial) { - var result = util.format( - '
  • %s

    ', - linkto(tutorial.longname, tutorial.title) - ); + return tutorials.reduce(function(html, tutorial) { + var result = util.format('
  • %s

    ', linkto(tutorial.longname, tutorial.title)); if (tutorial.children) { result += buildNavItemList(tutorial.children, 'sections', linkto); } - return result + '
  • '; - }); + return html + result + ''; + }, ''); } function buildReadmeNav(readme) { @@ -584,83 +519,70 @@ function buildReadmeNav(readme) { } function buildChangelogNav() { - return ( - '' - ); + return ''; } function buildMemberNav(item) { var itemsNav = ''; var statics = find({kind:'function', isStatic: true, memberof: item.longname}); var members = find({kind:'member', memberof: item.longname}); - var methods = find({kind:'function', isInitialize: false, isLodashMethod: false, isStatic: false, memberof: item.longname}); + var methods = find({ + kind:'function', + isInitialize: false, + isLodashMethod: false, + isStatic: false, + memberof: item.longname + }); var lodash = find({kind:'function', isLodashMethod: true, memberof: item.longname}); var events = find({kind:'event', memberof: item.longname}); var classes = find({kind:'class', memberof: item.longname}); - var initialize = find({kind:'function', isInitialize: true, isLodashMethod: false, isStatic: false, memberof: item.longname}); + var initialize = find({ + kind:'function', + isInitialize: true, + isLodashMethod: false, + isStatic: false, + memberof: item.longname + }); - if ( !hasOwnProp.call(item, 'longname') ) { - itemsNav += '
  • ' + linkto('', item.name); - itemsNav += '
  • '; - } else { - var itemName = - itemsNav += '
  • '; - itemsNav += util.format( - '

    %s

    ', - sectionLink(item), - item.name.replace(/^module:/, '') - ); - - /* - itemsNav += - '
    • ' + - linkto(item.longname, 'constructor') + - '
    '; - */ - itemsNav += buildSubsectionLink(item, 'construction', 'Construction'); - itemsNav += buildNavItemList([item].concat(initialize), 'construction', linkto); - - if (statics.length) { - itemsNav += buildSubsectionLink(item, 'static', 'Static'); - itemsNav += buildNavItemList(statics, 'static', linkto); - } - if (members.length) { - itemsNav += buildSubsectionLink(item, 'members', 'Members'); - itemsNav += buildNavItemList(members, 'members', linkto); - } - if (methods.length) { - itemsNav += buildSubsectionLink(item, 'methods', 'Methods'); - itemsNav += buildNavItemList(methods, 'methods', linkto); - } - if (lodash.length) { - itemsNav += buildSubsectionLink(item, 'lodash-methods', 'Lodash Methods'); - itemsNav += buildNavItemList(lodash, 'lodash-methods', linkto); - } - if (events.length) { - itemsNav += buildSubsectionLink(item, 'events', 'Events'); - itemsNav += buildNavItemList(events, 'events', linkto); - } - itemsNav += '
  • '; + if (!hasOwnProp.call(item, 'longname')) { + itemsNav += '
  • ' + linkto('', item.name) + '
  • '; + } + else { + itemsNav += '
  • '; + itemsNav += util.format('

    %s

    ', sectionLink(item), item.name.replace(/^module:/, '')); + itemsNav += buildSubsectionLink(item, 'construction', 'Construction'); + itemsNav += buildNavItemList([item].concat(initialize), 'construction', linkto); + + if (statics.length) { + itemsNav += buildSubsectionLink(item, 'static', 'Static'); + itemsNav += buildNavItemList(statics, 'static', linkto); + } + if (members.length) { + itemsNav += buildSubsectionLink(item, 'members', 'Members'); + itemsNav += buildNavItemList(members, 'members', linkto); + } + if (methods.length) { + itemsNav += buildSubsectionLink(item, 'methods', 'Methods'); + itemsNav += buildNavItemList(methods, 'methods', linkto); + } + if (lodash.length) { + itemsNav += buildSubsectionLink(item, 'lodash-methods', 'Lodash Methods'); + itemsNav += buildNavItemList(lodash, 'lodash-methods', linkto); + } + if (events.length) { + itemsNav += buildSubsectionLink(item, 'events', 'Events'); + itemsNav += buildNavItemList(events, 'events', linkto); + } + + itemsNav += '
  • '; } itemsNav += classes.map(buildMemberNav).join(''); return itemsNav; } -function buildMemberNavs(items, itemHeading, itemsSeen, linktoFn) { - return items.length - ? items.map(buildMemberNav).join('') - : ''; -} - -function linktoTutorial(longName, name) { - return tutoriallink(name); -} - -function linktoExternal(longName, name) { - return linkto(longName, name.replace(/(^"|"$)/g, '')); +function buildMemberNavs(items) { + return items.length ? items.map(buildMemberNav).join('') : ''; } /** @@ -677,48 +599,38 @@ function linktoExternal(longName, name) { * @param {array} members.interfaces * @return {string} The HTML for the navigation sidebar. */ -var bs = 0; function buildNav(members, readme) { - var nav = ''; - var seen = {}; - var seenTutorials = {}; - - nav += buildReadmeNav(readme); - - nav += buildChangelogNav() - - nav += '
      '; - nav += buildTutorialsNav(members.tutorials); - nav += buildMemberNavs(members.topLevelClasses, 'Classes', seen, linkto); - //nav += buildMemberNav(members.modules, 'Modules', {}, linkto); - //nav += buildMemberNav(members.externals, 'Externals', seen, linktoExternal); - //nav += buildMemberNav(members.events, 'Events', seen, linkto); - //nav += buildMemberNav(members.namespaces, 'Namespaces', seen, linkto); - //nav += buildMemberNav(members.mixins, 'Mixins', seen, linkto); - //nav += buildMemberNav(members.tutorials, 'Tutorials', seenTutorials, linktoTutorial); - //nav += buildMemberNav(members.interfaces, 'Interfaces', seen, linkto); - nav += '
    '; - - if (members.globals.length) { - var globalNav = ''; - - members.globals.forEach(function(g) { - if ( g.kind !== 'typedef' && !hasOwnProp.call(seen, g.longname) ) { - globalNav += '
  • ' + linkto(g.longname, g.name) + '
  • '; - } - seen[g.longname] = true; - }); - - if (!globalNav) { - // turn the heading into a link so you can actually get to the global page - nav += '

    ' + linkto('global', 'Global') + '

    '; - } - else { - nav += '

    Global

      ' + globalNav + '
    '; - } + var nav = ''; + var seen = {}; + + nav += buildReadmeNav(readme); + nav += buildChangelogNav() + nav += '
      '; + nav += buildTutorialsNav(members.tutorials); + nav += buildMemberNavs(members.topLevelClasses); + nav += '
    '; + + if (members.globals.length) { + var globalNav = ''; + + members.globals.forEach(function(g) { + if (g.kind !== 'typedef' && !hasOwnProp.call(seen, g.longname)) { + globalNav += '
  • ' + linkto(g.longname, g.name) + '
  • '; + } + + seen[g.longname] = true; + }); + + if (!globalNav) { + // turn the heading into a link so you can actually get to the global page + nav += '

    ' + linkto('global', 'Global') + '

    '; + } + else { + nav += '

    Global

      ' + globalNav + '
    '; } + } - return nav; + return nav; } /** @@ -727,297 +639,244 @@ function buildNav(members, readme) { @param {Tutorial} tutorials */ exports.publish = function(taffyData, opts, tutorials) { - data = taffyData; - - var conf = env.conf.templates || {}; - conf.default = conf.default || {}; - - var templatePath = path.normalize(opts.template); - view = new template.Template( path.join(templatePath, 'tmpl') ); - - // claim some special filenames in advance, so the All-Powerful Overseer of Filename Uniqueness - // doesn't try to hand them out later - var indexUrl = helper.getUniqueFilename('index'); - // don't call registerLink() on this one! 'index' is also a valid longname - - var globalUrl = helper.getUniqueFilename('global'); - helper.registerLink('global', globalUrl); - - // set up templating - view.layout = conf.default.layoutFile ? - path.getResourcePath(path.dirname(conf.default.layoutFile), - path.basename(conf.default.layoutFile) ) : - 'layout.tmpl'; - - // set up tutorials for helper - helper.setTutorials(tutorials); - - function registerTutorial(tutorial) { - var url = createLink(tutorial); - helper.registerLink(tutorial.longname, url); - tutorial.children.forEach(registerTutorial); - }; - - tutorials.children.forEach(registerTutorial); - - data = helper.prune(data); - data.sort('longname, version, since'); - helper.addEventListeners(data); - - var sourceFiles = {}; - var sourceFilePaths = []; - data().each(function(doclet) { - doclet.attribs = ''; - - // Identify Lodash methods to be stubbed. - doclet.isLodashMethod = isLodashMethod(doclet); - doclet.isInitialize = doclet.name == 'initialize'; - - if (doclet.examples) { - doclet.examples = doclet.examples.map(function(example) { - var caption, code; - - if (example.match(/^\s*([\s\S]+?)<\/caption>(\s*[\n\r])([\s\S]+)$/i)) { - caption = RegExp.$1; - code = RegExp.$3; - } - - return { - caption: caption || '', - code: code || example - }; - }); - } - if (doclet.see) { - doclet.see.forEach(function(seeItem, i) { - doclet.see[i] = hashToLink(doclet, seeItem); - }); - } + data = taffyData; + var conf = env.conf.templates || {}; + conf.default = conf.default || {}; + var templatePath = path.normalize(opts.template); + view = new template.Template(path.join(templatePath, 'tmpl')); + + // Claim some special filenames in advance, so the All-Powerful Overseer of Filename Uniqueness + // doesn't try to hand them out later. + // Don't call registerLink() on this one! 'index' is also a valid longname + var indexUrl = helper.getUniqueFilename('index'); + var globalUrl = helper.getUniqueFilename('global'); + helper.registerLink('global', globalUrl); + + // set up templating + view.layout = conf.default.layoutFile ? + path.getResourcePath(path.dirname(conf.default.layoutFile), path.basename(conf.default.layoutFile)) : + 'layout.tmpl'; + + helper.setTutorials(tutorials); + + function registerTutorial(tutorial) { + var url = createLink(tutorial); + helper.registerLink(tutorial.longname, url); + tutorial.children.forEach(registerTutorial); + } - // build a list of source files - var sourcePath; - if (doclet.meta) { - sourcePath = getPathFromDoclet(doclet); - sourceFiles[sourcePath] = { - resolved: sourcePath, - shortened: null - }; - if (sourceFilePaths.indexOf(sourcePath) === -1) { - sourceFilePaths.push(sourcePath); - } - } - }); + tutorials.children.forEach(registerTutorial); - // update outdir if necessary, then create outdir - var packageInfo = ( find({kind: 'package'}) || [] ) [0]; - if (packageInfo && packageInfo.name) { - outdir = path.join( outdir, packageInfo.name, (packageInfo.version || '') ); - } - fs.mkPath(outdir); + data = helper.prune(data); + data.sort('longname, version, since'); + helper.addEventListeners(data); - // copy the template's static files to outdir - var fromDir = path.join(templatePath, 'static'); - var staticFiles = fs.ls(fromDir, 3); + var sourceFiles = {}; + var sourceFilePaths = []; - // Add fontawesome... + data().each(function(doclet) { + doclet.attribs = ''; - staticFiles.forEach(function(fileName) { - var toDir = fs.toDir( fileName.replace(fromDir, outdir) ); - fs.mkPath(toDir); - fs.copyFileSync(fileName, toDir); - }); + // Identify Lodash methods to be stubbed. + doclet.isLodashMethod = isLodashMethod(doclet); + doclet.isInitialize = doclet.name == 'initialize'; + + if (doclet.examples) { + doclet.examples = doclet.examples.map(function(example) { + var caption, code; + + if (example.match(/^\s*([\s\S]+?)<\/caption>(\s*[\n\r])([\s\S]+)$/i)) { + caption = RegExp.$1; + code = RegExp.$3; + } - // copy user-specified static files to outdir - var staticFilePaths; - var staticFileFilter; - var staticFileScanner; - if (conf.default.staticFiles) { - // The canonical property name is `include`. We accept `paths` for backwards compatibility - // with a bug in JSDoc 3.2.x. - staticFilePaths = conf.default.staticFiles.include || - conf.default.staticFiles.paths || - []; - staticFileFilter = new (require('jsdoc/src/filter')).Filter(conf.default.staticFiles); - staticFileScanner = new (require('jsdoc/src/scanner')).Scanner(); - - staticFilePaths.forEach(function(filePath) { - var extraStaticFiles = staticFileScanner.scan([filePath], 10, staticFileFilter); - - extraStaticFiles.forEach(function(fileName) { - var sourcePath = fs.toDir(filePath); - var toDir = fs.toDir( fileName.replace(sourcePath, outdir) ); - fs.mkPath(toDir); - fs.copyFileSync(fileName, toDir); - }); - }); + return { + caption: caption || '', + code: code || example + }; + }); } - if (sourceFilePaths.length) { - sourceFiles = shortenPaths( sourceFiles, path.commonPrefix(sourceFilePaths) ); + if (doclet.see) { + doclet.see.forEach(function(seeItem, i) { + doclet.see[i] = hashToLink(doclet, seeItem); + }); } - data().each(function(doclet) { - var url = createLink(doclet); - helper.registerLink(doclet.longname, url); - - // add a shortened version of the full path - var docletPath; - if (doclet.meta) { - docletPath = getPathFromDoclet(doclet); - docletPath = sourceFiles[docletPath].shortened; - if (docletPath) { - doclet.meta.shortpath = docletPath; - } - } - }); - data().each(function(doclet) { - var url = helper.longnameToUrl[doclet.longname]; + // build a list of source files + var sourcePath; + if (doclet.meta) { + sourcePath = getPathFromDoclet(doclet); + sourceFiles[sourcePath] = { + resolved: sourcePath, + shortened: null + }; + + if (sourceFilePaths.indexOf(sourcePath) === -1) { + sourceFilePaths.push(sourcePath); + } + } + }); - doclet.id = elementId(doclet); + // update outdir if necessary, then create outdir + var packageInfo = (find({kind: 'package'}) || [])[0]; - if ( needsFunctionSignature(doclet) ) { - addSignatureName(doclet); - addSignatureParams(doclet); - addSignatureReturns(doclet); - addAttribs(doclet); - } else if (needsEventSignature(doclet)) { - addEventSignature(doclet); - } - }); + if (packageInfo && packageInfo.name) { + outdir = path.join(outdir, packageInfo.name, (packageInfo.version || '')); + } - // do this after the urls have all been generated - data().each(function(doclet) { - doclet.ancestors = getAncestorLinks(doclet); + fs.mkPath(outdir); - if (doclet.kind === 'member') { - addSignatureName(doclet); - addSignatureTypes(doclet); - addAttribs(doclet); - } + // copy the template's static files to outdir + var fromDir = path.join(templatePath, 'static'); + var staticFiles = fs.ls(fromDir, 3); - if (doclet.kind === 'constant') { - addSignatureTypes(doclet); - addAttribs(doclet); - doclet.kind = 'member'; - } - }); + staticFiles.forEach(function(fileName) { + var toDir = fs.toDir(fileName.replace(fromDir, outdir)); + fs.mkPath(toDir); + fs.copyFileSync(fileName, toDir); + }); + + // copy user-specified static files to outdir + var staticFilePaths; + var staticFileFilter; + var staticFileScanner; + + if (conf.default.staticFiles) { + // The canonical property name is `include`. We accept `paths` for backwards compatibility + // with a bug in JSDoc 3.2.x. + staticFilePaths = conf.default.staticFiles.include || conf.default.staticFiles.paths || []; + staticFileFilter = new (require('jsdoc/src/filter')).Filter(conf.default.staticFiles); + staticFileScanner = new (require('jsdoc/src/scanner')).Scanner(); + + staticFilePaths.forEach(function(filePath) { + var extraStaticFiles = staticFileScanner.scan([filePath], 10, staticFileFilter); - var members = helper.getMembers(data); - members.tutorials = tutorials.children; - - // set up the lists that we'll use to generate pages - var classes = taffy(members.classes); - var modules = taffy(members.modules); - var namespaces = taffy(members.namespaces); - var mixins = taffy(members.mixins); - var externals = taffy(members.externals); - var interfaces = taffy(members.interfaces); - - // Find and store top level classes. - var topLevelClasses = helper.find(classes, {memberof: {isUndefined: true}}); - - var whitelist = opts.whitelist; - if (whitelist) { - topLevelClasses = whitelist.map(function(longname) { - var result = _.find(topLevelClasses, {longname: longname}); - if (!result) throw new Error('White listed class `' + longname + '` not found'); - return result; + extraStaticFiles.forEach(function(fileName) { + var sourcePath = fs.toDir(filePath); + var toDir = fs.toDir(fileName.replace(sourcePath, outdir)); + + fs.mkPath(toDir); + fs.copyFileSync(fileName, toDir); }); + }); + } + + if (sourceFilePaths.length) { + sourceFiles = shortenPaths(sourceFiles, path.commonPrefix(sourceFilePaths)); + } + + data().each(function(doclet) { + var url = createLink(doclet); + + helper.registerLink(doclet.longname, url); + + // add a shortened version of the full path + var docletPath; + + if (doclet.meta) { + docletPath = sourceFiles[getPathFromDoclet(doclet)].shortened; + + if (docletPath) { + doclet.meta.shortpath = docletPath; + } } + }); + + data().each(function(doclet) { + doclet.id = elementId(doclet); - members.topLevelClasses = topLevelClasses; - - - // output pretty-printed source files by default - var outputSourceFiles = conf.default && conf.default.outputSourceFiles !== false - ? true - : false; - - var showInheritedFrom = conf.default && conf.default.showInheritedFrom !== false - ? true - : false - - // add template helpers - view.find = find; - view.linkto = linkto; - view.updateItemName = updateItemName; - view.elementId = elementId; - view.sectionId = sectionId; - view.subsectionId = subsectionId; - view.simplifyName = simplifyName; - view.formattedParent = formattedParent; - view.resolveAuthorLinks = resolveAuthorLinks; - view.htmlsafe = htmlsafe; - view.outputSourceFiles = outputSourceFiles; - view.showInheritedFrom = showInheritedFrom; - view.generateTutorial = generateTutorial; - view.moment = require('moment'); - - // once for all - view.nav = buildNav(members, opts.readme); - attachModuleSymbols( find({ longname: {left: 'module:'} }), members.modules ); - - // generate the pretty-printed source files first so other pages can link to them - if (outputSourceFiles) { - generateSourceFiles(sourceFiles, opts.encoding); + if (needsFunctionSignature(doclet)) { + addSignatureName(doclet); + addSignatureParams(doclet); + addSignatureReturns(doclet); + addAttribs(doclet); + } + else if (needsEventSignature(doclet)) { + addEventSignature(doclet); } + }); + + // do this after the urls have all been generated + data().each(function(doclet) { + doclet.ancestors = getAncestorLinks(doclet); - if (members.globals.length) { - generate('', 'Global', [{kind: 'globalobj'}], globalUrl); + if (doclet.kind === 'member') { + addSignatureName(doclet); + addSignatureTypes(doclet); + addAttribs(doclet); } - // index page displays information from package.json and lists files - var files = find({kind: 'file'}); - var packages = find({kind: 'package'}); - - // Get changelog. - var changelog = fs.readFileSync(opts.changelog, opts.encoding); - changelog = new tutorial.Tutorial(null, changelog, tutorial.TYPES.MARKDOWN); - - generate('index', 'Bookshelf.js', - packages.concat( - [{kind: 'mainpage', - readme: addHeadingIds(opts.readme), - tutorials: tutorials, - longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page' - }] - ).concat(topLevelClasses).concat(files).concat({ - kind: 'mainpage', changelog: changelog - }), - indexUrl - ); + if (doclet.kind === 'constant') { + addSignatureTypes(doclet); + addAttribs(doclet); + doclet.kind = 'member'; + } + }); - /* - Object.keys(helper.longnameToUrl).forEach(function(longname) { - var myModules = helper.find(modules, {longname: longname}); - if (myModules.length) { - generate('Module', myModules[0].name, myModules, helper.longnameToUrl[longname]); - } + var members = helper.getMembers(data); + members.tutorials = tutorials.children; - var myClasses = helper.find(classes, {longname: longname}); - if (myClasses.length) { - generate('Class', myClasses[0].name, myClasses, helper.longnameToUrl[longname]); - } + // set up the lists that we'll use to generate pages + var classes = taffy(members.classes); + var topLevelClasses = helper.find(classes, {memberof: {isUndefined: true}}); + var whitelist = opts.whitelist; - var myNamespaces = helper.find(namespaces, {longname: longname}); - if (myNamespaces.length) { - generate('Namespace', myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname]); - } + if (whitelist) { + topLevelClasses = whitelist.map(function(longname) { + var result = _.find(topLevelClasses, {longname: longname}); + if (!result) throw new Error('White listed class `' + longname + '` not found'); + return result; + }); + } - var myMixins = helper.find(mixins, {longname: longname}); - if (myMixins.length) { - generate('Mixin', myMixins[0].name, myMixins, helper.longnameToUrl[longname]); - } + members.topLevelClasses = topLevelClasses; + + // output pretty-printed source files by default + var outputSourceFiles = conf.default && conf.default.outputSourceFiles !== false; + var showInheritedFrom = conf.default && conf.default.showInheritedFrom !== false; + + // add template helpers + view.find = find; + view.linkto = linkto; + view.updateItemName = updateItemName; + view.elementId = elementId; + view.sectionId = sectionId; + view.subsectionId = subsectionId; + view.simplifyName = simplifyName; + view.formattedParent = formattedParent; + view.resolveAuthorLinks = resolveAuthorLinks; + view.htmlsafe = htmlsafe; + view.outputSourceFiles = outputSourceFiles; + view.showInheritedFrom = showInheritedFrom; + view.generateTutorial = generateTutorial; + view.moment = require('moment'); + + view.nav = buildNav(members, opts.readme); + + attachModuleSymbols(find({longname: {left: 'module:'}}), members.modules); + + // generate the pretty-printed source files first so other pages can link to them + if (outputSourceFiles) { + generateSourceFiles(sourceFiles, opts.encoding); + } - var myExternals = helper.find(externals, {longname: longname}); - if (myExternals.length) { - generate('External', myExternals[0].name, myExternals, helper.longnameToUrl[longname]); - } + if (members.globals.length) { + generate('', 'Global', [{kind: 'globalobj'}], globalUrl); + } - var myInterfaces = helper.find(interfaces, {longname: longname}); - if (myInterfaces.length) { - generate('Interface', myInterfaces[0].name, myInterfaces, helper.longnameToUrl[longname]); - } - }); - */ + // index page displays information from package.json and lists files + var files = find({kind: 'file'}); + var packages = find({kind: 'package'}); + var changelog = new tutorial.Tutorial(null, fs.readFileSync(opts.changelog, opts.encoding), tutorial.TYPES.MARKDOWN); + var readmeAndTutorials = [{ + kind: 'mainpage', + readme: addHeadingIds(opts.readme), + tutorials: tutorials, + longname: opts.mainpagetitle ? opts.mainpagetitle : 'Main Page' + }]; + var changelogDoc = {kind: 'mainpage', changelog: changelog}; + var docs = packages.concat(readmeAndTutorials, topLevelClasses, files, changelogDoc); + + generate('index', 'Bookshelf.js', docs, indexUrl); };