checking in jsdoc dir so people can generate docs themselves

This commit is contained in:
Eric Rowell
2014-01-12 00:39:08 -08:00
parent 98b282b819
commit 8dd503c7bd
376 changed files with 24397 additions and 2 deletions

View File

@@ -0,0 +1,20 @@
/**
Deep clone a simple object.
@private
*/
var doop = exports.doop = function(o) {
var clone,
prop;
if (o instanceof Object && o.constructor != Function) {
clone = o instanceof Array ? [] : {};
Object.keys(o).forEach(function(prop) {
clone[prop] = (o[prop] instanceof Object) ? doop(o[prop]) : o[prop];
});
return clone;
}
return o;
};

View File

@@ -0,0 +1,94 @@
/**
* Recursively print out all names and values in a data structure.
* @module jsdoc/util/dumper
* @author Michael Mathews <micmath@gmail.com>
* @license Apache License 2.0 - See file 'LICENSE.md' in this project.
*/
var util = require('util');
var seenItems = [];
function seen(object) {
if (seenItems.indexOf(object) !== -1) {
return true;
}
return false;
}
// some objects are unwalkable, like Java native objects
function isUnwalkable(o) {
return (o && typeof o === 'object' && typeof o.constructor === 'undefined');
}
function isFunction(o) {
return (o && typeof o === 'function' || o instanceof Function);
}
function isObject(o) {
return o && o instanceof Object ||
(o && typeof o.constructor !== 'undefined' && o.constructor.name === 'Object');
}
function checkCircularRefs(o, func) {
if ( seen(o) ) {
return '<CircularRef>';
}
else {
seenItems.push(o);
return func.call(this, o);
}
}
function walk(o) {
var result;
if ( isUnwalkable(o) ) {
result = '<Object>';
}
else if ( o === undefined ) {
result = 'undefined';
}
else if ( Array.isArray(o) ) {
result = checkCircularRefs(o, function(arr) {
var newArray = [];
arr.forEach(function(item) {
newArray.push( walk(item) );
});
return newArray;
});
}
else if ( util.isRegExp(o) ) {
result = '<RegExp ' + o + '>';
}
else if ( util.isDate(o) ) {
result = '<Date ' + o.toUTCString() + '>';
}
else if ( isFunction(o) ) {
result = '<Function' + (o.name ? ' ' + o.name : '') + '>';
}
else if ( isObject(o) && o !== null ) {
result = checkCircularRefs(o, function(obj) {
var newObj = {};
Object.keys(obj).forEach(function(key) {
newObj[key] = walk(obj[key]);
});
return newObj;
});
}
// should be safe to JSON.stringify() everything else
else {
result = o;
}
return result;
}
/**
* @param {*} object
*/
exports.dump = function(object) {
return JSON.stringify(walk(object), null, 4);
};

View File

@@ -0,0 +1,32 @@
/*global env: true */
/**
Helper functions for handling errors.
@module jsdoc/util/error
*/
/**
Handle an exception appropriately based on whether lenient mode is enabled:
+ If lenient mode is enabled, log the exception to the console.
+ If lenient mode is not enabled, re-throw the exception.
@param {Error} e - The exception to handle.
@exception {Error} Re-throws the original exception unless lenient mode is enabled.
@memberof module:jsdoc/util/error
*/
exports.handle = function(e) {
var msg;
if (env.opts.lenient) {
msg = e.message || JSON.stringify(e);
// include the error type if it's an Error object
if (e instanceof Error) {
msg = e.name + ': ' + msg;
}
console.log(msg);
}
else {
throw e;
}
};

View File

@@ -0,0 +1,7 @@
/**
* The global object to which functions and properties can be assigned.
* @private
*/
module.exports = (function() {
return this;
}).call(null);

View File

