"use strict";
/**
* @module template/publish
* @type {*}
*/
/*global env: true */
var template = require( 'jsdoc/template' ),
fs = require( 'jsdoc/fs' ),
_ = require( 'underscore' ),
path = require( 'jsdoc/path' ),
taffy = require( 'taffydb' ).taffy,
handle = require( 'jsdoc/util/error' ).handle,
helper = require( 'jsdoc/util/templateHelper' ),
htmlsafe = helper.htmlsafe,
linkto = helper.linkto,
resolveAuthorLinks = helper.resolveAuthorLinks,
scopeToPunc = helper.scopeToPunc,
hasOwnProp = Object.prototype.hasOwnProperty,
conf = env.conf.templates || {},
data,
view,
outdir = env.opts.destination;
var globalUrl = helper.getUniqueFilename( 'global' );
var indexUrl = helper.getUniqueFilename( 'index' );
var navOptions = {
systemName : conf.systemName || "Documentation",
navType : conf.navType || "vertical",
footer : conf.footer || "",
copyright : conf.copyright || "",
theme : conf.theme || "simplex",
linenums : conf.linenums,
collapseSymbols : conf.collapseSymbols || false,
inverseNav : conf.inverseNav
};
var navigationMaster = {
index : {
title : navOptions.systemName,
link : indexUrl,
members : []
},
namespace : {
title : "Namespaces",
link : helper.getUniqueFilename( "namespaces.list" ),
members : []
},
module : {
title : "Modules",
link : helper.getUniqueFilename( "modules.list" ),
members : []
},
class : {
title : "Classes",
link : helper.getUniqueFilename( 'classes.list' ),
members : []
},
mixin : {
title : "Mixins",
link : helper.getUniqueFilename( "mixins.list" ),
members : []
},
event : {
title : "Events",
link : helper.getUniqueFilename( "events.list" ),
members : []
},
tutorial : {
title : "Tutorials",
link : helper.getUniqueFilename( "tutorials.list" ),
members : []
},
global : {
title : "Global",
link : globalUrl,
members : []
},
external : {
title : "Externals",
link : helper.getUniqueFilename( "externals.list" ),
members : []
}
};
function find( spec ) {
return helper.find( data, spec );
}
function tutoriallink( tutorial ) {
return helper.toTutorial( tutorial, null, { tag : 'em', classname : 'disabled', prefix : 'Tutorial: ' } );
}
function getAncestorLinks( doclet ) {
return helper.getAncestorLinks( data, doclet );
}
function hashToLink( doclet, hash ) {
if ( !/^(#.+)/.test( hash ) ) { return hash; }
var url = helper.createLink( doclet );
url = url.replace( /(#.+|$)/, hash );
return '' + hash + '';
}
function needsSignature( doclet ) {
var needsSig = false;
// 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;
}
}
}
return needsSig;
}
function addSignatureParams( f ) {
var params = helper.getSignatureParams( f, 'optional' );
f.signature = (f.signature || '') + '(' + params.join( ', ' ) + ')';
}
function addSignatureReturns( f ) {
var returnTypes = helper.getSignatureReturns( f );
f.signature = '' + (f.signature || '') + '' + '' + (returnTypes.length ? ' → {' + returnTypes.join( '|' ) + '}' : '') + '';
}
function addSignatureTypes( f ) {
var types = helper.getSignatureTypes( f );
f.signature = (f.signature || '') + '' + (types.length ? ' :' + types.join( '|' ) : '') + '';
}
function addAttribs( f ) {
var attribs = helper.getAttribs( f );
f.attribs = '' + htmlsafe( attribs.length ? '<' + attribs.join( ', ' ) + '> ' : '' ) + '';
}
function shortenPaths( files, commonPrefix ) {
// always use forward slashes
var regexp = new RegExp( '\\\\', 'g' );
Object.keys( files ).forEach( function ( file ) {
files[file].shortened = files[file].resolved.replace( commonPrefix, '' )
.replace( regexp, '/' );
} );
return files;
}
function getPathFromDoclet( doclet ) {
if ( !doclet.meta ) {
return;
}
return doclet.meta.path && doclet.meta.path !== 'null' ?
doclet.meta.path + '/' + doclet.meta.filename :
doclet.meta.filename;
}
function generate( docType, title, docs, filename, resolveLinks ) {
resolveLinks = resolveLinks === false ? false : true;
var docData = {
title : title,
docs : docs,
docType : docType
};
var outpath = path.join( outdir, filename ),
html = view.render( 'container.tmpl', docData );
if ( resolveLinks ) {
html = helper.resolveLinks( html ); // turn {@link foo} into foo
}
fs.writeFileSync( outpath, html, 'utf8' );
}
function generateSourceFiles( sourceFiles ) {
Object.keys( sourceFiles ).forEach( function ( file ) {
var source;
// links are keyed to the shortened path in each doclet's `meta.shortpath` property
var sourceOutfile = helper.getUniqueFilename( sourceFiles[file].shortened );
helper.registerLink( sourceFiles[file].shortened, sourceOutfile );
try {
source = {
kind : 'source',
code : helper.htmlsafe( fs.readFileSync( sourceFiles[file].resolved, 'utf8' ) )
};
}
catch ( e ) {
handle( e );
}
generate( 'source', 'Source: ' + sourceFiles[file].shortened, [source], sourceOutfile,
false );
} );
}
/**
* Look for classes or functions with the same name as modules (which indicates that the module
* exports only that class or function), then attach the classes or functions to the `module`
* property of the appropriate module doclets. The name of each class or function is also updated
* for display purposes. This function mutates the original arrays.
*
* @private
* @param {Array.} doclets - The array of classes and functions to
* check.
* @param {Array.} modules - The array of module doclets to search.
*/
function attachModuleSymbols( doclets, modules ) {
var symbols = {};
// build a lookup table
doclets.forEach( function ( symbol ) {
symbols[symbol.longname] = symbol;
} );
return modules.map( function ( module ) {
if ( symbols[module.longname] ) {
module.module = symbols[module.longname];
module.module.name = module.module.name.replace( 'module:', 'require("' ) + '")';
}
} );
}
/**
* Create the navigation sidebar.
* @param {object} members The members that will be used to create the sidebar.
* @param {array