it('should not return the same filename twice', function() { var name = 'polymorphic'; var filename1 = helper.getUniqueFilename(name); var filename2 = helper.getUniqueFilename(name); expect(filename1).not.toEqual(filename2); });
var PublishJob = module.exports = function(template, options) { // directories created by the publish job this.outputDirectories = {}; this.templateConfig = template.config; this.options = options; this.destination = this.options.destination; this.navTree = null; this.package = null; this.pageTitlePrefix = ''; this.template = template.init(); this.renderOptions = { beautify: this.templateConfig.beautify }; init(); // claim some special filenames in advance // TODO: we used to avoid calling `registerLink` on `index`; okay that we do it now? // if not, should we stop registering `global`, too? this.indexUrl = helper.getUniqueFilename('index'); helper.registerLink('index', this.indexUrl); this.globalUrl = helper.getUniqueFilename('global'); helper.registerLink('global', this.globalUrl); };
it('should not consider the same name with different letter case to be unique', function() { var camel = 'myJavaScriptIdentifier'; var pascal = 'MyJavaScriptIdentifier'; var filename1 = helper.getUniqueFilename(camel); var filename2 = helper.getUniqueFilename(pascal); expect( filename1.toLowerCase() ).not.toEqual( filename2.toLowerCase() ); });
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, encoding ) ) }; } catch( e ) { logger.error( 'Error while generating source file %s: %s', file, e.message ); } generate( 'Source', sourceFiles[file].shortened, [source], sourceOutfile, false ); }
Object.keys(sourceFiles).forEach(function(file) { var source; // links are keyed to the shortened path in each doclet's `meta.filename` 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, encoding) ) }; } catch(e) { handle(e); } generate('Source: ' + sourceFiles[file].shortened, [source], sourceOutfile, conf, false); });
Object.keys(pathMap).forEach(function(file) { var data = { docs: null, pageCategory: CATEGORIES.SOURCES, pageTitle: pathMap[file], pageTitlePrefix: this.pageTitlePrefix }; // links are keyed to the shortened path url = helper.getUniqueFilename(pathMap[file]); helper.registerLink(pathMap[file], url); try { data.docs = helper.htmlsafe(fs.readFileSync(file, encoding)); } catch (e) { logger.error('Unable to generate output for source file %s: %s', file, e.message); return; } self.generate('source', data, url); }, this);
it('should convert a string with slashes into an alphanumeric hash plus the default extension', function() { var filename = helper.getUniqueFilename('tick/tock'); expect(filename).toMatch(/^[A-Za-z0-9]+\.html$/); });
it('should convert a simple string into the string plus the default extension', function() { var filename = helper.getUniqueFilename('BackusNaur'); expect(filename).toEqual('BackusNaur.html'); });
exports.publish = function( taffyData, opts, tutorials ) { data = taffyData; var conf = env.conf.templates || {}; conf.default = conf.default || {}; // Default a few config settings if( conf.addProjectSubdir === undefined || conf.addProjectSubdir !== true ) { conf.addProjectSubdir = false; } if( conf.addVersionSubdir === undefined || conf.addVersionSubdir !== true ) { conf.addVersionSubdir = false; } 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 ); data = helper.prune( data ); data.sort( 'longname, version, since' ); helper.addEventListeners( data ); var sourceFiles = {}; var sourceFilePaths = []; data().each( function( doclet ) { doclet.attribs = ''; if( doclet.examples ) { doclet.examples = doclet.examples.map( function( example ) { var caption, code; if( example.match( /^\s*<caption>([\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 ); } ); } // 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 ); } } } ); // update outdir if necessary, then create outdir var packageInfo = ( find( {kind : 'package'} ) || [] ) [0]; if( packageInfo && packageInfo.name ) { if( conf.addProjectSubdir ) { outdir = path.join( outdir, packageInfo.name ); } if( conf.addVersionSubdir ) { outdir = path.join( outdir, (packageInfo.version || '') ); } } fs.mkPath( outdir ); // copy the template's static files to outdir var fromDir = path.join( templatePath, 'static' ); var staticFiles = fs.ls( fromDir, 3 ); 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 ); 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 = helper.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]; if( url.indexOf( '#' ) > -1 ) { doclet.id = helper.longnameToUrl[doclet.longname].split( /#/ ).pop(); } else { doclet.id = doclet.name; } if( needsSignature( doclet ) ) { addSignatureParams( doclet ); addSignatureReturns( doclet ); addAttribs( doclet ); } } ); // do this after the urls have all been generated data().each( function( doclet ) { doclet.ancestors = getAncestorLinks( doclet ); if( doclet.kind === 'member' ) { addSignatureTypes( doclet ); addAttribs( doclet ); } if( doclet.kind === 'constant' ) { addSignatureTypes( doclet ); addAttribs( doclet ); doclet.kind = 'member'; } } ); var members = helper.getMembers( data ); members.tutorials = tutorials.children; // output pretty-printed source files by default var outputSourceFiles = conf.default && conf.default.outputSourceFiles !== false ? true : false; // add template helpers view.find = find; view.linkto = linkto; view.resolveAuthorLinks = resolveAuthorLinks; view.tutoriallink = tutoriallink; view.htmlsafe = htmlsafe; view.outputSourceFiles = outputSourceFiles; // once for all view.nav = buildNav( members ); 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( members.globals.length ) { generate( '', 'Global', [{kind : 'globalobj'}], globalUrl ); } // index page displays information from package.json and lists files var files = find( {kind : 'file'} ); var packages = find( {kind : 'package'} ); generate( '', 'Home', packages.concat( [ { kind : 'mainpage', readme : opts.readme, longname : (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page' } ] ).concat( files ), indexUrl ); // 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 ); 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 myClasses = helper.find( classes, {longname : longname} ); if( myClasses.length ) { generate( 'Class', myClasses[0].name, myClasses, helper.longnameToUrl[longname] ); } var myNamespaces = helper.find( namespaces, {longname : longname} ); if( myNamespaces.length ) { generate( 'Namespace', myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname] ); } var myMixins = helper.find( mixins, {longname : longname} ); if( myMixins.length ) { generate( 'Mixin', myMixins[0].name, myMixins, helper.longnameToUrl[longname] ); } var myExternals = helper.find( externals, {longname : longname} ); if( myExternals.length ) { generate( 'External', myExternals[0].name, myExternals, helper.longnameToUrl[longname] ); } var myInterfaces = helper.find( interfaces, {longname : longname} ); if( myInterfaces.length ) { generate( 'Interface', myInterfaces[0].name, myInterfaces, helper.longnameToUrl[longname] ); } } ); // TODO: move the tutorial functions to templateHelper.js function generateTutorial ( title, tutorial, filename ) { var tutorialData = { title : title, header : tutorial.title, content : tutorial.parse(), children : tutorial.children }; var tutorialPath = path.join( outdir, filename ); var html = view.render( 'tutorial.tmpl', tutorialData ); // yes, you can use {@link} in tutorials too! html = helper.resolveLinks( html ); // turn {@link foo} into <a href="foodoc.html">foo</a> fs.writeFileSync( tutorialPath, html, 'utf8' ); } // tutorials can have only one parent so there is no risk for loops function saveChildren ( node ) { node.children.forEach( function( child ) { generateTutorial( 'Tutorial: ' + child.title, child, helper.tutorialToUrl( child.name ) ); saveChildren( child ); } ); } saveChildren( tutorials ); };
exports.publish = function(taffyData, opts, tutorials) { data = taffyData; var conf = env.conf.templates || {}; conf['default'] = conf['default'] || {}; conf['weswit'] = conf['weswit'] || {}; var templatePath = opts.template; view = new template.Template(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'); var indexAllUrl = helper.getUniqueFilename('index-all'); // 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 = 'layout.tmpl'; // set up tutorials for helper helper.setTutorials(tutorials); var externs = {}; function searchDescription(className,methodName) { var _class = find({longname:className}); for (var c=0; c<_class.length; c++) { if (_class[c].augments) { for (var a = 0; a < _class[c].augments.length; a++) { var _superMethod = find({longname: _class[c].augments[a] + "#" + methodName}); for (var s = 0; s < _superMethod.length; s++) { if (_superMethod[s].inherits) { return _superMethod[s].inherits; } else if (_superMethod[s].description) { return _superMethod[s].longname; } } var inherits = searchDescription(_class[c].augments[a], methodName); if (inherits) { return inherits; } } } } return null; } //create summary if missing var methods = find({kind: 'function'}); methods.forEach(function(m) { if (!m.summary && m.description) { var d = m.description; m.summary = d.indexOf(".") > -1 ? d.substring(0,d.indexOf(".")+1) : d; } if (!m.inherited) { m.inherited = false; } if (m.reimplemented !== true && m.reimplemented !== false) { var others = find({kind: 'function', longname: m.longname, inherited: true, memberof: m.memberof}); var f = 0; others.forEach(function(o) { f++; if (!m.inherited) { m.inherits = o.inherits; o.reimplemented = true; } else if (f>1) { o.reimplemented = true; } else { o.reimplemented = false; } }); if (!m.description && !m.inherits) { m.inherits = searchDescription(m.memberof, m.name); if (m.inherits) { m.inherited = true; } } } }); var stuffWithSource = find({kind: ['class', 'module', 'global']}); stuffWithSource.forEach(function(m) { m.printSourceLink = conf['default'] && conf['default'].outputSourceFiles === true; }); data = helper.prune(data); data.sort('longname, version, since'); helper.addEventListeners(data); var sourceFiles = {}; var sourceFilePaths = []; data().each(function(doclet) { doclet.attribs = ''; if (doclet.examples) { doclet.examples = doclet.examples.map(function(example) { var caption, code; if (example.match(/^\s*<caption>([\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); }); } // build a list of source files var sourcePath; var resolvedSourcePath; if (doclet.meta) { sourcePath = getPathFromDoclet(doclet); resolvedSourcePath = resolveSourcePath(sourcePath); sourceFiles[sourcePath] = { resolved: resolvedSourcePath, shortened: null }; sourceFilePaths.push(resolvedSourcePath); } }); // 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); // copy the template's static files to outdir var fromDir = path.join(templatePath, 'static'); var staticFiles = fs.ls(fromDir, 3); 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) { staticFilePaths = 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.statSync(filePath).isDirectory() ? filePath : path.dirname(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 = helper.createLink(doclet); helper.registerLink(doclet.longname, url); // replace the filename with a shortened version of the full path var docletPath; if (doclet.meta) { docletPath = getPathFromDoclet(doclet); docletPath = sourceFiles[docletPath].shortened; if (docletPath) { doclet.meta.filename = docletPath; } } }); var namesForIndex = []; data().each(function(doclet) { //prepare alphabetic index (currently handles methods classes and modules TODO complete) //TODO might we use doclet.kind? var longname = doclet.longname if (longname.indexOf("~") > -1) { //hide private stuff } else if (longname.indexOf("#") > -1) { //instance methods var shortName = longname.substring(longname.indexOf("#")+1); shortName = shortName.replace('"','',"g"); var cName = longname.substring(0,longname.indexOf("#")); cName = cName.substring(cName.indexOf(":")+1); if (cName == "undefined") { cName = "Globals"; } namesForIndex.push({name: shortName, definition: "Instance method in " + cName, extern: cName+".prototype."+shortName+" = function() {};", longname: longname, memberof: cName}); } else if (longname.indexOf(".") > -1) { //static methods var shortName = longname.substring(longname.indexOf(".")+1); shortName = shortName.replace('"','',"g"); var cName = longname.substring(0,longname.indexOf(".")); cName = cName.substring(cName.indexOf(":")+1); if (cName == "undefined") { cName = "Globals"; } namesForIndex.push({name: shortName, definition: "Static method in " + cName, extern: cName+"."+shortName+" = function() {};", longname: longname, memberof: cName}); } else if (longname.indexOf(":") > -1) { //name undefined means globals //modules var shortName = longname.substring(longname.indexOf(":")+1); shortName = shortName.replace('"','',"g"); if (shortName == "undefined") { shortName="Globals"; } namesForIndex.push({name: shortName, definition: "Module " + shortName, extern: shortName+" = {};", longname: longname}); } else { //classes var shortName = longname.replace('"','',"g"); namesForIndex.push({name: shortName, extern: shortName+" = function() {};", definition: "Class " + longname, longname: longname}); } var url = helper.longnameToUrl[doclet.longname]; if (url.indexOf('#') > -1) { doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop(); } else { doclet.id = doclet.name; } if ( needsSignature(doclet) ) { addSignatureParams(doclet); addSignatureReturns(doclet); addAttribs(doclet); } }); namesForIndex = namesForIndex.sort(function(a,b) { var al = a.name.toLowerCase(); var bl = b.name.toLowerCase(); if (al == bl) { return 0; } return al < bl ? -1 : 1; }); var byLetterIndex = [];//would be easier with a {} var curr = null; namesForIndex.forEach(function(el) { var l = el.name[0].toUpperCase(); if (l != curr) { byLetterIndex.push([]); curr = l; } byLetterIndex[byLetterIndex.length-1].push(el); }); namesForIndex = namesForIndex.sort(function(a,b) { if (a.memberof == b.memberof) { return 0; } else if (!a.memberof) { if (!b.memberof) { return 0; } return -1; } else if (!b.memberof) { return 1; } return a.memberof < b.memberof ? -1 : 1; }); var externsIndex = []; externsIndex.push([]); curr = null; namesForIndex.forEach(function(el) { var l = el.memberof; if (l != curr) { externsIndex.push([]); curr = l; } externsIndex[externsIndex.length-1].push(el); }); // do this after the urls have all been generated data().each(function(doclet) { doclet.ancestors = getAncestorLinks(doclet); if (doclet.kind === 'member') { addSignatureTypes(doclet); addAttribs(doclet); } if (doclet.kind === 'constant') { addSignatureTypes(doclet); addAttribs(doclet); doclet.kind = 'member'; } }); var members = helper.getMembers(data); members.tutorials = tutorials.children; // add template helpers view.find = find; view.linkto = linkto; view.resolveAuthorLinks = resolveAuthorLinks; view.tutoriallink = tutoriallink; view.htmlsafe = htmlsafe; // once for all view.nav = buildNav(members,conf["weswit"].logo); attachModuleSymbols( find({ kind: ['class', 'function'], longname: {left: 'module:'} }), members.modules ); // do not output pretty-printed source files by default; do this before generating any other pages, so // that the other pages can link to the source files if (!conf['default'] || conf['default'].outputSourceFiles === true) { generateSourceFiles(sourceFiles, opts.encoding, conf["weswit"]); } if (members.globals.length) { generate('Global', [{kind: 'globalobj'}], globalUrl, conf["weswit"]); } // index page displays information from package.json and lists files var files = find({kind: 'file'}), packages = find({kind: 'package'}); var libName = conf["weswit"] && conf["weswit"].extendedLibraryName ? conf["weswit"].extendedLibraryName : "Index"; var summaryText = conf["weswit"].summaryFile ? fs.readFileSync( conf["weswit"].summaryFile, 'utf8' ) : (!opts.readme ? "Javascript Documentation" : null); generate(libName, packages.concat( [{ kind: 'mainpage', readme: opts.readme, longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page', summary:summaryText }] ).concat(files), indexUrl, conf["weswit"]); generateIndex("Index", packages.concat( [{ kind: 'index', longname: 'Index Page', }]).concat(files), indexAllUrl, conf["weswit"], byLetterIndex); generateExterns(externsIndex); // 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); Object.keys(helper.longnameToUrl).forEach(function(longname) { var myClasses = helper.find(classes, {longname: longname}); if (myClasses.length) { generate('Class: ' + myClasses[0].name, myClasses, helper.longnameToUrl[longname], conf["weswit"]); } var myModules = helper.find(modules, {longname: longname}); if (myModules.length) { generate('Module: ' + myModules[0].name, myModules, helper.longnameToUrl[longname], conf["weswit"]); } var myNamespaces = helper.find(namespaces, {longname: longname}); if (myNamespaces.length) { generate('Namespace: ' + myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname], conf["weswit"]); } var myMixins = helper.find(mixins, {longname: longname}); if (myMixins.length) { generate('Mixin: ' + myMixins[0].name, myMixins, helper.longnameToUrl[longname], conf["weswit"]); } var myExternals = helper.find(externals, {longname: longname}); if (myExternals.length) { generate('External: ' + myExternals[0].name, myExternals, helper.longnameToUrl[longname], conf["weswit"]); } }); // TODO: move the tutorial functions to templateHelper.js function generateTutorial(title, tutorial, filename) { var tutorialData = { title: title, header: tutorial.title, content: tutorial.parse(), children: tutorial.children }; var tutorialPath = path.join(outdir, filename), html = view.render('tutorial.tmpl', tutorialData); // yes, you can use {@link} in tutorials too! html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a> fs.writeFileSync(tutorialPath, html, 'utf8'); } // tutorials can have only one parent so there is no risk for loops function saveChildren(node) { node.children.forEach(function(child) { generateTutorial('Tutorial: ' + child.title, child, helper.tutorialToUrl(child.name)); saveChildren(child); }); } saveChildren(tutorials); };
it('should convert a string with slashes into the text following the last slash plus the default extension', function() { var filename = helper.getUniqueFilename('tick/tock'); expect(filename).toMatch(/^tock\.html$/); });
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 = opts.layoutFile; // set up tutorials for helper helper.setTutorials(tutorials); data = helper.prune(data); data.sort('longname, version, since'); helper.addEventListeners(data); var sourceFiles = {}; var sourceFilePaths = []; data().each(function(doclet) { doclet.attribs = ''; if (doclet.examples) { doclet.examples = doclet.examples.map(function(example) { var caption, code; if (example.match(/^\s*<caption>([\s\S]+?)<\/caption>(\s*[\n\r])([\s\S]+)$/i)) { caption = RegExp.$1; code = RegExp.$3; } return { caption: caption || '', code: code || example }; }); } if (doclet.codeExamples) { doclet.codeExamples = doclet.codeExamples.map(function(codeExample) { var caption, code; if (codeExample.match(/^\s*<caption>([\s\S]+?)<\/caption>(\s*[\n\r])([\s\S]+)$/i)) { caption = RegExp.$1; code = RegExp.$3; } return { caption: caption || '', code: code || codeExample }; }); } if (doclet.see) { doclet.see.forEach(function(seeItem, i) { doclet.see[i] = hashToLink(doclet, seeItem); }); } // 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); } } }); /* * Handle the defaul values for non optional properties correctly. * */ data().each(function(doclet) { if (doclet.properties) { doclet.properties = doclet.properties.map(function(property) { var separator = " - ", separatorLength = separator.length; var defaultvalue = property.defaultvalue; var description = property.description; if( property.defaultvalue !== 'undefined' && !property.optional && description.indexOf(separator) > 0) { var index = description.indexOf(separator); defaultvalue += " " + description.substr(separatorLength, index-separatorLength); description = "<p>" + description.substr(index + separatorLength, description.length); } return { defaultvalue: defaultvalue, description: description, type: property.type, name: property.name } }); } }); // 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); // copy the template's static files to outdir var fromDir = path.join(templatePath, 'static'); var staticFiles = fs.ls(fromDir, 3); 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; filePath = path.resolve(env.pwd, filePath); 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); }); }); } if (sourceFilePaths.length) { sourceFiles = shortenPaths( sourceFiles, path.commonPrefix(sourceFilePaths) ); } data().each(function(doclet) { var url = helper.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; } } var sourceLink; if (doclet.meta) { sourceLink = getLinkFromDoclet(doclet); doclet.meta.sourceLink = sourceLink; } }); data().each(function(doclet) { var url = helper.longnameToUrl[doclet.longname]; if (url.indexOf('#') > -1) { doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop(); } else { doclet.id = doclet.name; } if ( needsSignature(doclet) ) { addSignatureParams(doclet); //addSignatureReturns(doclet); addAttribs(doclet); } }); // do this after the urls have all been generated data().each(function(doclet) { doclet.ancestors = getAncestorLinks(doclet); if (doclet.kind === 'member') { addSignatureTypes(doclet); addAttribs(doclet); } if (doclet.kind === 'constant') { addSignatureTypes(doclet); addAttribs(doclet); doclet.kind = 'member'; doclet.constant = true; } }); data().each(function(doclet) { if(!doclet.ignore) { var parent = find({longname: doclet.memberof})[0]; if( !parent ) { doclet.scopeEf = doclet.scope; } else { if(doclet.scope === 'static' && parent.kind !== 'class') { doclet.scopeEf = 'instance'; } else if(doclet.scope === 'static' && parent.static && parent.kind === 'class') { doclet.scopeEf = 'instance'; } else { doclet.scopeEf = doclet.scope; } } } }); // handle summary, description and class description default values properly data().each(function(doclet) { if(!doclet.ignore) { if(!doclet.summary && (desc = (doclet.description || doclet.classdesc))) { //Try to split when a "." or a ".</htmlTag>" is found. //TODO: When markdown is present it fails the split and dumps all description in the summary. var split = desc.split(/(\.(<\/?([^<]+)>)?\s*)$/) doclet.summary = split[0] + (split[1] || ""); } var checkP = function(prop) { if(!prop) return; prop = prop.replace(/<p><p>/g, "<p>"); if(prop.indexOf("<p>") == -1) { return "<p>" + prop + "</p>"; } return prop; } var replaceCode = function(string) { if(!string) return; var flip = true; var idx = string.indexOf("`"); while(idx > -1) { string = string.substr(0, idx) + (flip ? "<code>" : "</code>") + string.substr(idx + 1); flip = !flip; idx = string.indexOf("`"); } return string; }; doclet.summary = replaceCode(checkP(doclet.summary)); doclet.description = replaceCode(checkP(doclet.description)); doclet.classdesc = replaceCode(checkP(doclet.classdesc)); } }); //handle splits and joins on names data().each(function(doclet) { if(!doclet.ignore) { var split = function(str, sep) { if(str) { return str.split(sep).join(''); } } //dont split for code if(doclet.description && doclet.description.indexOf("syntax.javascript") == -1) { doclet.description = split(doclet.description, '<br>'); } if(doclet.classdesc && doclet.classdesc.indexOf("syntax.javascript") == -1) { doclet.classdesc = split(doclet.classdesc, '<br>'); } if(doclet.summary && doclet.summary.indexOf("syntax.javascript") == -1) { doclet.summary = split(doclet.summary, '<br>'); } doclet.parsedName = split(doclet.name, '"') doclet.parsedLongname = split(doclet.longname, '"') } }); var members = helper.getMembers(data); members.tutorials = tutorials.children; // add template helpers view.find = find; view.linkto = linkto; view.resolveAuthorLinks = resolveAuthorLinks; view.tutoriallink = tutoriallink; view.htmlsafe = htmlsafe; // once for all view.nav = buildNav(findMembers(data, 'namespace')); attachModuleSymbols( find({ longname: {left: 'module:'} }), members.modules ); if (members.globals.length) { generate('Global', [{kind: 'globalobj'}], globalUrl); } // index page displays information from package.json and lists files var files = find({kind: 'file'}), packages = find({kind: 'package'}); generate('Home', packages.concat( [{kind: 'mainpage', readme: opts.readme, longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page'}] ).concat(files), indexUrl); // 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); 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 myClasses = helper.find(classes, {longname: longname}); if (myClasses.length) { generate('Class: ' + myClasses[0].name, myClasses, helper.longnameToUrl[longname]); } var myNamespaces = helper.find(namespaces, {longname: longname}); if (myNamespaces.length) { generate('Namespace: ' + myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname]); } var myMixins = helper.find(mixins, {longname: longname}); if (myMixins.length) { generate('Mixin: ' + myMixins[0].name, myMixins, helper.longnameToUrl[longname]); } var myExternals = helper.find(externals, {longname: longname}); if (myExternals.length) { generate('External: ' + myExternals[0].name, myExternals, helper.longnameToUrl[longname]); } var myInterfaces = helper.find(interfaces, {longname: longname}); if (myInterfaces.length) { generate('Interface: ' + myInterfaces[0].name, myInterfaces, helper.longnameToUrl[longname]); } }); // TODO: move the tutorial functions to templateHelper.js function generateTutorial(title, tutorial, filename) { var tutorialData = { title: title, header: tutorial.title, content: tutorial.parse(), children: tutorial.children }; var tutorialPath = path.join(outdir, filename), html = view.render('tutorial.tmpl', tutorialData); // yes, you can use {@link} in tutorials too! html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a> fs.writeFileSync(tutorialPath, html, 'utf8'); } // tutorials can have only one parent so there is no risk for loops function saveChildren(node) { node.children.forEach(function(child) { generateTutorial('Tutorial: ' + child.title, child, helper.tutorialToUrl(child.name)); saveChildren(child); }); } saveChildren(tutorials); };
exports.publish = function(taffyData, opts, tutorials) { data = taffyData; var conf = env.conf.templates || {}; conf['default'] = conf['default'] || {}; var templatePath = opts.template; view = new template.Template(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); data = helper.prune(data); data.sort('longname, version, since'); helper.addEventListeners(data); var sourceFiles = {}; var sourceFilePaths = []; data().each(function(doclet) { doclet.attribs = ''; switch(doclet.ngdoc) { case "provider": doclet.kind = "class"; break; case "service": doclet.kind = "class"; break; case "type": doclet.kind = "typedef"; break; case "property": doclet.kind = "member"; break; case "event": doclet.kind = "function"; break; } if (doclet.ngdoc == "provider" || doclet.ngdoc == "service") { doclet.kind = "class"; } if (doclet.examples) { doclet.examples = doclet.examples.map(function(example) { var caption, code; if (example.match(/^\s*<caption>([\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); }); } // build a list of source files var sourcePath; var resolvedSourcePath; if (doclet.meta) { sourcePath = getPathFromDoclet(doclet); resolvedSourcePath = resolveSourcePath(sourcePath); sourceFiles[sourcePath] = { resolved: resolvedSourcePath, shortened: null }; sourceFilePaths.push(resolvedSourcePath); } }); // 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); // copy the template's static files to outdir var fromDir = path.join(templatePath, 'static'), staticFiles = fs.ls(fromDir, 3); 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) { staticFilePaths = 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); }); }); } if (sourceFilePaths.length) { sourceFiles = shortenPaths( sourceFiles, path.commonPrefix(sourceFilePaths) ); } data().each(function(doclet) { var url = helper.createLink(doclet); helper.registerLink(doclet.longname, url); // replace the filename with a shortened version of the full path var docletPath; if (doclet.meta) { docletPath = getPathFromDoclet(doclet); docletPath = sourceFiles[docletPath].shortened; if (docletPath) { doclet.meta.filename = docletPath; } } }); data().each(function(doclet) { var url = helper.longnameToUrl[doclet.longname]; if (url.indexOf('#') > -1) { doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop(); } else { doclet.id = doclet.name; } if ( needsSignature(doclet) ) { addSignatureParams(doclet); addSignatureReturns(doclet); addAttribs(doclet); } }); // do this after the urls have all been generated data().each(function(doclet) { doclet.ancestors = getAncestorLinks(doclet); if (doclet.kind === 'member') { addSignatureTypes(doclet); addAttribs(doclet); } if (doclet.kind === 'constant') { addSignatureTypes(doclet); addAttribs(doclet); doclet.kind = 'member'; } }); var members = helper.getMembers(data); members.tutorials = tutorials.children; // add template helpers view.find = find; view.linkto = linkto; view.resolveAuthorLinks = resolveAuthorLinks; view.tutoriallink = tutoriallink; view.htmlsafe = htmlsafe; //grimbo: pass the conf to the template. view.outputSourceReference = (true === conf['default'].outputSourceReference); // once for all view.nav = buildNav(members); attachModuleSymbols( find({ kind: ['class', 'function'], longname: {left: 'module:'} }), members.modules ); // only output pretty-printed source files if requested; do this before generating any other // pages, so the other pages can link to the source files if (conf['default'].outputSourceFiles) { generateSourceFiles(sourceFiles); } if (members.globals.length) { generate('Global', [{kind: 'globalobj'}], globalUrl); } // index page displays information from package.json and lists files var files = find({kind: 'file'}), packages = find({kind: 'package'}); generate('Index', packages.concat( [{kind: 'mainpage', readme: opts.readme, longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page'}] ).concat(files), indexUrl); // 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); for (var longname in helper.longnameToUrl) { if ( hasOwnProp.call(helper.longnameToUrl, longname) ) { var myClasses = helper.find(classes, {longname: longname}); if (myClasses.length) { var titlePrefix = myClasses[0].ngdoc ? myClasses[0].ngdoc : 'Class'; var iconPrefix = ''; switch (titlePrefix.toLowerCase()) { case "class": case "provider": case "service": iconPrefix = '<i class="icon-shield" style="color:#0186d1"></i> '; break; case "directive": iconPrefix = '<i class="icon-archive"></i> '; break; case "type": iconPrefix = '<i class="icon-key"></i> '; break; case "property": iconPrefix = '<i class="icon-maxcdn"></i> '; break; case "module": case "modules": iconPrefix = '<i class="icon-puzzle-piece"></i> '; break; case "event": iconPrefix = '<i class="icon-cogs"></i> '; break; } generate(iconPrefix + titlePrefix + ': ' + myClasses[0].name, myClasses, helper.longnameToUrl[longname]); } var myModules = helper.find(modules, {longname: longname}); if (myModules.length) { generate('<i class="icon-puzzle-piece"></i> ' + 'Module: ' + myModules[0].name, myModules, helper.longnameToUrl[longname]); } var myNamespaces = helper.find(namespaces, {longname: longname}); if (myNamespaces.length) { generate('<i class="icon-code"></i> ' + 'Namespace: ' + myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname]); } var myMixins = helper.find(mixins, {longname: longname}); if (myMixins.length) { generate('<i class="icon-beaker"></i> ' + 'Mixin: ' + myMixins[0].name, myMixins, helper.longnameToUrl[longname]); } var myExternals = helper.find(externals, {longname: longname}); if (myExternals.length) { generate('External: ' + myExternals[0].name, myExternals, helper.longnameToUrl[longname]); } } } // TODO: move the tutorial functions to templateHelper.js function generateTutorial(title, tutorial, filename) { var tutorialData = { title: title, header: tutorial.title, content: tutorial.parse(), children: tutorial.children }; var tutorialPath = path.join(outdir, filename), html = view.render('tutorial.tmpl', tutorialData); // yes, you can use {@link} in tutorials too! html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a> fs.writeFileSync(tutorialPath, html, 'utf8'); } // tutorials can have only one parent so there is no risk for loops function saveChildren(node) { node.children.forEach(function(child) { generateTutorial('Tutorial: ' + child.title, child, helper.tutorialToUrl(child.name)); saveChildren(child); }); } saveChildren(tutorials); };
exports.publish = function(taffyData, opts, tutorials) { data = taffyData; var conf = env.conf.templates || {}; conf['default'] = conf['default'] || {}; var templatePath = opts.template; view = new template.Template(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 = 'layout.tmpl'; // set up tutorials for helper helper.setTutorials(tutorials); data = helper.prune(data); data.sort('longname, version, since'); helper.addEventListeners(data); var sourceFiles = {}; var sourceFilePaths = []; data().each(function(doclet) { doclet.attribs = ''; if (doclet.examples) { doclet.examples = doclet.examples.map(function(example) { var caption, code; if (example.match(/^\s*<caption>([\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); }); } // build a list of source files var sourcePath; var resolvedSourcePath; if (doclet.meta) { sourcePath = getPathFromDoclet(doclet); resolvedSourcePath = resolveSourcePath(sourcePath); sourceFiles[sourcePath] = { resolved: resolvedSourcePath, shortened: null }; sourceFilePaths.push(resolvedSourcePath); } }); // 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); // copy the template's static files to outdir var fromDir = path.join(templatePath, 'static'); var staticFiles = fs.ls(fromDir, 3); 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) { staticFilePaths = 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.statSync(filePath).isDirectory() ? filePath : path.dirname(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 = helper.createLink(doclet); helper.registerLink(doclet.longname, url); // replace the filename with a shortened version of the full path var docletPath; if (doclet.meta) { docletPath = getPathFromDoclet(doclet); docletPath = sourceFiles[docletPath].shortened; if (docletPath) { doclet.meta.filename = docletPath; } } }); data().each(function(doclet) { var url = helper.longnameToUrl[doclet.longname]; if (url.indexOf('#') > -1) { doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop(); } else { doclet.id = doclet.name; } if ( needsSignature(doclet) ) { addSignatureParams(doclet); addSignatureReturns(doclet); addAttribs(doclet); } }); // do this after the urls have all been generated data().each(function(doclet) { doclet.ancestors = getAncestorLinks(doclet); if (doclet.kind === 'member') { addSignatureTypes(doclet); addAttribs(doclet); } if (doclet.kind === 'constant') { addSignatureTypes(doclet); addAttribs(doclet); doclet.kind = 'member'; } }); var members = helper.getMembers(data); members.tutorials = tutorials.children; ////**debug** //if (debugMode) { // debugHtml += ('<h3>members.classes</h3>\n<pre class="source-code">\nmembers.classes =\n' + JSON.stringify(members.classes, null, " ") + '</pre>\n'); //} ////**debug** // add template helpers view.find = find; view.linkto = linkto; view.resolveAuthorLinks = resolveAuthorLinks; view.tutoriallink = tutoriallink; view.htmlsafe = htmlsafe; view.hljs = hljs; // once for all view.nav = buildNav(members); attachModuleSymbols( find({ kind: ['class', 'function'], longname: {left: 'module:'} }), members.modules ); // output source files by default; do this before generating any other pages, so // that the other pages can link to the source files if (!conf['default'] || conf['default'].outputSourceFiles !== false) { generateSourceFiles(sourceFiles, opts.encoding); } if (members.globals.length) { generate(null, 'Global', [{kind: 'globalobj'}], globalUrl); } // index page displays information from package.json and lists files var files = find({kind: 'file'}), packages = find({kind: 'package'}); //**debug** if (debugMode) { debugHtml += ('<h3>mainpage docs</h3>\n<pre class="source-code">\ndocs =\n' + JSON.stringify(packages.concat([{kind: 'mainpage', readme: opts.readme, longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page'}]), null, " ") + '</pre>\n'); } //**debug** generate('OpenSeadragonImaging API', 'OpenSeadragonImaging API', packages.concat( [{kind: 'mainpage', readme: opts.readme, longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page'}] ).concat(files), indexUrl); // 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); Object.keys(helper.longnameToUrl).forEach(function(longname) { var myClasses = helper.find(classes, {longname: longname}); if (myClasses.length) { generate(null, 'Class: ' + myClasses[0].name, myClasses, helper.longnameToUrl[longname]); } var myModules = helper.find(modules, {longname: longname}); if (myModules.length) { generate(null, 'Module: ' + myModules[0].name, myModules, helper.longnameToUrl[longname]); } var myNamespaces = helper.find(namespaces, {longname: longname}); if (myNamespaces.length) { generate(null, 'Namespace: ' + myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname]); } var myMixins = helper.find(mixins, {longname: longname}); if (myMixins.length) { generate(null, 'Mixin: ' + myMixins[0].name, myMixins, helper.longnameToUrl[longname]); } var myExternals = helper.find(externals, {longname: longname}); if (myExternals.length) { generate(null, 'External: ' + myExternals[0].name, myExternals, helper.longnameToUrl[longname]); } }); // TODO: move the tutorial functions to templateHelper.js function generateTutorial(title, tutorial, filename) { var tutorialData = { title: title, header: tutorial.title, content: tutorial.parse(), children: tutorial.children }; var tutorialPath = path.join(outdir, filename), html = view.render('tutorial.tmpl', tutorialData); // yes, you can use {@link} in tutorials too! html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a> fs.writeFileSync(tutorialPath, html, 'utf8'); } // tutorials can have only one parent so there is no risk for loops function saveChildren(node) { node.children.forEach(function(child) { generateTutorial('Tutorial: ' + child.title, child, helper.tutorialToUrl(child.name)); saveChildren(child); }); } saveChildren(tutorials); if (logMode) { fs.writeFileSync(logTextFile, logText, 'utf8'); } if (debugMode) { fs.writeFileSync(debugHtmlFile, debugHtmlHeader + debugHtml + debugHtmlFooter, 'utf8'); } };
exports.publish = function(taffyData, opts, tutorials) { data = taffyData; var conf = env.conf.templates || {}; conf['default'] = conf['default'] || {}; var templatePath = opts.template; view = new template.Template(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 = 'layout.tmpl'; extendTutorialsObj(tutorials, "external"); extendTutorialsObj(tutorials, "demo"); console.log(tutorials.children[0]); // set up tutorials for helper helper.setTutorials(tutorials); data = helper.prune(data); data.sort('longname, version, since'); helper.addEventListeners(data); var sourceFiles = {}; var sourceFilePaths = []; data().each(function(doclet) { doclet.attribs = ''; if (doclet.examples) { doclet.examples = doclet.examples.map(function(example) { var caption, code; if (example.match(/^\s*(?:<p>)?\s*<caption>([\s\S]+?)<\/caption>\s*(?:<\/p>)?[\s\r\n]*([\s\S]+)$/i)) { caption = RegExp.$1; code = RegExp.$2; } return { caption: caption || '', code: code || example }; }); } if (doclet.see) { doclet.see.forEach(function(seeItem, i) { doclet.see[i] = hashToLink(doclet, seeItem); }); } // build a list of source files var sourcePath; var resolvedSourcePath; if (doclet.meta) { sourcePath = getPathFromDoclet(doclet); resolvedSourcePath = resolveSourcePath(sourcePath); sourceFiles[sourcePath] = { resolved: resolvedSourcePath, shortened: null }; sourceFilePaths.push(resolvedSourcePath); } }); // 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); // copy the template's static files to outdir var fromDir = path.join(templatePath, 'static'); var staticFiles = fs.ls(fromDir, 3); 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) { staticFilePaths = 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.statSync(filePath).isDirectory() ? filePath : path.dirname(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 = helper.createLink(doclet); helper.registerLink(doclet.longname, url); // replace the filename with a shortened version of the full path var docletPath; if (doclet.meta) { docletPath = getPathFromDoclet(doclet); docletPath = sourceFiles[docletPath].shortened; if (docletPath) { doclet.meta.filename = docletPath; } } }); data().each(function(doclet) { var url = helper.longnameToUrl[doclet.longname]; if (url.indexOf('#') > -1) { doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop(); } else { doclet.id = doclet.name; } if ( needsSignature(doclet) ) { addSignatureParams(doclet); addSignatureReturns(doclet); addAttribs(doclet); } }); // do this after the urls have all been generated data().each(function(doclet) { doclet.ancestors = getAncestorLinks(doclet); if (doclet.kind === 'member') { addSignatureTypes(doclet); addAttribs(doclet); } if (doclet.kind === 'constant') { addSignatureTypes(doclet); addAttribs(doclet); doclet.kind = 'member'; } }); var members = helper.getMembers(data); members.tutorials = tutorials.children; // add template helpers view.find = find; view.linkto = linkto; view.resolveAuthorLinks = resolveAuthorLinks; view.tutoriallink = tutoriallink; view.htmlsafe = htmlsafe; view.members = members; //@davidshimjs: To make navigation for customizing // once for all view.nav = buildNav(members); attachModuleSymbols(find({ kind: ['class', 'function'], longname: {left: 'module:'} }), members.modules); // only output pretty-printed source files if requested; do this before generating any other // pages, so the other pages can link to the source files if (conf['default'].outputSourceFiles) { generateSourceFiles(sourceFiles); } if (members.globals.length) { generate('Global', [{kind: 'globalobj'}], globalUrl); } // index page displays information from package.json and lists files var files = find({kind: 'file'}), packages = find({kind: 'package'}); generate('Index', packages.concat( [{kind: 'mainpage', readme: opts.readme, longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page'}] ).concat(files), indexUrl); // 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); for (var longname in helper.longnameToUrl) { if ( hasOwnProp.call(helper.longnameToUrl, longname) ) { var myClasses = helper.find(classes, {longname: longname}); if (myClasses.length) { generate('Class: ' + myClasses[0].name, myClasses, helper.longnameToUrl[longname]); } var myModules = helper.find(modules, {longname: longname}); if (myModules.length) { generate('Module: ' + myModules[0].name, myModules, helper.longnameToUrl[longname]); } var myNamespaces = helper.find(namespaces, {longname: longname}); if (myNamespaces.length) { generate('Namespace: ' + myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname]); } var myMixins = helper.find(mixins, {longname: longname}); if (myMixins.length) { generate('Mixin: ' + myMixins[0].name, myMixins, helper.longnameToUrl[longname]); } var myExternals = helper.find(externals, {longname: longname}); if (myExternals.length) { generate('External: ' + myExternals[0].name, myExternals, helper.longnameToUrl[longname]); } } } // TODO: move the tutorial functions to templateHelper.js function generateTutorial(title, tutorial, filename) { var tutorialData = { title: title, header: tutorial.title, content: tutorial.parse(), children: tutorial.children, filename: filename }; var tutorialPath = path.join(outdir, filename), html = view.render('tutorial.tmpl', tutorialData); // turn {@link foo} into <a href="foodoc.html">foo</a> html = helper.resolveLinks(html); if(tutorial.demo || (tutorial.parent && tutorial.parent.demo)) { tutorialPath = tutorialPath.replace('tutorial-', 'demo-'); } fs.writeFileSync(tutorialPath, html, 'utf8'); } // tutorials can have only one parent so there is no risk for loops function saveChildren(node) { node.children.forEach(function(child) { // Do not generate static pages for the main 'headers' if(child.parent.name !== 'index' && !child.external) { generateTutorial('Tutorial: ' + child.title, child, helper.tutorialToUrl(child.name)); } saveChildren(child); }); } function getExtendedTutorialProperties (parsedJSON, extension, list, name) { var init, children; if(!list) { var list = []; init = true; parsedJSON = parsedJSON.index; } else { init = false; } if(parsedJSON.hasOwnProperty(extension)) { list.push({ 'name': name || 'index', 'extensionValue': parsedJSON[extension] }); } if(parsedJSON.hasOwnProperty('children')) { children = Object.keys(parsedJSON.children); for(var i = 0; i < children.length; i++) { getExtendedTutorialProperties(parsedJSON.children[children[i]], extension, list, children[i]); } } if(init) { return list; } } function setExtendedTutorialProperties (tutorials, extension, extended) { for(var i = 0; i < extended.length; i++) { tutorials.getByName(extended[i].name)[extension] = extended[i].extensionValue; } } function extendTutorialsObj (tutorials, extensions) { var extensionsArray = [], extended, json, parsed; if(typeof extensions === 'string') { extensionsArray.push(extensions); } json = fs.readFileSync(env.opts.template + '/' + env.opts.tutorials + '/' + env.opts.tutorials + '.json' , env.opts.encoding); parsed = JSON.parse(json); for(var i = 0; i < extensionsArray.length; i++) { extended = getExtendedTutorialProperties (parsed, extensionsArray[i]); setExtendedTutorialProperties(tutorials, extensionsArray[i], extended); } return tutorials; } saveChildren(tutorials); };
helper = require('jsdoc/util/templateHelper'), moment = require('moment'), htmlsafe = helper.htmlsafe, sanitizeHtml = require('sanitize-html'), linkto = helper.linkto, resolveAuthorLinks = helper.resolveAuthorLinks, hasOwnProp = Object.prototype.hasOwnProperty, conf = env.conf.templates || {}, data, view, outdir = env.opts.destination, searchEnabled = conf.search !== false; logger.info('logger level', logger.getLevel()); var globalUrl = helper.getUniqueFilename('global'); var indexUrl = helper.getUniqueFilename('index'); if (conf.syntaxTheme) { logger.warn('`template.syntaxTheme` is ignored. You can change the syntax theme by modifying template/styles/main.less.'); } var navOptions = { analytics: conf.analytics || null, collapseSymbols: conf.collapseSymbols || false, copyright: conf.copyright || '', dateFormat: conf.dateFormat, disablePackagePath: conf.disablePackagePath, footer: conf.footer || '', includeDate: conf.includeDate !== false, inverseNav: conf.inverseNav,
exports.publish = function(taffyData, opts, tutorials) { data = taffyData; var conf = env.conf.templates || {}; conf['default'] = conf['default'] || {}; var templatePath = opts.template; view = new template.Template(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 = 'layout.tmpl'; // set up tutorials for helper helper.setTutorials(tutorials); data = helper.prune(data); data.sort('longname, version, since'); helper.addEventListeners(data); var sourceFiles = {}; var sourceFilePaths = []; data().each(function(doclet) { doclet.attribs = ''; if (doclet.examples) { doclet.examples = doclet.examples.map(function(example) { var caption, code; if (example.match(/^\s*<caption>([\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); }); } // 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); } } }); // 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); // copy the template's static files to outdir var fromDir = path.join(templatePath, 'static'); var staticFiles = fs.ls(fromDir, 3); staticFiles.forEach(function(fileName) { var toDir = fs.toDir( fileName.replace(fromDir, outdir) ); fs.mkPath(toDir); fs.copyFileSync(fileName, toDir); }); if (sourceFilePaths.length) { sourceFiles = shortenPaths( sourceFiles, path.commonPrefix(sourceFilePaths) ); } data().each(function(doclet) { var url = helper.createLink(doclet); helper.registerLink(doclet.longname, url); // replace the filename with a shortened version of the full path var docletPath; if (doclet.meta) { docletPath = getPathFromDoclet(doclet); docletPath = sourceFiles[docletPath].shortened; if (docletPath) { doclet.meta.filename = docletPath; doclet.meta.sourceUrl = conf['sourceUrl'].replace('{version}', process.env.CESIUM_VERSION).replace('{filename}', docletPath); } } }); data().each(function(doclet) { var url = helper.longnameToUrl[doclet.longname]; if (url.indexOf('#') > -1) { doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop(); } else { doclet.id = doclet.name; } if ( needsSignature(doclet) ) { addSignatureParams(doclet); addSignatureReturns(doclet); addAttribs(doclet); } }); // do this after the urls have all been generated data().each(function(doclet) { doclet.ancestors = getAncestorLinks(doclet); if (doclet.kind === 'member') { addSignatureTypes(doclet); addAttribs(doclet); } if (doclet.kind === 'constant') { addSignatureTypes(doclet); addAttribs(doclet); doclet.kind = 'member'; } }); var members = helper.getMembers(data); // add template helpers view.find = find; view.linkto = linkto; view.resolveAuthorLinks = resolveAuthorLinks; view.tutoriallink = tutoriallink; view.htmlsafe = htmlsafe; // once for all view.nav = buildNav(members); attachModuleSymbols( find({ kind: ['class', 'function'], longname: {left: 'module:'} }), members.modules ); if (members.globals.length) { generate('Global', [{kind: 'globalobj'}], globalUrl); } // index page displays information from package.json and lists files var files = find({kind: 'file'}), packages = find({kind: 'package'}); var origLayout = view.layout; view.layout = 'indexLayout.tmpl'; generate('Index', packages.concat( [{kind: 'mainpage', readme: opts.readme, longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page'}] ).concat(files), indexUrl); view.layout = origLayout; // set up the lists that we'll use to generate pages var classes = taffy(members.classes); var modules = taffy(members.modules); var typesJson = {}; Object.keys(helper.longnameToUrl).forEach(function(longname) { var items = helper.find(classes, {longname: longname}); if (!items.length) { items = helper.find(modules, {longname: longname}); } if (items.length) { var title = items[0].name; var filename = helper.longnameToUrl[longname]; generate(title, items, filename); var titleLower = title.toLowerCase(); typesJson[titleLower] = typesJson[titleLower] || []; typesJson[titleLower].push(filename); var members = find({kind: ['function','member'], memberof: longname}); members.forEach(function(member) { member = member.id; var memberLower = member.toLowerCase(); typesJson[memberLower] = typesJson[memberLower] || []; typesJson[memberLower].push(filename + '#' + member); }); } }); fs.writeFileSync(outdir + '/types.txt', JSON.stringify(typesJson), 'utf8'); };
_ = 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 = {version: 2}, 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 : {
exports.publish = function(taffyData, opts, tutorials) { data = taffyData; var conf = env.conf.templates || {}; conf['default'] = conf['default'] || {}; var templatePath = opts.template; view = new template.Template(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 = 'layout.tmpl'; // set up tutorials for helper helper.setTutorials(tutorials); data = helper.prune(data); data.sort('longname, version, since'); var sourceFiles = {}; var sourceFilePaths = []; data().each(function(doclet) { doclet.attribs = ''; if (doclet.examples) { doclet.examples = doclet.examples.map(function(example) { var caption, code; if (example.match(/^\s*<caption>([\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); }); } // build a list of source files var sourcePath; var resolvedSourcePath; if (doclet.meta) { sourcePath = getPathFromDoclet(doclet); resolvedSourcePath = resolveSourcePath(sourcePath); sourceFiles[sourcePath] = { resolved: resolvedSourcePath, shortened: null }; sourceFilePaths.push(resolvedSourcePath); } }); // 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); // copy static files to outdir var fromDir = path.join(templatePath, 'static'), staticFiles = fs.ls(fromDir, 3); staticFiles.forEach(function(fileName) { var toDir = fs.toDir( fileName.replace(fromDir, outdir) ); fs.mkPath(toDir); fs.copyFileSync(fileName, toDir); }); if (sourceFilePaths.length) { sourceFiles = shortenPaths( sourceFiles, path.commonPrefix(sourceFilePaths) ); } data().each(function(doclet) { var url = helper.createLink(doclet); helper.registerLink(doclet.longname, url); // replace the filename with a shortened version of the full path var docletPath; if (doclet.meta) { docletPath = getPathFromDoclet(doclet); docletPath = sourceFiles[docletPath].shortened; if (docletPath) { doclet.meta.filename = docletPath; } } }); data().each(function(doclet) { var url = helper.longnameToUrl[doclet.longname]; if (url.indexOf('#') > -1) { doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop(); } else { doclet.id = doclet.name; } if ( needsSignature(doclet) ) { addSignatureParams(doclet); addSignatureReturns(doclet); addAttribs(doclet); } }); // do this after the urls have all been generated data().each(function(doclet) { doclet.ancestors = getAncestorLinks(doclet); if (doclet.kind === 'member') { addSignatureTypes(doclet); addAttribs(doclet); } if (doclet.kind === 'constant') { addSignatureTypes(doclet); addAttribs(doclet); doclet.kind = 'member'; } }); var members = helper.getMembers(data); members.tutorials = tutorials.children; // add template helpers view.find = find; view.linkto = linkto; view.resolveAuthorLinks = resolveAuthorLinks; view.tutoriallink = tutoriallink; view.htmlsafe = htmlsafe; // once for all view.nav = buildNav(members); var summaryData = buildSummary(members); //console.log(summaryData); // only output pretty-printed source files if requested; do this before generating any other // pages, so the other pages can link to the source files if (conf['default'].outputSourceFiles) { generateSourceFiles(sourceFiles); } if (members.globals.length) { generate('Global', [{kind: 'globalobj'}], globalUrl); } // index page displays information from package.json and lists files var files = find({kind: 'file'}), packages = find({kind: 'package'}); generate('Index', packages.concat( [{kind: 'mainpage', readme: opts.readme, longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page',summaryData:summaryData}] ).concat(files), indexUrl); // 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); for (var longname in helper.longnameToUrl) { if ( hasOwnProp.call(helper.longnameToUrl, longname) ) { var myClasses = helper.find(classes, {longname: longname}); if (myClasses.length) { //test //if(longname=="$.Scroll"){ //console.log(myClasses); generate('Class: ' + myClasses[0].name, myClasses, helper.longnameToUrl[longname]); //} } var myModules = helper.find(modules, {longname: longname}); if (myModules.length) { generate('Module: ' + myModules[0].name, myModules, helper.longnameToUrl[longname]); } var myNamespaces = helper.find(namespaces, {longname: longname}); if (myNamespaces.length) { generate('Namespace: ' + myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname]); } var myMixins = helper.find(mixins, {longname: longname}); if (myMixins.length) { generate('Mixin: ' + myMixins[0].name, myMixins, helper.longnameToUrl[longname]); } var myExternals = helper.find(externals, {longname: longname}); if (myExternals.length) { generate('External: ' + myExternals[0].name, myExternals, helper.longnameToUrl[longname]); } } } // TODO: move the tutorial functions to templateHelper.js function generateTutorial(title, tutorial, filename) { var tutorialData = { title: title, header: tutorial.title, content: tutorial.parse(), children: tutorial.children }; var tutorialPath = path.join(outdir, filename), html = view.render('tutorial.tmpl', tutorialData); // yes, you can use {@link} in tutorials too! html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a> fs.writeFileSync(tutorialPath, html, 'utf8'); } // tutorials can have only one parent so there is no risk for loops function saveChildren(node) { node.children.forEach(function(child) { generateTutorial('Tutorial: ' + child.title, child, helper.tutorialToUrl(child.name)); saveChildren(child); }); } saveChildren(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) data = helper.prune(data) data.sort("longname, version, since") helper.addEventListeners(data) var sourceFiles = {} var sourceFilePaths = [] data().each(function (doclet) { doclet.attribs = "" if (doclet.examples) { doclet.examples = doclet.examples.map(function (example) { var caption, code if ( example.match( /^\s*<caption>([\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) }) } // 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) } } }) // 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) // copy the template's static files to outdir var fromDir = path.join(templatePath, "static") var staticFiles = fs.ls(fromDir, 3) 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 ) 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 = helper.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] if (url.indexOf("#") > -1) { doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop() } else { doclet.id = doclet.name } if (needsSignature(doclet)) { addSignatureParams(doclet) addSignatureReturns(doclet) addAttribs(doclet) } }) // do this after the urls have all been generated data().each(function (doclet) { doclet.ancestors = getAncestorLinks(doclet) if (doclet.kind === "member") { addSignatureTypes(doclet) addAttribs(doclet) } if (doclet.kind === "constant") { addSignatureTypes(doclet) addAttribs(doclet) doclet.kind = "member" } }) var members = helper.getMembers(data) members.tutorials = tutorials.children // output pretty-printed source files by default var outputSourceFiles = conf.default && conf.default.outputSourceFiles !== false ? true : false // add template helpers view.find = find view.linkto = linkto view.resolveAuthorLinks = resolveAuthorLinks view.tutoriallink = tutoriallink view.htmlsafe = htmlsafe view.outputSourceFiles = outputSourceFiles // once for all view.nav = buildNav(members) 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 (members.globals.length) { generate("", "Global", [{kind: "globalobj"}], globalUrl) } // index page displays information from package.json and lists files var files = find({kind: "file"}) var packages = find({kind: "package"}) generate( "", "Home", packages .concat([ { kind: "mainpage", readme: opts.readme, longname: opts.mainpagetitle ? opts.mainpagetitle : "Main Page" } ]) .concat(files), indexUrl ) // 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) 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 myClasses = helper.find(classes, {longname: longname}) if (myClasses.length) { generate( "Class", myClasses[0].name, myClasses, helper.longnameToUrl[longname] ) } var myNamespaces = helper.find(namespaces, {longname: longname}) if (myNamespaces.length) { generate( "Namespace", myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname] ) } var myMixins = helper.find(mixins, {longname: longname}) if (myMixins.length) { generate( "Mixin", myMixins[0].name, myMixins, helper.longnameToUrl[longname] ) } var myExternals = helper.find(externals, {longname: longname}) if (myExternals.length) { generate( "External", myExternals[0].name, myExternals, helper.longnameToUrl[longname] ) } var myInterfaces = helper.find(interfaces, {longname: longname}) if (myInterfaces.length) { generate( "Interface", myInterfaces[0].name, myInterfaces, helper.longnameToUrl[longname] ) } }) // TODO: move the tutorial functions to templateHelper.js function generateTutorial(title, tutorial, filename) { var tutorialData = { title: title, header: tutorial.title, content: tutorial.parse(), children: tutorial.children } var tutorialPath = path.join(outdir, filename) var html = view.render("tutorial.tmpl", tutorialData) // yes, you can use {@link} in tutorials too! html = helper.resolveLinks(html) // turn {@link foo} into <a href="foodoc.html">foo</a> fs.writeFileSync(tutorialPath, html, "utf8") } // tutorials can have only one parent so there is no risk for loops function saveChildren(node) { node.children.forEach(function (child) { generateTutorial( child.title, child, helper.tutorialToUrl(child.name) ) saveChildren(child) }) } saveChildren(tutorials) }