@@ -0,0 +1,19 @@
var path = require('path');
var vm = require('jsdoc/util/vm');
/**
* Read and execute a JavaScript file in global scope.
* @private
* @param {string} filepath The path to the JavaScript file. May contain an absolute path or a
* path relative to env.dirname.
*/
module.exports = function(filepath) {
filepath = path.resolve(__dirname, filepath);
try {
vm.getModule('jsdoc/util/include')(filepath);
}
catch (e) {
console.log('Cannot include ' + filepath + ': ' + e);
}
};

View File

@@ -0,0 +1,112 @@
/*global env: true */
/**
* Provides access to Markdown-related functions.
* @module jsdoc/util/markdown
* @author Michael Mathews <micmath@gmail.com>
* @author Ben Blank <ben.blank@gmail.com>
*/
/**
* Enumeration of Markdown parsers that are available.
* @enum {String}
*/
var parsers = {
/** The "[markdown-js](https://github.com/evilstreak/markdown-js)" (aka "evilstreak") parser. */
evilstreak: "markdown",
/**
* The "GitHub-flavored Markdown" parser.
* @deprecated Replaced by "marked."
*/
gfm: "marked",
/**
* The "[Marked](https://github.com/chjj/marked)" parser.
*/
marked: "marked"
};
/**
* Escape underscores that occur within {@ ... } in order to protect them
* from the markdown parser(s).
* @param {String} source the source text to sanitize.
* @returns {String} `source` where underscores within {@ ... } have been
* protected with a preceding backslash (i.e. \_) -- the markdown parsers
* will strip the backslash and protect the underscore.
*/
function escapeUnderscores(source) {
return source.replace(/\{@[^}\r\n]+\}/g, function (wholeMatch) {
return wholeMatch.replace(/(^|[^\\])_/g, '$1\\_');
});
}
/**
* Retrieve a function that accepts a single parameter containing Markdown source. The function uses
* the specified parser to transform the Markdown source to HTML, then returns the HTML as a string.
*
* @private
* @param {String} parser The name of the selected parser.
* @param {Object} [conf] Configuration for the selected parser, if any.
* @returns {Function} A function that accepts Markdown source, feeds it to the selected parser, and
* returns the resulting HTML.
* @throws {Error} If the name does not correspond to a known parser.
*/
function getParseFunction(parser, conf) {
conf = conf || {};
var parse;
if (parser === parsers.marked) {
parser = require(parser);
parser.setOptions({
gfm: true,
tables: true,
breaks: false,
pedantic: false,
sanitize: true,
smartLists: true,
langPrefix: 'lang-'
});
parse = function(source) {
source = escapeUnderscores(source);
return parser(source)
.replace(/\s+$/, '')
.replace(/&#39;/g, "'");
};
parse._parser = parsers.marked;
return parse;
} else if (parser === parsers.evilstreak) {
parser = require(parser).markdown;
parse = function(source) {
source = escapeUnderscores(source);
// evilstreak parser expects line endings to be \n
source = source.replace(/\r\n|\r/g, '\n');
return parser.toHTML(source, conf.dialect);
};
parse._parser = parsers.evilstreak;
return parse;
} else {
throw new Error("unknown Markdown parser: '" + parser + "'");
}
}
/**
* Retrieve a Markdown parsing function based on the value of the `conf.json` file's
* `env.conf.markdown` property. The parsing function accepts a single parameter containing Markdown
* source. The function uses the parser specified in `conf.json` to transform the Markdown source to
* HTML, then returns the HTML as a string.
* @returns {Function} A function that accepts Markdown source, feeds it to the selected parser, and
* returns the resulting HTML.
* @throws {Error} If the value of `env.conf.markdown.parser` does not correspond to a known parser.
*/
exports.getParser = function() {
var conf = env.conf.markdown;
if (conf && conf.parser) {
return getParseFunction(parsers[conf.parser], conf);
} else if (conf && conf.githubRepoOwner && conf.githubRepoName) {
// use GitHub-friendly parser if GitHub-specific options are present
return getParseFunction(parsers.gfm, conf);
} else {
// evilstreak is the default parser
return getParseFunction(parsers.evilstreak, conf);
}
};

View File

@@ -0,0 +1,711 @@
/*global env: true */
/**
* @module jsdoc/util/templateHelper
*/
var dictionary = require('jsdoc/tag/dictionary');
var util = require('util');
var hasOwnProp = Object.prototype.hasOwnProperty;
var files = {};
// each container gets its own html file
var containers = ['class', 'module', 'external', 'namespace', 'mixin'];
var tutorials;
/** Sets tutorials map.
@param {jsdoc.tutorial.Tutorial} root - Root tutorial node.
*/
exports.setTutorials = function(root) {
tutorials = root;
};
exports.globalName = 'global';
exports.fileExtension = '.html';
exports.scopeToPunc = { 'static': '.', 'inner': '~', 'instance': '#' };
function getNamespace(kind) {
if (dictionary.isNamespace(kind)) {
return kind + ':';
}
return '';
}
function makeFilenameUnique(filename, str) {
var key = filename.toLowerCase();
var nonUnique = true;
// append enough underscores to make the filename unique
while (nonUnique) {
if ( files[key] && hasOwnProp.call(files, key) ) {
filename += '_';
key = filename.toLowerCase();
} else {
nonUnique = false;
}
}
files[key] = str;
return filename;
}
// compute it here just once
var nsprefix = /^(event|module|external):/;
var htmlsafe = exports.htmlsafe = function(str) {
return str.replace(/</g, '&lt;');
};
/**
* Convert a string to a unique filename, including an extension.
*
* Filenames are cached to ensure that they are used only once. For example, if the same string is
* passed in twice, two different filenames will be returned.
*
* Also, filenames are not considered unique if they are capitalized differently but are otherwise
* identical.
* @param {string} str The string to convert.
* @return {string} The filename to use for the string.
*/
var getUniqueFilename = exports.getUniqueFilename = function(str) {
// allow for namespace prefix
var basename = str.replace(nsprefix, '$1-')
// use - instead of ~ to denote 'inner'
.replace(/~/g, '-')
// remove the variation, if any
.replace(/\([\s\S]*\)$/, '');
// if the basename includes characters that we can't use in a filepath, remove everything up to
// and including the last bad character
var regexp = /[^$a-z0-9._\-](?=[$a-z0-9._\-]*$)/i;
var result = regexp.exec(basename);
if (result && result.index) {
basename = basename.substr(result.index + 1);
}
// make sure we don't create hidden files on POSIX systems
basename = basename.replace(/^\./, '');
// and in case we've now stripped the entire basename (uncommon, but possible):
basename = basename.length ? basename : '_';
return makeFilenameUnique(basename, str) + exports.fileExtension;
};
// two-way lookup
var linkMap = {
longnameToUrl: {},
urlToLongname: {}
};
var tutorialLinkMap = {
nameToUrl: {},
urlToName: {}
};
var longnameToUrl = exports.longnameToUrl = linkMap.longnameToUrl;
function parseType(longname) {
var catharsis = require('catharsis');
var err;
try {
return catharsis.parse(longname, {jsdoc: true});
}
catch (e) {
err = new Error('unable to parse ' + longname + ': ' + e.message);
require('jsdoc/util/error').handle(err);
return longname;
}
}
function stringifyType(parsedType, cssClass, linkMap) {
return require('catharsis').stringify(parsedType, {
cssClass: cssClass,
htmlSafe: true,
links: linkMap
});
}
function hasUrlPrefix(text) {
return (/^(http|ftp)s?:\/\//).test(text);
}
/**
* Build an HTML link to the symbol with the specified longname. If the longname is not
* associated with a URL, this method simply returns the link text, if provided, or the longname.
*
* The `longname` parameter can also contain a URL rather than a symbol's longname.
*
* This method supports type applications that can contain one or more types, such as
* `Array.<MyClass>` or `Array.<(MyClass|YourClass)>`. In these examples, the method attempts to
* replace `Array`, `MyClass`, and `YourClass` with links to the appropriate types. The link text
* is ignored for type applications.
*
* @param {string} longname - The longname (or URL) that is the target of the link.
* @param {string=} linkText - The text to display for the link, or `longname` if no text is
* provided.
* @param {Object} options - Options for building the link.
* @param {string=} options.cssClass - The CSS class (or classes) to include in the link's `<a>`
* tag.
* @param {string=} options.fragmentId - The fragment identifier (for example, `name` in
* `foo.html#name`) to append to the link target.
* @param {string=} options.linkMap - The link map in which to look up the longname.
* @param {boolean=} options.monospace - Indicates whether to display the link text in a monospace
* font.
* @return {string} The HTML link, or the link text if the link is not available.
*/
function buildLink(longname, linkText, options) {
var catharsis = require('catharsis');
var classString = options.cssClass ? util.format(' class="%s"', options.cssClass) : '';
var fragmentString = options.fragmentId ? '#' + options.fragmentId : '';
var stripped;
var text;
var url;
var parsedType;
// handle cases like:
// @see <http://example.org>
// @see http://example.org
stripped = longname ? longname.replace(/^<|>$/g, '') : '';
if ( hasUrlPrefix(stripped) ) {
url = stripped;
text = linkText || stripped;
}
// handle complex type expressions that may require multiple links
// (but skip anything that looks like an inline tag)
else if (longname && longname.search(/[<{(]/) !== -1 && /\{\@.+\}/.test(longname) === false) {
parsedType = parseType(longname);
return stringifyType(parsedType, options.cssClass, options.linkMap);
}
else {
url = hasOwnProp.call(options.linkMap, longname) ? options.linkMap[longname] : '';
text = linkText || longname;
}
text = options.monospace ? '<code>' + text + '</code>' : text;
if (!url) {
return text;
}
else {
return util.format('<a href="%s%s"%s>%s</a>', url, fragmentString, classString, text);
}
}
/**
* Retrieve an HTML link to the symbol with the specified longname. If the longname is not
* associated with a URL, this method simply returns the link text, if provided, or the longname.
*
* The `longname` parameter can also contain a URL rather than a symbol's longname.
*
* This method supports type applications that can contain one or more types, such as
* `Array.<MyClass>` or `Array.<(MyClass|YourClass)>`. In these examples, the method attempts to
* replace `Array`, `MyClass`, and `YourClass` with links to the appropriate types. The link text
* is ignored for type applications.
*
* @param {string} longname - The longname (or URL) that is the target of the link.
* @param {string=} linkText - The text to display for the link, or `longname` if no text is
* provided.
* @param {string=} cssClass - The CSS class (or classes) to include in the link's `<a>` tag.
* @param {string=} fragmentId - The fragment identifier (for example, `name` in `foo.html#name`) to
* append to the link target.
* @return {string} The HTML link, or a plain-text string if the link is not available.
*/
var linkto = exports.linkto = function(longname, linkText, cssClass, fragmentId) {
return buildLink(longname, linkText, {
cssClass: cssClass,
fragmentId: fragmentId,
linkMap: longnameToUrl
});
};
function useMonospace(tag, text) {
var cleverLinks;
var monospaceLinks;
var result;
if ( hasUrlPrefix(text) ) {
result = false;
}
else if (tag === 'linkplain') {
result = false;
}
else if (tag === 'linkcode') {
result = true;
}
else {
cleverLinks = env.conf.templates.cleverLinks;
monospaceLinks = env.conf.templates.monospaceLinks;
if (monospaceLinks || cleverLinks) {
result = true;
}
}
return result || false;
}
function splitLinkText(text) {
var linkText;
var target;
var splitIndex;
// if a pipe is not present, we split on the first space
splitIndex = text.indexOf('|');
if (splitIndex === -1) {
splitIndex = text.indexOf(' ');
}
if (splitIndex !== -1) {
linkText = text.substr(splitIndex + 1);
target = text.substr(0, splitIndex);
}
return {
linkText: linkText,
target: target || text
};
}
var tutorialToUrl = exports.tutorialToUrl = function(tutorial) {
var node = tutorials.getByName(tutorial);
// no such tutorial
if (!node) {
require('jsdoc/util/error').handle( new Error('No such tutorial: '+tutorial) );
return;
}
var url;
// define the URL if necessary
if (!hasOwnProp.call(tutorialLinkMap.nameToUrl, node.name)) {
url = 'tutorial-' + getUniqueFilename(node.name);
tutorialLinkMap.nameToUrl[node.name] = url;
tutorialLinkMap.urlToName[url] = node.name;
}
return tutorialLinkMap.nameToUrl[node.name];
};
/**
* Retrieve a link to a tutorial, or the name of the tutorial if the tutorial is missing. If the
* `missingOpts` parameter is supplied, the names of missing tutorials will be prefixed by the
* specified text and wrapped in the specified HTML tag and CSS class.
*
* @todo Deprecate missingOpts once we have a better error-reporting mechanism.
* @param {string} tutorial The name of the tutorial.
* @param {string} content The link text to use.
* @param {object} [missingOpts] Options for displaying the name of a missing tutorial.
* @param {string} missingOpts.classname The CSS class to wrap around the tutorial name.
* @param {string} missingOpts.prefix The prefix to add to the tutorial name.
* @param {string} missingOpts.tag The tag to wrap around the tutorial name.
* @return {string} An HTML link to the tutorial, or the name of the tutorial with the specified
* options.
*/
var toTutorial = exports.toTutorial = function(tutorial, content, missingOpts) {
if (!tutorial) {
require('jsdoc/util/error').handle( new Error('Missing required parameter: tutorial') );
return;
}
var node = tutorials.getByName(tutorial);
// no such tutorial
if (!node) {
missingOpts = missingOpts || {};
var tag = missingOpts.tag;
var classname = missingOpts.classname;
var link = tutorial;
if (missingOpts.prefix) {
link = missingOpts.prefix + link;
}
if (tag) {
link = '<' + tag + (classname ? (' class="' + classname + '">') : '>') + link;
link += '</' + tag + '>';
}
return link;
}
content = content || node.title;
return '<a href="' + tutorialToUrl(tutorial) + '">' + content + '</a>';
};
/** Find symbol {@link ...} and {@tutorial ...} strings in text and turn into html links */
exports.resolveLinks = function(str) {
var replaceInlineTags = require('jsdoc/tag/inline').replaceInlineTags;
function extractLeadingText(string, completeTag) {
var tagIndex = string.indexOf(completeTag);
var leadingText = null;
var leadingTextInfo = /\[(.+?)\]/.exec(string);
// did we find leading text, and if so, does it immediately precede the tag?
if ( leadingTextInfo && leadingTextInfo.index &&
(leadingTextInfo.index + leadingTextInfo[0].length === tagIndex) ) {
string = string.replace(leadingTextInfo[0], '');
leadingText = leadingTextInfo[1];
}
return {
leadingText: leadingText,
string: string
};
}
function processLink(string, tagInfo) {
var leading = extractLeadingText(string, tagInfo.completeTag);
var linkText = leading.leadingText;
var monospace;
var split;
var target;
string = leading.string;
split = splitLinkText(tagInfo.text);
target = split.target;
linkText = linkText || split.linkText;
monospace = useMonospace(tagInfo.tag, tagInfo.text);
return string.replace( tagInfo.completeTag, buildLink(target, linkText, {
linkMap: longnameToUrl,
monospace: monospace
}) );
}
function processTutorial(string, tagInfo) {
var leading = extractLeadingText(string, tagInfo.completeTag);
string = leading.string;
return string.replace( tagInfo.completeTag, toTutorial(tagInfo.text, leading.leadingText) );
}
var replacers = {
link: processLink,
linkcode: processLink,
linkplain: processLink,
tutorial: processTutorial
};
return replaceInlineTags(str, replacers).newString;
};
/** Convert tag text like "Jane Doe <jdoe@example.org>" into a mailto link */
exports.resolveAuthorLinks = function(str) {
var author;
var matches = str.match(/^\s?([\s\S]+)\b\s+<(\S+@\S+)>\s?$/);
if (matches && matches.length === 3) {
author = '<a href="mailto:' + matches[2] + '">' + htmlsafe(matches[1]) + '</a>';
}
else {
author = htmlsafe(str);
}
return author;
};
/**
* Find items in a TaffyDB database that match the specified key-value pairs.
* @param {TAFFY} data The TaffyDB database to search.
* @param {object|function} spec Key-value pairs to match against (for example,
* `{ longname: 'foo' }`), or a function that returns `true` if a value matches or `false` if it
* does not match.
* @return {array<object>} The matching items.
*/
var find = exports.find = function(data, spec) {
return data(spec).get();
};
/**
* Check whether a symbol is a function and is the only symbol exported by a module (as in
* `module.exports = function() {};`).
*
* @private
* @param {module:jsdoc/doclet.Doclet} doclet - The doclet for the symbol.
* @return {boolean} `true` if the symbol is a function and is the only symbol exported by a module;
* otherwise, `false`.
*/
function isModuleFunction(doclet) {
return doclet.longname && doclet.longname === doclet.name &&
doclet.longname.indexOf('module:') === 0 && doclet.kind === 'function';
}
/**
* Retrieve all of the following types of members from a set of doclets:
*
* + Classes
* + Externals
* + Globals
* + Mixins
* + Modules
* + Namespaces
* + Events
* @param {TAFFY} data The TaffyDB database to search.
* @return {object} An object with `classes`, `externals`, `globals`, `mixins`, `modules`,
* `events`, and `namespaces` properties. Each property contains an array of objects.
*/
exports.getMembers = function(data) {
var members = {
classes: find( data, {kind: 'class'} ),
externals: find( data, {kind: 'external'} ),
events: find( data, {kind: 'event'} ),
globals: find(data, {
kind: ['member', 'function', 'constant', 'typedef'],
memberof: { isUndefined: true }
}),
mixins: find( data, {kind: 'mixin'} ),
modules: find( data, {kind: 'module'} ),
namespaces: find( data, {kind: 'namespace'} )
};
// functions that are also modules (as in "module.exports = function() {};") are not globals
members.globals = members.globals.filter(function(doclet) {
if ( isModuleFunction(doclet) ) {
return false;
}
return true;
});
return members;
};
/**
* Retrieve the member attributes for a doclet (for example, `virtual`, `static`, and
* `readonly`).
* @param {object} d The doclet whose attributes will be retrieved.
* @return {array<string>} The member attributes for the doclet.
*/
exports.getAttribs = function(d) {
var attribs = [];
if (d.virtual) {
attribs.push('virtual');
}
if (d.access && d.access !== 'public') {
attribs.push(d.access);
}
if (d.scope && d.scope !== 'instance' && d.scope !== 'global') {
if (d.kind == 'function' || d.kind == 'member' || d.kind == 'constant') {
attribs.push(d.scope);
}
}
if (d.readonly === true) {
if (d.kind == 'member') {
attribs.push('readonly');
}
}
if (d.kind === 'constant') {
attribs.push('constant');
}
return attribs;
};
/**
* Retrieve links to allowed types for the member.
*
* @param {Object} d - The doclet whose types will be retrieved.
* @param {string} [cssClass] - The CSS class to include in the `class` attribute for each link.
* @return {Array.<string>} HTML links to allowed types for the member.
*/
exports.getSignatureTypes = function(d, cssClass) {
var types = [];
if (d.type && d.type.names) {
types = d.type.names;
}
if (types && types.length) {
types = types.map(function(t) {
return linkto(t, htmlsafe(t), cssClass);
});
}
return types;
};
/**
* Retrieve names of the parameters that the member accepts. If a value is provided for `optClass`,
* the names of optional parameters will be wrapped in a `<span>` tag with that class.
* @param {object} d The doclet whose parameter names will be retrieved.
* @param {string} [optClass] The class to assign to the `<span>` tag that is wrapped around the
* names of optional parameters. If a value is not provided, optional parameter names will not be
* wrapped with a `<span>` tag. Must be a legal value for a CSS class name.
* @return {array<string>} An array of parameter names, with or without `<span>` tags wrapping the
* names of optional parameters.
*/
exports.getSignatureParams = function(d, optClass) {
var pnames = [];
if (d.params) {
d.params.forEach(function(p) {
if (p.name && p.name.indexOf('.') === -1) {
if (p.optional && optClass) {
pnames.push('<span class="' + optClass + '">' + p.name + '</span>');
}
else {
pnames.push(p.name);
}
}
});
}
return pnames;
};
/**
* Retrieve links to types that the member can return.
*
* @param {Object} d - The doclet whose types will be retrieved.
* @param {string} [cssClass] - The CSS class to include in the `class` attribute for each link.
* @return {Array.<string>} HTML links to types that the member can return.
*/
exports.getSignatureReturns = function(d, cssClass) {
var returnTypes = [];
if (d.returns) {
d.returns.forEach(function(r) {
if (r.type && r.type.names) {
if (!returnTypes.length) {
returnTypes = r.type.names;
}
}
});
}
if (returnTypes && returnTypes.length) {
returnTypes = returnTypes.map(function(r) {
return linkto(r, htmlsafe(r), cssClass);
});
}
return returnTypes;
};
/**
* Retrieve links to a member's ancestors.
*
* @param {TAFFY} data - The TaffyDB database to search.
* @param {Object} doclet - The doclet whose ancestors will be retrieved.
* @param {string} [cssClass] - The CSS class to include in the `class` attribute for each link.
* @return {Array.<string>} HTML links to a member's ancestors.
*/
exports.getAncestorLinks = function(data, doclet, cssClass) {
var ancestors = [],
doc = doclet.memberof;
while (doc) {
doc = find( data, {longname: doc}, false );
if (doc) { doc = doc[0]; }
if (!doc) { break; }
ancestors.unshift( linkto(doc.longname, (exports.scopeToPunc[doc.scope] || '') + doc.name,
cssClass) );
doc = doc.memberof;
}
if (ancestors.length) {
ancestors[ancestors.length - 1] += (exports.scopeToPunc[doclet.scope] || '');
}
return ancestors;
};
/**
* Iterates through all the doclets in `data`, ensuring that if a method
* @listens to an event, then that event has a 'listeners' array with the
* longname of the listener in it.
*
* @param {TAFFY} data - The TaffyDB database to search.
*/
exports.addEventListeners = function(data) {
// TODO: do this on the *pruned* data
// find all doclets that @listen to something.
var listeners = find(data, function () { return this.listens && this.listens.length; });
if (!listeners.length) {
return;
}
var doc,
l,
_events = {}; // just a cache to prevent me doing so many lookups
listeners.forEach(function (listener) {
l = listener.listens;
l.forEach(function (eventLongname) {
doc = _events[eventLongname] || find(data, {longname: eventLongname, kind: 'event'})[0];
if (doc) {
if (!doc.listeners) {
doc.listeners = [listener.longname];
} else {
doc.listeners.push(listener.longname);
}
_events[eventLongname] = _events[eventLongname] || doc;
}
});
});
};
/**
* Remove members that will not be included in the output, including:
*
* + Undocumented members.
* + Members tagged `@ignore`.
* + Members of anonymous classes.
* + Members tagged `@private`, unless the `private` option is enabled.
* @param {TAFFY} data The TaffyDB database to prune.
* @return {TAFFY} The pruned database.
*/
exports.prune = function(data) {
data({undocumented: true}).remove();
data({ignore: true}).remove();
if (!env.opts.private) { data({access: 'private'}).remove(); }
data({memberof: '<anonymous>'}).remove();
return data;
};
var registerLink = exports.registerLink = function(longname, url) {
linkMap.longnameToUrl[longname] = url;
linkMap.urlToLongname[url] = longname;
};
/**
* Get a longname's filename if one has been registered; otherwise, generate a unique filename, then
* register the filename.
* @private
*/
function getFilename(longname) {
var url;
if ( longnameToUrl[longname] && hasOwnProp.call(longnameToUrl, longname) ) {
url = longnameToUrl[longname];
} else {
url = getUniqueFilename(longname);
registerLink(longname, url);
}
return url;
}
/** Turn a doclet into a URL. */
exports.createLink = function(doclet) {
var url = '';
var longname = doclet.longname;
var filename;
if ( containers.indexOf(doclet.kind) !== -1 || isModuleFunction(doclet) ) {
url = getFilename(longname);
}
else {
filename = getFilename(doclet.memberof || exports.globalName);
url = filename + '#' + getNamespace(doclet.kind) + doclet.name;
}
return url;
};

View File

@@ -0,0 +1,83 @@
/*global Packages: true */
/**
* Helper functions to enable JSDoc to run on multiple JavaScript virtual machines.
* @module jsdoc/util/vm
*/
var os = require('os');
// These strings represent directory names; do not modify them!
/** @private */
const RHINO = exports.RHINO = 'rhino';
/** @private */
const NODEJS = exports.NODEJS = 'nodejs';
// hacky conversion from Windows path to URI
function pathToUri(filepath) {
var uri = filepath;
// get drive
var drive = uri.match(/^[A-Za-z]/)[0] || '';
// strip drive/colon (if present; UNC paths won't have either)
uri = uri.replace(/^:?([A-Za-z]\:)?/, '');
// replace spaces with %20
uri = uri.replace(/\s/g, '%20');
// prepend drive (if present)
if (drive) {
uri = drive + ':' + uri;
}
// prepend URI scheme
uri = 'file:/' + uri;
return uri;
}
/**
* The JavaScript VM that is executing JSDoc:
*
* + `module:jsdoc/util/vm.RHINO`: Mozilla Rhino.
* + `module:jsdoc/util/vm.NODEJS`: Node.js (not currently supported).
*/
var vm = exports.vm = (function() {
if (Packages && typeof Packages === 'object' &&
Object.prototype.toString.call(Packages) === '[object JavaPackage]') {
return RHINO;
} else if ( require && require.main && module && (require.main === module) ) {
return NODEJS;
} else {
// unknown VM
throw new Error('Unable to identify the current JavaScript VM.');
}
})();
/**
* Load the VM-specific implementation of a module.
*
* @param {string} modulePath - The relative path to the module. Use the same format as when calling
* `require()`.
* @return {object} An object containing VM-specific functions for the requested module.
*/
exports.getModule = function(modulePath) {
modulePath = [__dirname, vm, modulePath].join('/').replace(/ /g, '%20');
if (os.platform() === 'win32') {
modulePath = pathToUri(modulePath);
}
return require(modulePath);
};
/**
* Check whether Mozilla Rhino is running JSDoc.
* @return {boolean} Set to `true` if the current VM is Mozilla Rhino.
*/
exports.isRhino = function() {
return vm === RHINO;
};
/**
* Check whether Node.js is running JSDoc. (Node.js is not currently supported.)
* @return {boolean} Set to `true` if the current VM is Node.js.
*/
exports.isNodejs = function() {
return vm === NODEJS;
};