mirror of
https://github.com/WhitestormJS/whs.js.git
synced 2026-01-18 16:03:24 +00:00
924 lines
25 KiB
JavaScript
924 lines
25 KiB
JavaScript
/*global env: true */
|
|
"use strict"
|
|
|
|
var doop = require("jsdoc/util/doop")
|
|
var fs = require("jsdoc/fs")
|
|
var helper = require("jsdoc/util/templateHelper")
|
|
var logger = require("jsdoc/util/logger")
|
|
var path = require("jsdoc/path")
|
|
var env = require("jsdoc/env")
|
|
var readme = require("jsdoc/readme");
|
|
var taffy = require("taffydb").taffy
|
|
var template = require("jsdoc/template")
|
|
var util = require("util")
|
|
var mdurl = require("mdurl")
|
|
var yaml = require("js-yaml");
|
|
var _path = require("path");
|
|
|
|
var config = yaml.safeLoad(fs.readFileSync(_path.resolve(__dirname, '../data/data.yml'), 'utf8'));
|
|
|
|
var htmlsafe = helper.htmlsafe
|
|
|
|
var linkto = function(longname, linkText, cssClass, fragmentId) {
|
|
let result = helper.linkto(longname, linkText, cssClass, fragmentId);
|
|
|
|
// while (result.indexOf('%') > 0) {
|
|
// result = mdurl.decode(result);
|
|
// }
|
|
|
|
return result; // Fix whitespace bug.
|
|
}
|
|
|
|
var resolveAuthorLinks = helper.resolveAuthorLinks
|
|
var scopeToPunc = helper.scopeToPunc
|
|
var hasOwnProp = Object.prototype.hasOwnProperty
|
|
|
|
var data
|
|
var view
|
|
|
|
var outdir = path.normalize(env.opts.destination)
|
|
|
|
function find(spec) {
|
|
return helper.find(data, spec)
|
|
}
|
|
|
|
function tutoriallink(tutorial) {
|
|
return helper.toTutorial(tutorial, null, {
|
|
tag: "em",
|
|
classname: "disabled",
|
|
prefix: "Tutorial: "
|
|
})
|
|
}
|
|
|
|
function getAncestorLinks(doclet) {
|
|
return helper.getAncestorLinks(data, doclet)
|
|
}
|
|
|
|
function hashToLink(doclet, hash) {
|
|
if (!/^(#.+)/.test(hash)) {
|
|
return hash
|
|
}
|
|
|
|
var url = helper.createLink(doclet)
|
|
|
|
url = url.replace(/(#.+|$)/, hash)
|
|
return '<a href="' + url + '">' + hash + "</a>"
|
|
}
|
|
|
|
function needsSignature(doclet) {
|
|
var needsSig = false
|
|
|
|
// function and class definitions always get a signature
|
|
if (doclet.kind === "function" || doclet.kind === "class") {
|
|
needsSig = true
|
|
} else if (
|
|
doclet.kind === "typedef" &&
|
|
doclet.type &&
|
|
doclet.type.names &&
|
|
doclet.type.names.length
|
|
) {
|
|
// typedefs that contain functions get a signature, too
|
|
for (var i = 0, l = doclet.type.names.length; i < l; i++) {
|
|
if (doclet.type.names[i].toLowerCase() === "function") {
|
|
needsSig = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
return needsSig
|
|
}
|
|
|
|
function getSignatureAttributes(item) {
|
|
var attributes = []
|
|
|
|
if (item.optional) {
|
|
attributes.push("opt")
|
|
}
|
|
|
|
if (item.nullable === true) {
|
|
attributes.push("nullable")
|
|
} else if (item.nullable === false) {
|
|
attributes.push("non-null")
|
|
}
|
|
|
|
return attributes
|
|
}
|
|
|
|
function updateItemName(item) {
|
|
var attributes = getSignatureAttributes(item)
|
|
var itemName = item.name || ""
|
|
|
|
if (item.variable) {
|
|
itemName = "…" + itemName
|
|
}
|
|
|
|
if (attributes && attributes.length) {
|
|
itemName = util.format(
|
|
'%s<span class="signature-attributes">%s</span>',
|
|
itemName,
|
|
attributes.join(", ")
|
|
)
|
|
}
|
|
|
|
return itemName
|
|
}
|
|
|
|
function addParamAttributes(params) {
|
|
return params
|
|
.filter(function(param) {
|
|
return param.name && param.name.indexOf(".") === -1
|
|
})
|
|
.map(updateItemName)
|
|
}
|
|
|
|
function buildItemTypeStrings(item) {
|
|
var types = []
|
|
|
|
if (item && item.type && item.type.names) {
|
|
item.type.names.forEach(function(name) {
|
|
types.push(linkto(name, htmlsafe(name)))
|
|
})
|
|
}
|
|
|
|
return types
|
|
}
|
|
|
|
function buildAttribsString(attribs) {
|
|
var attribsString = ""
|
|
|
|
if (attribs && attribs.length) {
|
|
attribsString = htmlsafe(util.format("(%s) ", attribs.join(", ")))
|
|
}
|
|
|
|
return attribsString
|
|
}
|
|
|
|
function addNonParamAttributes(items) {
|
|
var types = []
|
|
|
|
items.forEach(function(item) {
|
|
types = types.concat(buildItemTypeStrings(item))
|
|
})
|
|
|
|
return types
|
|
}
|
|
|
|
function addSignatureParams(f) {
|
|
var params = f.params ? addParamAttributes(f.params) : []
|
|
f.signature = util.format("%s(%s)", f.signature || "", params.join(", "))
|
|
}
|
|
|
|
function addSignatureReturns(f) {
|
|
var attribs = []
|
|
var attribsString = ""
|
|
var returnTypes = []
|
|
var returnTypesString = ""
|
|
|
|
// jam all the return-type attributes into an array. this could create odd results (for example,
|
|
// if there are both nullable and non-nullable return types), but let's assume that most people
|
|
// who use multiple @return tags aren't using Closure Compiler type annotations, and vice-versa.
|
|
if (f.returns) {
|
|
f.returns.forEach(function(item) {
|
|
helper.getAttribs(item).forEach(function(attrib) {
|
|
if (attribs.indexOf(attrib) === -1) {
|
|
attribs.push(attrib)
|
|
}
|
|
})
|
|
})
|
|
|
|
attribsString = buildAttribsString(attribs)
|
|
}
|
|
|
|
if (f.returns) {
|
|
returnTypes = addNonParamAttributes(f.returns)
|
|
}
|
|
if (returnTypes.length) {
|
|
returnTypesString = util.format(
|
|
" → %s{%s}",
|
|
attribsString,
|
|
returnTypes.join("|")
|
|
)
|
|
}
|
|
|
|
f.signature =
|
|
'<span class="signature">' +
|
|
(f.signature || "") +
|
|
"</span>" +
|
|
'<span class="type-signature">' +
|
|
returnTypesString +
|
|
"</span>"
|
|
}
|
|
|
|
function addSignatureTypes(f) {
|
|
var types = f.type ? buildItemTypeStrings(f) : []
|
|
|
|
f.signature =
|
|
(f.signature || "") +
|
|
'<span class="type-signature">' +
|
|
(types.length ? " :" + types.join("|") : "") +
|
|
"</span>"
|
|
}
|
|
|
|
function addAttribs(f) {
|
|
var attribs = helper.getAttribs(f)
|
|
var attribsString = buildAttribsString(attribs)
|
|
|
|
f.attribs = util.format(
|
|
'<span class="type-signature">%s</span>',
|
|
attribsString
|
|
)
|
|
}
|
|
|
|
function shortenPaths(files, commonPrefix) {
|
|
Object.keys(files).forEach(function(file) {
|
|
files[file].shortened = files[file].resolved
|
|
.replace(commonPrefix, "")
|
|
// always use forward slashes
|
|
.replace(/\\/g, "/")
|
|
})
|
|
|
|
return files
|
|
}
|
|
|
|
function getPathFromDoclet(doclet) {
|
|
if (!doclet.meta) {
|
|
return null
|
|
}
|
|
|
|
return doclet.meta.path && doclet.meta.path !== "null"
|
|
? path.join(doclet.meta.path, doclet.meta.filename)
|
|
: doclet.meta.filename
|
|
}
|
|
|
|
function generate(type, title, docs, filename, resolveLinks, headtitle) {
|
|
resolveLinks = resolveLinks === false ? false : true
|
|
|
|
var docData = {
|
|
type: type,
|
|
headtitle: headtitle || null,
|
|
title: title,
|
|
docs: docs
|
|
}
|
|
|
|
var outpath = path.join(outdir, filename),
|
|
html = view.render("container.tmpl", docData)
|
|
|
|
if (resolveLinks) {
|
|
html = helper.resolveLinks(html) // turn {@link foo} into <a href="foodoc.html">foo</a>
|
|
}
|
|
|
|
fs.writeFileSync(outpath, html, "utf8")
|
|
}
|
|
|
|
function generateSourceFiles(sourceFiles, encoding) {
|
|
encoding = encoding || "utf8"
|
|
Object.keys(sourceFiles).forEach(function(file) {
|
|
var source
|
|
var repo = 'https://github.com/WhitestormJS/whitestorm.js/blob/dev/';
|
|
// links are keyed to the shortened path in each doclet's `meta.shortpath` property
|
|
|
|
var res = sourceFiles[file].resolved;
|
|
var path = res.substring(res.indexOf('src'), res.length);
|
|
|
|
var sourceOutfile = repo + path // helper.getUniqueFilename(sourceFiles[file].shortened)
|
|
|
|
helper.registerLink(sourceFiles[file].shortened, sourceOutfile)
|
|
|
|
try {
|
|
source = {
|
|
kind: "source",
|
|
code: helper.htmlsafe(
|
|
fs.readFileSync(sourceFiles[file].resolved, encoding)
|
|
)
|
|
}
|
|
} catch (e) {
|
|
logger.error("Error while generating source file %s: %s", file, e.message)
|
|
}
|
|
|
|
// generate(
|
|
// "Source",
|
|
// sourceFiles[file].shortened,
|
|
// [source],
|
|
// helper.getUniqueFilename(sourceFiles[file].shortened),
|
|
// false
|
|
// )
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Look for classes or functions with the same name as modules (which indicates that the module
|
|
* exports only that class or function), then attach the classes or functions to the `module`
|
|
* property of the appropriate module doclets. The name of each class or function is also updated
|
|
* for display purposes. This function mutates the original arrays.
|
|
*
|
|
* @private
|
|
* @param {Array.<module:jsdoc/doclet.Doclet>} doclets - The array of classes and functions to
|
|
* check.
|
|
* @param {Array.<module:jsdoc/doclet.Doclet>} modules - The array of module doclets to search.
|
|
*/
|
|
function attachModuleSymbols(doclets, modules) {
|
|
var symbols = {}
|
|
|
|
// build a lookup table
|
|
doclets.forEach(function(symbol) {
|
|
symbols[symbol.longname] = symbols[symbol.longname] || []
|
|
symbols[symbol.longname].push(symbol)
|
|
})
|
|
|
|
return modules.map(function(module) {
|
|
if (symbols[module.longname]) {
|
|
module.modules = symbols[module.longname]
|
|
// Only show symbols that have a description. Make an exception for classes, because
|
|
// we want to show the constructor-signature heading no matter what.
|
|
.filter(function(symbol) {
|
|
return symbol.description || symbol.kind === "class"
|
|
})
|
|
.map(function(symbol) {
|
|
symbol = doop(symbol)
|
|
|
|
if (symbol.kind === "class" || symbol.kind === "function") {
|
|
symbol.name = symbol.name.replace("module:", '(require("') + '"))'
|
|
}
|
|
|
|
return symbol
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Create the navigation sidebar.
|
|
* @param {object} members The members that will be used to create the sidebar.
|
|
* @param {array<object>} members.classes
|
|
* @param {array<object>} members.externals
|
|
* @param {array<object>} members.globals
|
|
* @param {array<object>} members.mixins
|
|
* @param {array<object>} members.modules
|
|
* @param {array<object>} members.namespaces
|
|
* @param {array<object>} members.tutorials
|
|
* @param {array<object>} members.events
|
|
* @param {array<object>} members.interfaces
|
|
* @return {array} The HTML for the navigation sidebar.
|
|
*/
|
|
function buildNav(members) {
|
|
var nav = []
|
|
var seen = {}
|
|
var seenTutorials = {}
|
|
|
|
if (members.titles.length > 0) nav.push('<li class="nav-heading">Pages</li>');
|
|
|
|
members.titles.forEach(name => {
|
|
nav.push(buildNavLink(name, '<a href="' + (name === config.markdown.default ? 'index' : name) + '.html">' + name + '</a>'))
|
|
});
|
|
// nav.push(buildNavLink('examples', '<a href="examples.html">examples</a>'))
|
|
|
|
nav = nav.concat(buildMemberNav(members.tutorials, "Tutorials", seenTutorials, linktoTutorial))
|
|
nav = nav.concat(buildMemberNav(members.classes, "Classes", seen, linkto))
|
|
// nav = nav.concat(buildMemberNav(members.modules, "Modules", {}, linkto))
|
|
nav = nav.concat(buildMemberNav(members.externals, "Externals", seen, linktoExternal))
|
|
nav = nav.concat(buildMemberNav(members.events, "Events", seen, linkto))
|
|
nav = nav.concat(buildMemberNav(members.namespaces, "Namespaces", seen, linkto))
|
|
nav = nav.concat(buildMemberNav(members.mixins, "Mixins", seen, linkto))
|
|
nav = nav.concat(buildMemberNav(members.interfaces, "Interfaces", seen, linkto))
|
|
|
|
if (members.globals.length) {
|
|
nav.push(buildNavHeading(linkto('global', 'Globals')))
|
|
|
|
members.globals.forEach(function (item) {
|
|
if (item.kind !== "typedef" && !hasOwnProp.call(seen, item.longname)) {
|
|
nav.push(buildNavItem(buildNavType(item.kind, linkto(item.longname, item.name))))
|
|
}
|
|
|
|
seen[item.longname] = true
|
|
})
|
|
}
|
|
|
|
return nav.join('')
|
|
}
|
|
|
|
function buildMemberNav(items, itemHeading, itemsSeen, linktoFn) {
|
|
var nav = []
|
|
var conf = env.conf.templates || {}
|
|
|
|
conf.default = conf.default || {}
|
|
|
|
if (items && items.length) {
|
|
var itemsNav = ""
|
|
var categories = {none: []};
|
|
var categoryLinks = {};
|
|
var categoriesOrder = config.Classes.order || [];
|
|
|
|
nav.push(buildNavHeading(itemHeading, false, true))
|
|
|
|
items.forEach(function(item) {
|
|
if (itemHeading === "Classes" && item.category) {
|
|
var name = item.category.name;
|
|
|
|
if (!categories[name]) {
|
|
categories[name] = [item];
|
|
categoryLinks[name] = linktoFn(item.memberof, name);
|
|
// console.log(name);
|
|
// console.log(categoriesOrder);
|
|
if (categoriesOrder.indexOf(name) == -1) categoriesOrder.push(name);
|
|
} else categories[name].push(item);
|
|
} else {
|
|
categories.none.push(item);
|
|
}
|
|
});
|
|
|
|
var processItemEach = function(item) {
|
|
var methods = find({ kind: "function", memberof: item.longname })
|
|
var members = find({ kind: "member", memberof: item.longname })
|
|
var displayName
|
|
|
|
if (!hasOwnProp.call(item, "longname")) {
|
|
nav.push(buildNavItem(linkfoFn('', item.name)))
|
|
return
|
|
}
|
|
|
|
if (!hasOwnProp.call(itemsSeen, item.longname)) {
|
|
if (!!conf.default.useLongnameInNav) {
|
|
displayName = item.longname
|
|
|
|
if (conf.default.useLongnameInNav > 0 && conf.default.useLongnameInNav !== true) {
|
|
var num = conf.default.useLongnameInNav
|
|
var cropped = item.longname.split(".").slice(-num).join(".")
|
|
if (cropped !== displayName) {
|
|
displayName = "..." + cropped
|
|
}
|
|
}
|
|
} else {
|
|
displayName = item.name
|
|
}
|
|
|
|
displayName = displayName.replace(/^module:/g, "")
|
|
|
|
if (itemHeading === 'Tutorials') {
|
|
nav.push(buildNavItem(linktoFn(item.longname, displayName)))
|
|
} else {
|
|
nav.push(buildNavHeading(buildNavType(item.kind, linktoFn(item.longname, displayName))))
|
|
}
|
|
|
|
if (methods.length && itemHeading !== "Classes") {
|
|
methods.forEach(function(method) {
|
|
if (method.inherited && conf.showInheritedInNav === false) {
|
|
return
|
|
}
|
|
|
|
nav.push(buildNavItem(buildNavType(method.kind, linkto(method.longname, method.name))))
|
|
})
|
|
}
|
|
|
|
itemsSeen[item.longname] = true
|
|
}
|
|
};
|
|
|
|
categories.none.forEach(processItemEach);
|
|
|
|
categoriesOrder.forEach(function (key) {
|
|
if (!categories[key]) return;
|
|
nav.push(buildNavHeading(categoryLinks[key], true));
|
|
categories[key].forEach(processItemEach);
|
|
});
|
|
}
|
|
|
|
return nav
|
|
}
|
|
|
|
function linktoTutorial(longName, name) {
|
|
return tutoriallink(name)
|
|
}
|
|
|
|
function linktoExternal(longName, name) {
|
|
return linkto(longName, name.replace(/(^"|"$)/g, ""))
|
|
}
|
|
|
|
/**
|
|
* Helper to generate navigation list link wrapper around navigation links for
|
|
* locations.
|
|
*
|
|
* @param {String} linkClass navigation link classname
|
|
* @param {String} linkContent navigation link HTML content
|
|
* @return {String}
|
|
*/
|
|
function buildNavLink (linkClass, linkContent) {
|
|
return [
|
|
'<li class="nav-link nav-' + linkClass + '-link">',
|
|
linkContent,
|
|
'</li>'
|
|
].join('')
|
|
}
|
|
|
|
/**
|
|
* Helper to generate navigation list header wrapper around navigation header content
|
|
* for headings and filenames.
|
|
*
|
|
* @param {String} content navigation header content
|
|
* @return {String}
|
|
*/
|
|
function buildNavHeading (content, pad, margin) {
|
|
return [
|
|
'<li class="nav-heading ' + (pad ? 'pad ' : '') + (margin ? 'margin' : '') + '">',
|
|
content,
|
|
'</li>'
|
|
].join('')
|
|
}
|
|
|
|
/**
|
|
* Helper for generating generic navigation wrapper around content passed for
|
|
* methods, and types.
|
|
*
|
|
* @param {String} itemContent navigation item content
|
|
* @return {String}
|
|
*/
|
|
function buildNavItem (itemContent) {
|
|
return [
|
|
'<li class="nav-item">',
|
|
itemContent,
|
|
'</li>'
|
|
].join('')
|
|
}
|
|
|
|
function buildNavType (type, typeLink) {
|
|
return [
|
|
'<span class="nav-item-type type-' + type + '">',
|
|
type[0].toUpperCase(),
|
|
'</span>',
|
|
|
|
'<span class="nav-item-name">',
|
|
typeLink,
|
|
'</span>'
|
|
].join('')
|
|
}
|
|
|
|
/**
|
|
@param {TAFFY} taffyData See <http://taffydb.com/>.
|
|
@param {object} opts
|
|
@param {Tutorial} tutorials
|
|
*/
|
|
exports.publish = function(taffyData, opts, tutorials) {
|
|
data = taffyData
|
|
|
|
var conf = env.conf.templates || {}
|
|
conf.default = conf.default || {}
|
|
|
|
var templatePath = path.normalize(opts.template)
|
|
view = new template.Template(path.join(templatePath, "tmpl"))
|
|
|
|
// claim some special filenames in advance, so the All-Powerful Overseer of Filename Uniqueness
|
|
// doesn't try to hand them out later
|
|
// var indexUrl = helper.getUniqueFilename("index")
|
|
|
|
// don't call registerLink() on this one! 'index' is also a valid longname
|
|
var globalUrl = helper.getUniqueFilename("global")
|
|
helper.registerLink("global", globalUrl)
|
|
|
|
// set up templating
|
|
view.layout = conf.default.layoutFile
|
|
? path.getResourcePath(
|
|
path.dirname(conf.default.layoutFile),
|
|
path.basename(conf.default.layoutFile)
|
|
)
|
|
: "layout.tmpl"
|
|
|
|
// set up tutorials for helper
|
|
helper.setTutorials(tutorials)
|
|
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).map(ancestor => ancestor.replace('</a>.', '</a>/'));
|
|
|
|
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
|
|
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" })
|
|
|
|
var markdowns = env.opts._ ? env.opts._.slice(0).concat(env.conf.source.include) : [];
|
|
|
|
markdowns = markdowns.filter(s => s.indexOf('.md') > 0)
|
|
|
|
members.titles = config.markdown.order ? config.markdown.order : [];
|
|
|
|
markdowns.forEach(path => {
|
|
var name = path.slice(path.lastIndexOf('/') + 1, path.indexOf('.md'));
|
|
if (members.titles.indexOf(name) === -1) members.titles.push(name);
|
|
})
|
|
|
|
view.nav = buildNav(members)
|
|
|
|
markdowns.forEach(path => {
|
|
const data = new readme(path);
|
|
const title = path.slice(path.lastIndexOf('/') + 1, path.indexOf('.md'));
|
|
|
|
generate(
|
|
"Page",
|
|
title,
|
|
packages
|
|
.concat([
|
|
{
|
|
kind: "mainpage",
|
|
readme: data.html,
|
|
longname: title
|
|
}
|
|
])
|
|
.concat(files),
|
|
helper.getUniqueFilename(title === config.markdown.default ? 'index' : title)
|
|
)
|
|
})
|
|
|
|
// 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)
|
|
|
|
var fix = function (sh) {
|
|
return '<span class="sub">'
|
|
+ sh.slice(0, sh.indexOf('/') + 1)
|
|
+ '</span>'
|
|
+ sh.slice(sh.indexOf('/') + 1, sh.length)
|
|
}
|
|
|
|
Object.keys(helper.longnameToUrl).forEach(function(longname) {
|
|
var myModules = helper.find(modules, { longname: longname })
|
|
if (myModules.length) {
|
|
generate(
|
|
"Module",
|
|
fix(myModules[0].name),
|
|
myModules,
|
|
helper.longnameToUrl[longname],
|
|
true,
|
|
myModules[0].name
|
|
)
|
|
}
|
|
|
|
var myClasses = helper.find(classes, { longname: longname })
|
|
if (myClasses.length) {
|
|
generate(
|
|
"Class",
|
|
fix(myClasses[0].name),
|
|
myClasses,
|
|
helper.longnameToUrl[longname],
|
|
true,
|
|
myClasses[0].name
|
|
)
|
|
}
|
|
|
|
var myNamespaces = helper.find(namespaces, { longname: longname })
|
|
if (myNamespaces.length) {
|
|
generate(
|
|
"Namespace",
|
|
fix(myNamespaces[0].name),
|
|
myNamespaces,
|
|
helper.longnameToUrl[longname],
|
|
true,
|
|
myNamespaces[0].name
|
|
)
|
|
}
|
|
|
|
var myMixins = helper.find(mixins, { longname: longname })
|
|
if (myMixins.length) {
|
|
generate(
|
|
"Mixin",
|
|
fix(myMixins[0].name),
|
|
myMixins,
|
|
helper.longnameToUrl[longname],
|
|
true,
|
|
myMixins[0].name
|
|
)
|
|
}
|
|
|
|
var myExternals = helper.find(externals, { longname: longname })
|
|
if (myExternals.length) {
|
|
generate(
|
|
"External",
|
|
fix(myExternals[0].name),
|
|
myExternals,
|
|
helper.longnameToUrl[longname],
|
|
true,
|
|
myExternals[0].name
|
|
)
|
|
}
|
|
|
|
var myInterfaces = helper.find(interfaces, { longname: longname })
|
|
if (myInterfaces.length) {
|
|
generate(
|
|
"Interface",
|
|
fix(myInterfaces[0].name),
|
|
myInterfaces,
|
|
helper.longnameToUrl[longname],
|
|
true,
|
|
myInterfaces[0].name
|
|
)
|
|
}
|
|
})
|
|
|
|
// 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
|
|
}
|
|
|
|
// TODO: .replace(/\s/g, '_')
|
|
var tutorialPath = path.join(outdir, filename)
|
|
var html = view.render("tutorial.tmpl", tutorialData)
|
|
|
|
// yes, you can use {@link} in tutorials too!
|
|
html = helper.resolveLinks(html) // turn {@link foo} into <a href="foodoc.html">foo</a>
|
|
fs.writeFileSync(tutorialPath, html, "utf8")
|
|
}
|
|
|
|
// tutorials can have only one parent so there is no risk for loops
|
|
function saveChildren(node) {
|
|
node.children.forEach(function(child) {
|
|
generateTutorial(
|
|
child.title,
|
|
child,
|
|
helper.tutorialToUrl(child.name)
|
|
)
|
|
saveChildren(child)
|
|
})
|
|
}
|
|
|
|
saveChildren(tutorials)
|
|
}
|