const initDb = () => { if (finalConfig.local.save !== 'NEVER') { if (!finalConfig.local.save) { throw new Error('config.local.save was not set') } if (!finalConfig.local.location) { throw new Error('config.local.location was not set') } try { const localDb = JSON.parse(fs.readFileSync(finalConfig.local.location)) if (localDb && !Array.isArray(localDb)) { throw new Error('Local database was not an array') } return taffy(localDb) } catch (err) { if (err.code !== 'ENOENT') { throw err } } } return taffy([]) }
/*@ngInject*/ export default function ownCardsController($scope, cardDetailsDialog, cards, ownCards) { var ownCardsTmpDB = taffy(); ownCardsTmpDB.insert(cards.filter({ id: _.map(ownCards.getAll(), 'id') })); $scope.scope = $scope; $scope.db = ownCardsTmpDB; $scope.filteredCards = []; $scope.maxResultLength = 20; $scope.currentPage = 1; $scope.cards = []; $scope.totalItems = 0; $scope.filterCollapsed = true; function updateList() { $scope.cards = $scope.filteredCards.slice(($scope.currentPage - 1) * $scope.maxResultLength, $scope.currentPage * $scope.maxResultLength); $scope.totalItems = $scope.filteredCards.length; } $scope.showCardModal = cardDetailsDialog.show; $scope.$watch('currentPage', updateList); $scope.$watch('maxResultLength', updateList); $scope.$watch('filterUpdateTimeStamp', updateList); };
it('should prune private members if env.opts.private is falsy', function() { var priv = !!env.opts['private']; env.opts['private'] = false; var pruned = helper.prune( taffy(arrayPrivate) )().get(); compareObjectArrays([], pruned); env.opts['private'] = !!priv; });
it('should not prune private members if env.opts.private is truthy', function() { var priv = !!env.opts['private']; env.opts['private'] = true; var pruned = helper.prune( taffy(arrayPrivate) )().get(); compareObjectArrays(arrayPrivate, pruned); env.opts['private'] = !!priv; });
ESDoc.generate(config, (data, asts, config)=>{ fs.removeSync(config.destination); let db = taffy(data); db.find = function(...cond) { return db(...cond).map(v => v); }; global.db = db; defaultPublisher(data, asts, config); });
cli.generateDocs = function() { var path = require('jsdoc/path'); var resolver = require('jsdoc/tutorial/resolver'); var taffy = require('taffydb').taffy; var template; env.opts.template = (function() { var publish = env.opts.template || 'templates/default'; // convoluted way to detect the correct path for the templates; done this round-about way to cope // with scenarios where JSDoc is executed in another project's working directory where that // project has templates of itself in a similar directory structure (templates/<name>/) var templatePath = path.getResourcePath(publish, "publish.js"); if (!templatePath) { logger.error('Unable to find the template "%s"', publish); return publish; } else { // correct the path to the template: templatePath = path.dirname(templatePath); } // if we didn't find the template, keep the user-specified value so the error message is // useful return templatePath || env.opts.template; })(); try { template = require(env.opts.template + '/publish'); } catch (e) { logger.fatal('Unable to load template: ' + e.message || e); } // templates should include a publish.js file that exports a "publish" function if (template.publish && typeof template.publish === 'function') { logger.info('Generating output files...'); var publishPromise = template.publish( taffy(props.docs), env.opts, resolver.root ); return Promise.resolve(publishPromise); } else { logger.fatal(env.opts.template + ' does not export a "publish" function. Global ' + '"publish" functions are no longer supported.'); } return Promise.resolve(); };
cli.generateDocs = function() { var path = require('jsdoc/path'); var resolver = require('jsdoc/tutorial/resolver'); var taffy = require('taffydb').taffy; var template; env.opts.template = (function() { var isNode = require('jsdoc/util/runtime').isNode(); var publish = env.opts.template || 'templates/default'; var templatePath = path.getResourcePath(publish); if (templatePath && isNode) { // On Node.js, the template needs to be inside the JSDoc folder if (templatePath.indexOf(env.dirname) !== 0) { templatePath = copyResourceDir(templatePath); } } // if we didn't find the template, keep the user-specified value so the error message is // useful return templatePath || env.opts.template; })(); try { template = require(env.opts.template + '/publish'); } catch(e) { logger.fatal('Unable to load template: ' + e.message || e); } // templates should include a publish.js file that exports a "publish" function if (template.publish && typeof template.publish === 'function') { logger.printInfo('Generating output files...'); template.publish( taffy(props.docs), env.opts, resolver.root ); logger.info('complete.'); } else { logger.fatal(env.opts.template + ' does not export a "publish" function. Global ' + '"publish" functions are no longer supported.'); } return cli; };
cli.generateDocs = function() { var path = require('jsdoc/path'); var resolver = require('jsdoc/tutorial/resolver'); var taffy = require('taffydb').taffy; var template; env.opts.template = (function() { var publish = env.opts.template || 'templates/default'; var templatePath = path.getResourcePath(publish); // if we didn't find the template, keep the user-specified value so the error message is // useful return templatePath || env.opts.template; })(); try { template = require(env.opts.template + '/publish'); } catch (e) { try { template = require(env.opts.template); } catch (ee) { logger.fatal('Unable to load template: ' + ee.message || ee); } } // templates should include a publish.js file that exports a "publish" function if (template.publish && typeof template.publish === 'function') { var publishPromise; logger.info('Generating output files...'); publishPromise = template.publish( taffy(props.docs), env.opts, resolver.root ); return Promise.resolve(publishPromise); } else { logger.fatal(env.opts.template + ' does not export a "publish" function. Global ' + '"publish" functions are no longer supported.'); } return Promise.resolve(); };
/*@ngInject*/ export default function CardsService($q, data, cardColor) { this.db = taffy(); this.filter = (search) => { return this.db(search).get(); }; this.limitFilter = (searchQuery, limit) => { return this.db(searchQuery).limit(limit).get(); }; this.prepareDataBase = () => { let defer = $q.defer(); if (this.db().count() === 0) { data.getCardData().then((cardData) => { each(cardData, (mtgSet) => { let cards = map(mtgSet.cards, (card) => { let foreignNames = card.foreignNames || []; foreignNames.push({ name: card.name }); return Object.assign( {}, card, { cardColor: cardColor.getColorBitsForDb(card.manaCost), setCode: mtgSet.code, setName: mtgSet.name, foreignNames: foreignNames, concatNames: map(foreignNames, 'name').join(' ° ') } ); }); this.db.insert(cards); }); defer.resolve(); }); } else { defer.resolve(); } return defer.promise; }; };
JSDoc.generateDocs = function() { var path = require('jsdoc/path'); var resolver = require('jsdoc/tutorial/resolver'); var taffy = require('taffydb').taffy; var template; env.opts.template = (function() { var publish = env.opts.template || 'templates/default'; // if we don't find it, keep the user-specified value so the error message is useful return path.getResourcePath(publish) || env.opts.template; })(); try { template = require(env.opts.template + '/publish'); } catch(e) { throw new Error('Unable to load template: ' + e.message || e); } // templates should include a publish.js file that exports a "publish" function if (template.publish && typeof template.publish === 'function') { // convert this from a URI back to a path if necessary env.opts.template = path._uriToPath(env.opts.template); template.publish( taffy(props.docs), env.opts, resolver.root ); } else { throw new Error(env.opts.template + ' does not export a "publish" function. Global ' + '"publish" functions are no longer supported.'); } };
beforeEach(angular.mock.inject(function ($controller, $rootScope, $q) { scope = $rootScope.$new(); scope.db = taffy(); $controller('CardFilterController', { $scope: scope, data: { getSetList: function () { return $q.when([ { code: 'TEST' } ]); }, isAvailable: function () { return true; } }, sets: { filter: function () { return [{ code: 'TEST' }]; } } }); }));
it('should prune the correct members', function() { var pruned = helper.prune( taffy(array) )().get(); compareObjectArrays(keep, pruned); });
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 = ''; doclet.longname = doclet.longname.replace(/^module:/, '') if (doclet.memberof) doclet.memberof = doclet.memberof.replace(/^module:/, '') 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 namespaces = taffy(members.namespaces); 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) { items = helper.find(namespaces, {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(); var firstChar = memberLower.charAt(0); if (firstChar === '.' || firstChar === '~') { memberLower = memberLower.substring(1); } typesJson[memberLower] = typesJson[memberLower] || []; typesJson[memberLower].push(filename + '#' + member); }); } }); fs.writeFileSync(outdir + '/types.txt', JSON.stringify(typesJson), 'utf8'); };
exports.publish = function (taffyData, opts, tutorials) { data = taffyData; const conf = env.conf.templates || {}; conf['default'] = conf['default'] || {}; const 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 const indexUrl = helper.getUniqueFilename('index'); // don't call registerLink() on this one! 'index' is also a valid longname const 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); let sourceFiles = {}; const sourceFilePaths = []; data().each(function (doclet) { doclet.attribs = ''; if (doclet.examples) { doclet.examples = doclet.examples.map(function (example) { let 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 let sourcePath; let resolvedSourcePath; if (doclet.meta) { sourcePath = getPathFromDoclet(doclet); resolvedSourcePath = resolveSourcePath(sourcePath); sourceFiles[sourcePath] = { resolved: resolvedSourcePath, shortened: null }; sourceFilePaths.push(resolvedSourcePath); } }); fs.mkPath(outdir); // copy the template's static files to outdir const fromDir = path.join(templatePath, 'static'); const staticFiles = fs.ls(fromDir, 3); staticFiles.forEach(function (fileName) { const toDir = fs.toDir(fileName.replace(fromDir, outdir)); fs.mkPath(toDir); fs.copyFileSync(fileName, toDir); }); // copy user-specified static files to outdir let staticFilePaths; let staticFileFilter; let staticFileScanner; if (conf['default'].staticFiles) { staticFilePaths = conf['default'].staticFiles.paths || []; staticFileFilter = new(require('jsdoc/lib/jsdoc/src/filter')).Filter(conf['default'].staticFiles); staticFileScanner = new(require('jsdoc/lib/jsdoc/src/scanner')).Scanner(); staticFilePaths.forEach(function (filePath) { const extraStaticFiles = staticFileScanner.scan([filePath], 10, staticFileFilter); extraStaticFiles.forEach(function (fileName) { const sourcePath = fs.statSync(filePath).isDirectory() ? filePath : path.dirname(filePath); const 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) { const url = helper.createLink(doclet); helper.registerLink(doclet.longname, url); // replace the filename with a shortened version of the full path let docletPath; if (doclet.meta) { docletPath = getPathFromDoclet(doclet); docletPath = sourceFiles[docletPath].shortened; if (docletPath) { doclet.meta.filename = docletPath; } } }); data().each(function (doclet) { const 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); } }); // do this after the urls have all been generated data().each(function (doclet) { doclet.ancestors = getAncestorLinks(doclet); if (doclet.kind === 'member') { addSignatureTypes(doclet); } if (doclet.kind === 'constant') { addSignatureTypes(doclet); doclet.kind = 'member'; } }); const 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 const files = find({ kind: 'file' }); generate('Index', [{ 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 const classes = taffy(members.classes); const modules = taffy(members.modules); const namespaces = taffy(members.namespaces); const mixins = taffy(members.mixins); const externals = taffy(members.externals); for (const longname in helper.longnameToUrl) { if (hasOwnProp.call(helper.longnameToUrl, longname)) { const myClasses = helper.find(classes, { longname: longname }); if (myClasses.length) { generate('Class: ' + myClasses[0].name, myClasses, helper.longnameToUrl[longname]); } const myModules = helper.find(modules, { longname: longname }); if (myModules.length) { generate('Module: ' + myModules[0].name, myModules, helper.longnameToUrl[longname]); } const myNamespaces = helper.find(namespaces, { longname: longname }); if (myNamespaces.length) { generate('Namespace: ' + myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname]); } const myMixins = helper.find(mixins, { longname: longname }); if (myMixins.length) { generate('Mixin: ' + myMixins[0].name, myMixins, helper.longnameToUrl[longname]); } const 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) { const tutorialData = { title: title, header: tutorial.title, content: tutorial.parse(), children: tutorial.children, titleApp, versionApp, }; let 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> const tutorialPath = path.join(outdir, filename); 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) ); } // sets the meta.filename property on each doclet 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; } } }); // sets the id property for each doclet 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 (set sign types and attribs) 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'; } }); // inherited members/methods dont show up by default in the file which extends // their parent class. let's rectify that. //console.log(data()); //returns a taffy object with taffy functions data().each(function(doclet) { var docletMembersMethodsObj, parentMembersMethodsObj; // console.log('data().each() --',doclet.kind,':',doclet.longname); if (doclet.kind == 'class' && doclet.augments) { // console.log('>>> CLASS:', doclet.name); // console.log('>> AUGMENTS:', doclet.augments); docletMembersMethodsObj = getMembersMethodsObj(doclet); // console.log('>>> docletMembersMethodsObj', docletMembersMethodsObj); doclet.augments.forEach(function(aug) { // console.log('checking:', aug); // console.log('>>>>> parent Class', aug); parentMembersMethodsObj = getMembersMethodsObj(find({ kind: 'class', longname: aug })[0]); // console.log('>>>>>>> parentMembersMethodsObj', parentMembersMethodsObj); // find overridden members/methods and update the db // console.log(' flagOverrides for methods'); flagOverrides(docletMembersMethodsObj.methods, parentMembersMethodsObj.methods); // console.log(' flagOverrides for members'); flagOverrides(docletMembersMethodsObj.members, parentMembersMethodsObj.members); // find inherited members/methods and update the db // addInherited(docletMembersMethodsObj.members, parentMembersMethodsObj.members, doclet.longname); // addInherited(docletMembersMethodsObj.methods, parentMembersMethodsObj.methods, doclet.longname); }); } }); // end inheritance enhancement 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; // custom view.taffyResultsToObj = taffyResultsToObj; view.killQuotes = killQuotes; // view.findInherited = findInherited; // view.findOverrides = findOverrides; // 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 /** * These vars returns an object: * { [Function] * insert: [Function], * merge: [Function], * TAFFY: true, * sort: [Function], * settings: [Function], * store: [Function] } */ 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]); } 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 templatePath = opts.template; view = new template.Template(templatePath + '/tmpl'); // set up templating view.layout = 'layout.tmpl'; // set up tutorials for helper helper.setTutorials(tutorials); data = helper.prune(data); data.sort('longname, version, since'); 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); }); } }); // 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); }); data().each(function(doclet) { var url = helper.createLink(doclet); helper.registerLink(doclet.longname, url); }); 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 (doclet.kind === 'function' || doclet.kind === 'class') { addSignatureParams(doclet); addSignatureReturns(doclet); addAttribs(doclet); } }); // do this after the urls have all been generated data().each(function(doclet) { doclet.ancestors = getAncestorLinks(doclet); doclet.signature = ''; 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.tutoriallink = tutoriallink; view.htmlsafe = htmlsafe; // once for all view.nav = buildNav(members); for (var longname in helper.longnameToUrl) { if ( hasOwnProp.call(helper.longnameToUrl, longname) ) { // reuse 'members', which speeds things up a bit var classes = taffy(members.classes); classes = helper.find(classes, {longname: longname}); if (classes.length) { generate('Class: ' + classes[0].longname, classes, helper.longnameToUrl[longname]); } var modules = taffy(members.modules); modules = helper.find(modules, {longname: longname}); if (modules.length) { generate('Module: ' + modules[0].longname, modules, helper.longnameToUrl[longname]); } var namespaces = taffy(members.namespaces); namespaces = helper.find(namespaces, {longname: longname}); if (namespaces.length) { generate('Namespace: ' + namespaces[0].longname, namespaces, helper.longnameToUrl[longname]); } var mixins = taffy(members.mixins); mixins = helper.find(mixins, {longname: longname}); if (mixins.length) { generate('Mixin: ' + mixins[0].longname, mixins, helper.longnameToUrl[longname]); } var externals = taffy(members.externals); externals = helper.find(externals, {longname: longname}); if (externals.length) { generate('External: ' + externals[0].longname, externals, helper.longnameToUrl[longname]); } } } if (members.globals.length) { generate('Global', members.globals, 'global.html'); } // 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), 'index.html'); // 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', ""); // set up templating view.layout = 'layout.tmpl'; //cleanup data data = helper.prune(data); data.sort('longname, version, since'); var sourceFiles = {}; var sourceFilePaths = []; //create lists of source files and paths readSourceFilesAndPaths(sourceFiles,sourceFilePaths); //find namespaces var namespaces = []; var hasNameSpace = ( find({kind: 'namespace'}) || [] ); for( var ns in hasNameSpace) { var longdirname = hasNameSpace[ns].longname.replace(".","/"); namespaces.push(longdirname); } //find components var components = []; var hasComponents = ( find({component:{isUndefined: false}}) || [] ); for(var hc in hasComponents) { components.push(hasComponents[hc].component); } //create folder structure createFolderStructure(outdir,namespaces, components ); //copy static files copyStaticFiles(templatePath); //shorten pathes shortenSourceFilePaths(sourceFilePaths, sourceFiles); //add signatures data().each(function(doclet) { var url = helper.longnameToUrl[doclet.longname]; if (url.indexOf('#') > -1) { doclet.id = url.split(/#/).pop(); } else { doclet.id = doclet.name; } if ( needsSignature(doclet) ) { addSignatureParams(doclet); addSignatureReturns(doclet, doclet.kind != 'function'); 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'; } }); //get data of member var typeLists = getLists(); // add template helpers view.find = find; view.linkto = linkto; view.linkFromTo = linkFromTo; view.linkFromContextTo = linkFromContextTo; view.resolveAuthorLinks = resolveAuthorLinks; view.htmlsafe = htmlsafe; view.context = null; view.typeLists = typeLists; view.disassemble = disassemble; var componentMap = {}; //inheritance hierarchy //generate X3D Nodes var x3dNodes = helper.find(taffy(typeLists.x3dNodes)); for(var n in x3dNodes) { var node = x3dNodes[n]; if(node.augments) { var parent = helper.find(taffy(typeLists.x3dNodes) , {longname:node.augments} )[0]; if( parent) { if(!parent.childNodes) parent.childNodes = []; parent.childNodes.push(node); node.parentNode = parent; } } } for (var longname in helper.longnameToUrl) { if ( hasOwnProp.call(helper.longnameToUrl, longname) ) { //generate classes var myClasses = helper.find(taffy(typeLists.classes), {longname: longname}); if (myClasses.length) { view.api = "developer"; generateClass('Class: ' + myClasses[0].name, myClasses, createDeveloperlApiPathWithFolders("developer."+helper.longnameToUrl[longname], false, true)); } //generate X3D Nodes var x3dNodes = helper.find(taffy(typeLists.x3dNodes), {longname: longname}); if (x3dNodes.length) { if(typeof componentMap[x3dNodes[0].component] === 'undefined') { componentMap[x3dNodes[0].component]= []; } componentMap[x3dNodes[0].component].push(x3dNodes[0]); //console.log(x3dNodes[0].name+ " " +x3dNodes[0].x3d + " " + x3dNodes[0].component); view.api = "author"; generateX3DNode('Node: ' + x3dNodes[0].name, x3dNodes, createSceneAuthorApiPathWithFolders( x3dNodes[0],helper.longnameToUrl[longname])); if(xndf) { generateXNDF(x3dNodes[0].name, x3dNodes[0]); } } //generate namespace overviews var namespaces = helper.find(taffy(typeLists.namespaces), {longname: longname}); if (namespaces.length) { var classes = helper.find(taffy(typeLists.classes), { memberof: longname}); view.api = "developer"; //if(helper.longnameToUrl[longname].indexOf("global") != 0 ) generateNameSpace('Namespace: ' + namespaces[0].name, namespaces, classes, createDeveloperlApiPathWithFolders("developer."+helper.longnameToUrl[longname],true,true)); } } } view.api = "developer"; generateIndex("Classes", typeLists.classes, false, "developer/classes.html",true); generateIndex("Namespaces", typeLists.namespaces, true, "developer/namespaces.html",true); view.api = "author"; generateComponents(componentMap); generateIndex("Nodes",typeLists.x3dNodes,false,"author/nodes.html",true); };
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', [{kind: 'mainpage', readme: opts.readme, longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page'}], 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); };
function addSignatureParams(f) { var params = taffy(f.params || []); f.signature = util.format('%s(%s)', (f.signature || ''), params().select('name').join(', ')); }
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 = 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) { var desc; if(!doclet.summary && (desc = (doclet.description || doclet.classdesc))) { // Try to split when a "." or a ".</htmlTag>" is found. /* ^ - start of string \s* - optional leading space <tagName> - optional tag, whose tagName is captured in m[1] and \1 \s* - optional white space (.|\n|\r)+?\. - summary text, that can cross lines, and ends in a period; captured in m[2] \s* - optional white space ( $ - the end of the string, or \r|\n - line-break, or </tagName> - the closing tag from the corresponding to the beginning opening tag ) */ var m = (/^\s*(?:<(\w+)>)?\s*((?:.|\n|\r)+?\.)\s*?($|(\r|\n)|(<\/\1>))/i).exec(desc); if(m) { // MATCHED! var tagName = m[1]; var summary = m[2]; if(tagName) summary = "<" + tagName + ">" + summary + "</" + tagName + ">"; doclet.summary = summary; //console.log("summary: " + summary); //console.log(" description: " + desc); //console.log(" "); } else { console.warn("Could not determine summary for: " + desc); } } 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; //console.log(env) 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 = ''; 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); } } }); 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; // generate the pretty-printed source files first so other pages can link to them if (outputSourceFiles) { registerSourceFiles(sourceFiles, opts.encoding); } // once for all 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' }); var packages = find({ kind: 'package' }); // 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]); } 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('./', filename); var markdown = view.render('tutorial.tmpl', tutorialData); markdown = markdown.replace(/\n+/g, '\n'); // yes, you can use {@link} in tutorials too! markdown = helper.resolveLinks(markdown); // turn {@link foo} into <a href="foodoc.html">foo</a> fs.writeFileSync(tutorialPath, markdown, '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); };
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// /** * Run the jsdoc application. * @todo Refactor function (and require statements) into smaller functions */ function main() { var _ = require('underscore'); var args = require('jsdoc/opts/args'); var augment = require('jsdoc/augment'); var borrow = require('jsdoc/borrow'); var Config = require('jsdoc/config'); var Filter = require('jsdoc/src/filter').Filter; var fs = require('jsdoc/fs'); var handlers = require('jsdoc/src/handlers'); var include = require('jsdoc/util/include'); var Package = require('jsdoc/package').Package; var path = require('jsdoc/path'); var plugins = require('jsdoc/plugins'); var Readme = require('jsdoc/readme'); var resolver = require('jsdoc/tutorial/resolver'); var taffy = require('taffydb').taffy; var vm = require('jsdoc/util/vm'); var defaultOpts; var docs; var exampleConf; var filter; var i; var info; var l; var packageDocs; var packageJson; var sourceFiles; var template; defaultOpts = { destination: './out/', encoding: 'utf8' }; // get JSDoc version number info = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8')); env.version = { number: info.version, revision: new Date(parseInt(info.revision, 10)).toUTCString() }; env.opts = args.parse(env.args); try { env.conf = new Config( fs.readFileSync( env.opts.configure || path.join(__dirname, 'conf.json'), 'utf8' ) ).get(); } catch (e) { try { // Use the example file if possible exampleConf = fs.readFileSync(path.join(__dirname, 'conf.json.EXAMPLE'), 'utf8'); env.conf = JSON.parse(exampleConf); } catch(e) { throw('Configuration file cannot be evaluated. ' + e); } } // look for options on the command line, in the config file, and in the defaults, in that order env.opts = _.defaults(env.opts, env.conf.opts, defaultOpts); // which version of javascript will be supported? (rhino only) if (typeof version === 'function') { version(env.conf.jsVersion || 180); } if (env.opts.help) { console.log( args.help() ); process.exit(0); } else if (env.opts.test) { include('test/runner.js'); process.exit(0); } else if (env.opts.version) { console.log('JSDoc ' + env.version.number + ' (' + env.version.revision + ')'); process.exit(0); } if (env.conf.plugins) { plugins.installPlugins(env.conf.plugins, app.jsdoc.parser); } if (env.conf.source && env.conf.source.include) { env.opts._ = (env.opts._ || []).concat(env.conf.source.include); } // any source file named package.json or README.md is treated special for (i = 0, l = env.opts._.length; i < l; i++ ) { if (/\bpackage\.json$/i.test(env.opts._[i])) { packageJson = fs.readFileSync( env.opts._[i], 'utf8' ); env.opts._.splice(i--, 1); } if (/(\bREADME|\.md)$/i.test(env.opts._[i])) { env.opts.readme = new Readme(env.opts._[i]).html; env.opts._.splice(i--, 1); } } if (env.conf.source && env.opts._.length > 0) { // are there any files to scan and parse? filter = new Filter(env.conf.source); sourceFiles = app.jsdoc.scanner.scan(env.opts._, (env.opts.recurse? 10 : undefined), filter); handlers.attachTo(app.jsdoc.parser); docs = app.jsdoc.parser.parse(sourceFiles, env.opts.encoding); //The files are ALWAYS useful for the templates to have //If there is no package.json, just create an empty package packageDocs = new Package(packageJson); packageDocs.files = sourceFiles || []; docs.push(packageDocs); borrow.indexAll(docs); augment.addInherited(docs); borrow.resolveBorrows(docs); if (env.opts.explain) { console.log(docs); process.exit(0); } if (env.opts.tutorials) { resolver.load(env.opts.tutorials); resolver.resolve(); } env.opts.template = (function() { var publish = env.opts.template || 'templates/default'; // if we don't find it, keep the user-specified value so the error message is useful return path.getResourcePath(publish) || env.opts.template; })(); try { template = require(env.opts.template + '/publish'); } catch(e) { throw new Error('Unable to load template: ' + e.message || e); } // templates should include a publish.js file that exports a "publish" function if (template.publish && typeof template.publish === 'function') { // convert this from a URI back to a path if necessary env.opts.template = path._uriToPath(env.opts.template); template.publish( taffy(docs), env.opts, resolver.root ); } else { // old templates define a global "publish" function, which is deprecated include(env.opts.template + '/publish.js'); if (publish && typeof publish === 'function') { console.log( env.opts.template + ' uses a global "publish" function, which is ' + 'deprecated and may not be supported in future versions. ' + 'Please update the template to use "exports.publish" instead.' ); // convert this from a URI back to a path if necessary env.opts.template = path._uriToPath(env.opts.template); publish( taffy(docs), env.opts, resolver.root ); } else { throw new Error( env.opts.template + ' does not export a "publish" function.' ); } } } }
exports.publish = function(taffyData, opts, tutorials) { data = taffyData; 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 // 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); var sortOption = navOptions.sort === undefined ? opts.sort : navOptions.sort; sortOption = sortOption === undefined ? true : sortOption; sortOption = sortOption === true ? 'longname, version, since' : sortOption; if (sortOption) { data.sort(sortOption); } 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, lang; // allow using a markdown parser on the examples captions (surrounded by useless HTML p tags) if (example.match(/^\s*(<p>)?<caption>([\s\S]+?)<\/caption>(\s*)([\s\S]+?)(<\/p>)?$/i)) { caption = RegExp.$2; example = RegExp.$4 + (RegExp.$1 ? '' : RegExp.$5); } var lang = /{@lang (.*?)}/.exec(example); if (lang && lang[1]) { example = example.replace(lang[0], ""); lang = lang[1]; } else { lang = null; } return { caption: caption || '', code: example, lang: lang || "javascript" }; }); } 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 }; //Check to see if the array of source file paths already contains // the source path, if not then add it if (sourceFilePaths.indexOf(sourcePath) === -1) { sourceFilePaths.push(sourcePath) } } }); // update outdir if necessary, then create outdir var packageInfo = (find({ kind: 'package' }) || [])[0]; if (navOptions.disablePackagePath !== true && packageInfo && packageInfo.name) { if (packageInfo.version) { outdir = path.join(outdir, packageInfo.name, packageInfo.version); } else { outdir = path.join(outdir, packageInfo.name); } } 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) { var payload = navOptions.sourceRootPath; if (!payload) { payload = path.commonPrefix(sourceFilePaths); } sourceFiles = shortenPaths(sourceFiles, payload); } 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); if (!_.isEmpty(sourceFiles[docletPath])) { 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; // add template helpers view.find = find; view.linkto = linkto; view.resolveAuthorLinks = resolveAuthorLinks; view.tutoriallink = tutoriallink; view.htmlsafe = htmlsafe; view.moment = moment; // once for all buildNav(members); view.nav = navigationMaster; view.navOptions = navOptions; 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 (navOptions.outputSourceFiles) { generateSourceFiles(sourceFiles); } if (members.globals.length) { generate('global', 'Global', [{ kind: 'globalobj' }], globalUrl); } // some browsers can't make the dropdown work if (view.nav.module && view.nav.module.members.length) { generate('module', view.nav.module.title, [{ kind: 'sectionIndex', contents: view.nav.module }], navigationMaster.module.link); } if (view.nav.class && view.nav.class.members.length) { generate('class', view.nav.class.title, [{ kind: 'sectionIndex', contents: view.nav.class }], navigationMaster.class.link); } if (view.nav.namespace && view.nav.namespace.members.length) { generate('namespace', view.nav.namespace.title, [{ kind: 'sectionIndex', contents: view.nav.namespace }], navigationMaster.namespace.link); } if (view.nav.mixin && view.nav.mixin.members.length) { generate('mixin', view.nav.mixin.title, [{ kind: 'sectionIndex', contents: view.nav.mixin }], navigationMaster.mixin.link); } if (view.nav.interface && view.nav.interface.members.length) { generate('interface', view.nav.interface.title, [{ kind: 'sectionIndex', contents: view.nav.interface }], navigationMaster.interface.link); } if (view.nav.external && view.nav.external.members.length) { generate('external', view.nav.external.title, [{ kind: 'sectionIndex', contents: view.nav.external }], navigationMaster.external.link); } if (view.nav.tutorial && view.nav.tutorial.members.length) { generate('tutorial', view.nav.tutorial.title, [{ kind: 'sectionIndex', contents: view.nav.tutorial }], navigationMaster.tutorial.link); } // index page displays information from package.json and lists files var files = find({ kind: 'file' }), packages = find({ kind: 'package' }); generate('index', '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 interfaces = taffy(members.interfaces); 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', 'Class: ' + myClasses[0].name, myClasses, helper.longnameToUrl[longname]); } var myModules = helper.find(modules, { longname: longname }); if (myModules.length) { generate('module', 'Module: ' + myModules[0].name, myModules, helper.longnameToUrl[longname]); } var myNamespaces = helper.find(namespaces, { longname: longname }); if (myNamespaces.length) { generate('namespace', 'Namespace: ' + myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname]); } var myMixins = helper.find(mixins, { longname: longname }); if (myMixins.length) { generate('mixin', 'Mixin: ' + myMixins[0].name, myMixins, helper.longnameToUrl[longname]); } var myInterfaces = helper.find(interfaces, { longname: longname }); if (myInterfaces.length) { generate('interface', 'Interface: ' + myInterfaces[0].name, myInterfaces, helper.longnameToUrl[longname]); } var myExternals = helper.find(externals, { longname: longname }); if (myExternals.length) { generate('external', '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, docs: null }; 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> searchableDocuments[filename] = { "id": filename, "title": title, "body": searchData(html) }; 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); }); } function generateQuickTextSearch(templatePath, searchableDocuments, navOptions) { var data = { searchableDocuments: JSON.stringify(searchableDocuments), navOptions: navOptions }; var tmplString = fs.readFileSync(templatePath + "/quicksearch.tmpl").toString(), tmpl = _.template(tmplString); var html = tmpl(data), outpath = path.join(outdir, "quicksearch.html"); fs.writeFileSync(outpath, html, "utf8"); } saveChildren(tutorials); generateQuickTextSearch(templatePath + '/tmpl', searchableDocuments, navOptions); };
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'; // set up tutorials for helper helper.setTutorials(tutorials); data = helper.prune(data); data.sort('longname, version, since'); var sourceFiles = {}; var sourceFilePaths = []; processInheritance(); data().each(function (doclet) { if (doclet.name) doclet.name = doclet.name.replace(/']/g, '').replace(/\['/g, ''); if (doclet.longname) doclet.longname = doclet.longname.replace(/']/g, '').replace(/\['/g, ''); 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); // 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); members.functions = helper.find(data, {kind: 'function', includeDoc: true}); var functions = taffy(members.functions); var counter=0; for (var longname in helper.longnameToUrl) { if (hasOwnProp.call(helper.longnameToUrl, longname)) { var myClasses = helper.find(classes, {longname: longname}); if (myClasses.length) { generate(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],undefined, members); } 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 myFunctions = helper.find(functions, {longname: longname, includeDoc: true}); if (myFunctions.length) { var newName = myFunctions[0].memberof +'.'+myFunctions[0].name+'.html'; // newName = newName.replace(/#/ig,''); // newName = newName.replace(/[']/ig,''); // log(myFunctions[0].memberof); generate(myFunctions[0].name, myFunctions, newName); } } } // 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); };
function prune() { return helper.prune( taffy(array) ); }
exports.publish = function ( taffyData, opts, tutorials ) { data = taffyData; 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, lang; if ( example.match( /^\s*<caption>([\s\S]+?)<\/caption>(\s*[\n\r])([\s\S]+)$/i ) ) { caption = RegExp.$1; code = RegExp.$3; } var lang = /{@lang (.*?)}/.exec( example ); if ( lang && lang[1] ) { example = example.replace( lang[0], "" ); lang = lang[1]; } else { lang = null; } return { caption : caption || '', code : code || example, lang : (lang && navOptions.highlightTutorialCode) ? lang : "javascript" }; } ); } 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 }; 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 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 ) { var payload = navOptions.sourceRootPath; if ( !payload ) { payload = path.commonPrefix( sourceFilePaths ); } sourceFiles = shortenPaths( sourceFiles, payload ); } 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 ); if ( !_.isEmpty( sourceFiles[docletPath] ) ) { 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; // add template helpers view.find = find; view.linkto = linkto; view.resolveAuthorLinks = resolveAuthorLinks; view.tutoriallink = tutoriallink; view.htmlsafe = htmlsafe; view.moment = moment; // once for all buildNav( members ); view.nav = navigationMaster; view.navOptions = navOptions; 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 ( navOptions.outputSourceFiles ) { generateSourceFiles( sourceFiles ); } if ( members.globals.length ) { generate( 'global', 'Global', [ {kind : 'globalobj'} ], globalUrl ); } // some browsers can't make the dropdown work if ( view.nav.module && view.nav.module.members.length ) { generate( 'module', view.nav.module.title, [ {kind : 'sectionIndex', contents : view.nav.module} ], navigationMaster.module.link ); } if ( view.nav.class && view.nav.class.members.length ) { generate( 'class', view.nav.class.title, [ {kind : 'sectionIndex', contents : view.nav.class} ], navigationMaster.class.link ); } if ( view.nav.namespace && view.nav.namespace.members.length ) { generate( 'namespace', view.nav.namespace.title, [ {kind : 'sectionIndex', contents : view.nav.namespace} ], navigationMaster.namespace.link ); } if ( view.nav.mixin && view.nav.mixin.members.length ) { generate( 'mixin', view.nav.mixin.title, [ {kind : 'sectionIndex', contents : view.nav.mixin} ], navigationMaster.mixin.link ); } if ( view.nav.external && view.nav.external.members.length ) { generate( 'external', view.nav.external.title, [ {kind : 'sectionIndex', contents : view.nav.external} ], navigationMaster.external.link ); } if ( view.nav.tutorial && view.nav.tutorial.members.length ) { generate( 'tutorial', view.nav.tutorial.title, [ {kind : 'sectionIndex', contents : view.nav.tutorial} ], navigationMaster.tutorial.link ); } // index page displays information from package.json and lists files var files = find( {kind : 'file'} ), packages = find( {kind : 'package'} ); generate( 'index', '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', 'Class: ' + myClasses[0].name, myClasses, helper.longnameToUrl[longname] ); } var myModules = helper.find( modules, {longname : longname} ); if ( myModules.length ) { generate( 'module', 'Module: ' + myModules[0].name, myModules, helper.longnameToUrl[longname] ); } var myNamespaces = helper.find( namespaces, {longname : longname} ); if ( myNamespaces.length ) { generate( 'namespace', 'Namespace: ' + myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname] ); } var myMixins = helper.find( mixins, {longname : longname} ); if ( myMixins.length ) { generate( 'mixin', 'Mixin: ' + myMixins[0].name, myMixins, helper.longnameToUrl[longname] ); } var myExternals = helper.find( externals, {longname : longname} ); if ( myExternals.length ) { generate( 'external', '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, docs : null }; 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'] || {}; 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); };
/** * publish document as HTML. * @param {DocObject[]} values - all doc objects. * @param {AST[]} asts - all ASTs. * @param {ESDocConfig} config - ESDoc config object. */ export default function publish(values, asts, config) { IceCap.debug = !!config.debug; if (!config.includeSource) { for (let value of values) { if (['file', 'testFile'].includes(value.kind) && 'content' in value) { value.content = ''; } } } let dumpPath = path.resolve(config.destination, 'dump.json'); fs.outputFileSync(dumpPath, JSON.stringify(values, null, 2)); let data = taffy(values); let _coverage = null; function log(text) { console.log(text); } function writeHTML(html, fileName) { log(fileName); html = Plugin.onHandleHTML(html, fileName); let filePath = path.resolve(config.destination, fileName); fs.outputFileSync(filePath, html, {encoding: 'utf8'}); } function writeCoverage(coverage, fileName) { _coverage = coverage; let json = JSON.stringify(coverage, null, 2); let filePath = path.resolve(config.destination, fileName); fs.outputFileSync(filePath, json, {encoding: 'utf8'}); } function writeBadge(badge, fileName) { log(fileName); let filePath = path.resolve(config.destination, fileName); fs.outputFileSync(filePath, badge, {encoding: 'utf8'}); } function writeAST(astJSON, fileName) { let filePath = path.resolve(config.destination, fileName); fs.outputFileSync(filePath, astJSON, {encoding: 'utf8'}); } function copy(srcPath, destPath) { log(destPath); fs.copySync(srcPath, path.resolve(config.destination, destPath)); } if (config.coverage) { new CoverageBuilder(data, config).exec(writeCoverage, writeBadge); } new IdentifiersDocBuilder(data, config).exec(writeHTML); new IndexDocBuilder(data, config, _coverage).exec(writeHTML); new ClassDocBuilder(data, config).exec(writeHTML); new SingleDocBuilder(data, config).exec(writeHTML); new FileDocBuilder(data, config).exec(writeHTML); new StaticFileBuilder(data, config).exec(copy); new SearchIndexBuilder(data, config).exec(writeHTML); new ASTDocBuilder(data, asts, config).exec(writeAST); new SourceDocBuilder(data, config, _coverage).exec(writeHTML); new ManualDocBuilder(data, config).exec(writeHTML, copy); // package.json try { const json = fs.readFileSync(config.package, {encoding: 'utf-8'}); let filePath = path.resolve(config.destination, 'package.json'); fs.outputFileSync(filePath, json, {encoding: 'utf8'}); } catch (e) { // ignore } if (config.test) { new TestDocBuilder(data, config).exec(writeHTML); new TestFileDocBuilder(data, config).exec(writeHTML); } if (config.coverage) { console.log('=================================='); console.log(`Coverage: ${_coverage.coverage} (${_coverage.actualCount}/${_coverage.expectCount})`); console.log('=================================='); } if (config.lint) { new LintDocBuilder(data, config).exec(); } };