mirror of
https://github.com/jsdoc/jsdoc.git
synced 2025-12-08 19:46:11 +00:00
enable JSHint's "latedef" test
This commit is contained in:
parent
534d82b84a
commit
4524af7a09
@ -4,7 +4,7 @@
|
||||
"eqeqeq": false,
|
||||
"forin": true,
|
||||
"immed": true,
|
||||
"latedef": false,
|
||||
"latedef": true,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"noempty": false,
|
||||
|
||||
46
jsdoc.js
46
jsdoc.js
@ -91,29 +91,6 @@ include.resolve = function(filepath) {
|
||||
return env.dirname + '/' + filepath;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Data that must be shared across the entire application.
|
||||
@namespace
|
||||
*/
|
||||
app = {
|
||||
jsdoc: {
|
||||
scanner: new (require('jsdoc/src/scanner').Scanner)(),
|
||||
parser: new (require('jsdoc/src/parser').Parser)(),
|
||||
name: require('jsdoc/name')
|
||||
}
|
||||
}
|
||||
|
||||
try { main(); }
|
||||
catch(e) {
|
||||
if (e.rhinoException != null) {
|
||||
e.rhinoException.printStackTrace();
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
finally { env.run.finish = new Date(); }
|
||||
|
||||
/** Print string/s out to the console.
|
||||
@param {string} ... String/s to print out to console.
|
||||
*/
|
||||
@ -185,6 +162,19 @@ function indexAll(docs) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Data that must be shared across the entire application.
|
||||
@namespace
|
||||
*/
|
||||
app = {
|
||||
jsdoc: {
|
||||
scanner: new (require('jsdoc/src/scanner').Scanner)(),
|
||||
parser: new (require('jsdoc/src/parser').Parser)(),
|
||||
name: require('jsdoc/name')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
|
||||
|
||||
|
||||
@ -324,3 +314,13 @@ function main() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try { main(); }
|
||||
catch(e) {
|
||||
if (e.rhinoException != null) {
|
||||
e.rhinoException.printStackTrace();
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
finally { env.run.finish = new Date(); }
|
||||
|
||||
@ -5,6 +5,19 @@ exports.readFileSync = function(filename, encoding) {
|
||||
return readFile(filename, encoding);
|
||||
};
|
||||
|
||||
var stat = exports.stat = exports.statSync = function(path, encoding) {
|
||||
var f = new java.io.File(path);
|
||||
return {
|
||||
isFile: function() {
|
||||
return f.isFile();
|
||||
},
|
||||
isDirectory: function() {
|
||||
return f.isDirectory();
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
var readdirSync = exports.readdirSync = function(path) {
|
||||
var dir,
|
||||
files;
|
||||
@ -64,28 +77,17 @@ var ls = exports.ls = function(dir, recurse, _allFiles, _path) {
|
||||
return _allFiles;
|
||||
};
|
||||
|
||||
var stat = exports.stat = exports.statSync = function(path, encoding) {
|
||||
var toDir = exports.toDir = function(path) {
|
||||
var f = new java.io.File(path);
|
||||
return {
|
||||
isFile: function() {
|
||||
return f.isFile();
|
||||
},
|
||||
isDirectory: function() {
|
||||
return f.isDirectory();
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
exports.mkPath = function(/**Array*/ path) {
|
||||
if (path.constructor != Array){path = path.split(/[\\\/]/);}
|
||||
var make = "";
|
||||
for (var i = 0, l = path.length; i < l; i++) {
|
||||
make += path[i] + '/';
|
||||
if (! exists(make)) {
|
||||
makeDir(make);
|
||||
}
|
||||
if (f.isDirectory()){
|
||||
return path;
|
||||
}
|
||||
|
||||
var parts = path.split(/[\\\/]/);
|
||||
parts.pop();
|
||||
|
||||
return parts.join('/');
|
||||
};
|
||||
|
||||
function makeDir(/**string*/ path) {
|
||||
@ -108,17 +110,20 @@ function exists(path) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var toDir = exports.toDir = function(path) {
|
||||
var f = new java.io.File(path);
|
||||
|
||||
if (f.isDirectory()){
|
||||
return path;
|
||||
exports.mkPath = function(/**Array*/ path) {
|
||||
if (path.constructor != Array){path = path.split(/[\\\/]/);}
|
||||
var make = "";
|
||||
for (var i = 0, l = path.length; i < l; i++) {
|
||||
make += path[i] + '/';
|
||||
if (! exists(make)) {
|
||||
makeDir(make);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var toFile = exports.toFile = function(path) {
|
||||
var parts = path.split(/[\\\/]/);
|
||||
parts.pop();
|
||||
|
||||
return parts.join('/');
|
||||
return parts.pop();
|
||||
};
|
||||
|
||||
exports.copyFile = function(inFile, outDir, fileName) {
|
||||
@ -139,11 +144,6 @@ exports.copyFile = function(inFile, outDir, fileName) {
|
||||
bis.close();
|
||||
};
|
||||
|
||||
var toFile = exports.toFile = function(path) {
|
||||
var parts = path.split(/[\\\/]/);
|
||||
return parts.pop();
|
||||
};
|
||||
|
||||
exports.writeFileSync = function(filename, data, encoding) {
|
||||
encoding = encoding || 'utf-8';
|
||||
|
||||
|
||||
@ -21,8 +21,6 @@ const defaults = {
|
||||
"jsVersion": 180
|
||||
};
|
||||
|
||||
module.exports = Config;
|
||||
|
||||
/**
|
||||
@class
|
||||
@classdesc Represents a JSDoc application configuration.
|
||||
@ -34,6 +32,8 @@ function Config(json) {
|
||||
this._config = util.mergeRecurse(defaults, json);
|
||||
}
|
||||
|
||||
module.exports = Config;
|
||||
|
||||
/**
|
||||
Get the merged configuration values.
|
||||
*/
|
||||
|
||||
@ -18,7 +18,109 @@ var jsdoc = {
|
||||
},
|
||||
name: require('jsdoc/name')
|
||||
};
|
||||
|
||||
function applyTag(tag) {
|
||||
if (tag.title === 'name') {
|
||||
this.name = tag.value;
|
||||
}
|
||||
|
||||
if (tag.title === 'kind') {
|
||||
this.kind = tag.value;
|
||||
}
|
||||
|
||||
if (tag.title === 'description') {
|
||||
this.description = tag.value;
|
||||
}
|
||||
|
||||
if (tag.title === 'scope') {
|
||||
this.scope = tag.value;
|
||||
}
|
||||
}
|
||||
|
||||
// use the meta info about the source code to guess what the doclet kind should be
|
||||
function codetypeToKind(type) {
|
||||
var kind = (type || '').toLowerCase();
|
||||
|
||||
if (kind !== 'function') {
|
||||
return 'member';
|
||||
}
|
||||
|
||||
return kind;
|
||||
}
|
||||
|
||||
function unwrap(docletSrc) {
|
||||
if (!docletSrc) { return ''; }
|
||||
|
||||
// note: keep trailing whitespace for @examples
|
||||
// extra opening/closing stars are ignored
|
||||
// left margin is considered a star and a space
|
||||
// use the /m flag on regex to avoid having to guess what this platform's newline is
|
||||
docletSrc =
|
||||
docletSrc.replace(/^\/\*\*+/, '') // remove opening slash+stars
|
||||
.replace(/\**\*\/$/, "\\Z") // replace closing star slash with end-marker
|
||||
.replace(/^\s*(\* ?|\\Z)/gm, '') // remove left margin like: spaces+star or spaces+end-marker
|
||||
.replace(/\s*\\Z$/g, ''); // remove end-marker
|
||||
|
||||
return docletSrc;
|
||||
}
|
||||
|
||||
function split(docletSrc) {
|
||||
var tagSrcs = [],
|
||||
tagText,
|
||||
tagTitle;
|
||||
|
||||
// split out the basic tags, keep surrounding whitespace
|
||||
// like: @tagTitle tagBody
|
||||
docletSrc
|
||||
.replace(/^(\s*)@(\S)/gm, '$1\\@$2') // replace splitter ats with an arbitrary sequence
|
||||
.split('\\@') // then split on that arbitrary sequence
|
||||
.forEach(function($) {
|
||||
if ($) {
|
||||
var parsedTag = $.match(/^(\S+)(:?\s+(\S[\s\S]*))?/);
|
||||
|
||||
if (parsedTag) {
|
||||
// we don't need parsedTag[0]
|
||||
tagTitle = parsedTag[1];
|
||||
tagText = parsedTag[2];
|
||||
|
||||
if (tagTitle) {
|
||||
tagSrcs.push({
|
||||
title: tagTitle,
|
||||
text: tagText
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return tagSrcs;
|
||||
}
|
||||
|
||||
/**
|
||||
Convert the raw source of the doclet comment into an array of Tag objects.
|
||||
@private
|
||||
*/
|
||||
function toTags(docletSrc) {
|
||||
var tagSrcs,
|
||||
tags = [];
|
||||
|
||||
docletSrc = unwrap(docletSrc);
|
||||
tagSrcs = split(docletSrc);
|
||||
|
||||
for (var i = 0, l = tagSrcs.length; i < l; i++) {
|
||||
tags.push( {title: tagSrcs[i].title, text: tagSrcs[i].text} );
|
||||
}
|
||||
|
||||
return tags;
|
||||
}
|
||||
|
||||
function fixDescription(docletSrc) {
|
||||
if (!/^\s*@/.test(docletSrc)) {
|
||||
docletSrc = '@description ' + docletSrc;
|
||||
}
|
||||
return docletSrc;
|
||||
}
|
||||
|
||||
/**
|
||||
@class
|
||||
@classdesc Represents a single JSDoc comment.
|
||||
@ -228,105 +330,3 @@ exports.Doclet.prototype.setMeta = function(meta) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function applyTag(tag) {
|
||||
if (tag.title === 'name') {
|
||||
this.name = tag.value;
|
||||
}
|
||||
|
||||
if (tag.title === 'kind') {
|
||||
this.kind = tag.value;
|
||||
}
|
||||
|
||||
if (tag.title === 'description') {
|
||||
this.description = tag.value;
|
||||
}
|
||||
|
||||
if (tag.title === 'scope') {
|
||||
this.scope = tag.value;
|
||||
}
|
||||
}
|
||||
|
||||
// use the meta info about the source code to guess what the doclet kind should be
|
||||
function codetypeToKind(type) {
|
||||
var kind = (type || '').toLowerCase();
|
||||
|
||||
if (kind !== 'function') {
|
||||
return 'member';
|
||||
}
|
||||
|
||||
return kind;
|
||||
}
|
||||
|
||||
/**
|
||||
Convert the raw source of the doclet comment into an array of Tag objects.
|
||||
@private
|
||||
*/
|
||||
function toTags(docletSrc) {
|
||||
var tagSrcs,
|
||||
tags = [];
|
||||
|
||||
docletSrc = unwrap(docletSrc);
|
||||
tagSrcs = split(docletSrc);
|
||||
|
||||
for (var i = 0, l = tagSrcs.length; i < l; i++) {
|
||||
tags.push( {title: tagSrcs[i].title, text: tagSrcs[i].text} );
|
||||
}
|
||||
|
||||
return tags;
|
||||
}
|
||||
|
||||
function unwrap(docletSrc) {
|
||||
if (!docletSrc) { return ''; }
|
||||
|
||||
// note: keep trailing whitespace for @examples
|
||||
// extra opening/closing stars are ignored
|
||||
// left margin is considered a star and a space
|
||||
// use the /m flag on regex to avoid having to guess what this platform's newline is
|
||||
docletSrc =
|
||||
docletSrc.replace(/^\/\*\*+/, '') // remove opening slash+stars
|
||||
.replace(/\**\*\/$/, "\\Z") // replace closing star slash with end-marker
|
||||
.replace(/^\s*(\* ?|\\Z)/gm, '') // remove left margin like: spaces+star or spaces+end-marker
|
||||
.replace(/\s*\\Z$/g, ''); // remove end-marker
|
||||
|
||||
return docletSrc;
|
||||
}
|
||||
|
||||
function fixDescription(docletSrc) {
|
||||
if (!/^\s*@/.test(docletSrc)) {
|
||||
docletSrc = '@description ' + docletSrc;
|
||||
}
|
||||
return docletSrc;
|
||||
}
|
||||
|
||||
function split(docletSrc) {
|
||||
var tagSrcs = [],
|
||||
tagText,
|
||||
tagTitle;
|
||||
|
||||
// split out the basic tags, keep surrounding whitespace
|
||||
// like: @tagTitle tagBody
|
||||
docletSrc
|
||||
.replace(/^(\s*)@(\S)/gm, '$1\\@$2') // replace splitter ats with an arbitrary sequence
|
||||
.split('\\@') // then split on that arbitrary sequence
|
||||
.forEach(function($) {
|
||||
if ($) {
|
||||
var parsedTag = $.match(/^(\S+)(:?\s+(\S[\s\S]*))?/);
|
||||
|
||||
if (parsedTag) {
|
||||
// we don't need parsedTag[0]
|
||||
tagTitle = parsedTag[1];
|
||||
tagText = parsedTag[2];
|
||||
|
||||
if (tagTitle) {
|
||||
tagSrcs.push({
|
||||
title: tagTitle,
|
||||
text: tagText
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return tagSrcs;
|
||||
}
|
||||
|
||||
@ -12,35 +12,9 @@
|
||||
@author Ben Blank <ben.blank@gmail.com>
|
||||
*/
|
||||
|
||||
module.exports = ReadMe;
|
||||
|
||||
var fs = require('fs'),
|
||||
conf = env.conf.markdown;
|
||||
|
||||
/**
|
||||
@class
|
||||
@classdesc Represents a README file.
|
||||
@param {string} path - The filepath to the README.
|
||||
*/
|
||||
function ReadMe(path) {
|
||||
var content = fs.readFileSync(path),
|
||||
parse;
|
||||
|
||||
// determine which parser should be used based on configuration options, if any
|
||||
if (conf && conf.parser) {
|
||||
parse = getParser(conf.parser, conf);
|
||||
} else if (conf && conf.githubRepoOwner && conf.githubRepoName) {
|
||||
// use GitHub-friendly parser if GitHub-specific options are present
|
||||
parse = getParser('gfm', conf);
|
||||
} else {
|
||||
// evilstreak is the default parser
|
||||
parse = getParser('evilstreak', conf);
|
||||
}
|
||||
|
||||
this.html = parse(content);
|
||||
|
||||
}
|
||||
|
||||
function getParser(parser, conf) {
|
||||
conf = conf || {};
|
||||
|
||||
@ -66,3 +40,28 @@ function getParser(parser, conf) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@class
|
||||
@classdesc Represents a README file.
|
||||
@param {string} path - The filepath to the README.
|
||||
*/
|
||||
function ReadMe(path) {
|
||||
var content = fs.readFileSync(path),
|
||||
parse;
|
||||
|
||||
// determine which parser should be used based on configuration options, if any
|
||||
if (conf && conf.parser) {
|
||||
parse = getParser(conf.parser, conf);
|
||||
} else if (conf && conf.githubRepoOwner && conf.githubRepoName) {
|
||||
// use GitHub-friendly parser if GitHub-specific options are present
|
||||
parse = getParser('gfm', conf);
|
||||
} else {
|
||||
// evilstreak is the default parser
|
||||
parse = getParser('evilstreak', conf);
|
||||
}
|
||||
|
||||
this.html = parse(content);
|
||||
|
||||
}
|
||||
|
||||
module.exports = ReadMe;
|
||||
|
||||
@ -39,7 +39,8 @@ exports.attachTo = function(parser) {
|
||||
});
|
||||
|
||||
function newSymbolDoclet(docletSrc, e) {
|
||||
var newDoclet = new jsdoc.doclet.Doclet(docletSrc, e);
|
||||
var memberofName = null,
|
||||
newDoclet = new jsdoc.doclet.Doclet(docletSrc, e);
|
||||
|
||||
// an undocumented symbol right after a virtual comment? rhino mistakenly connected the two
|
||||
if (newDoclet.name) { // there was a @name in comment
|
||||
@ -64,8 +65,7 @@ exports.attachTo = function(parser) {
|
||||
else if (e.code && e.code.name) { // we need to get the symbol name from code
|
||||
newDoclet.addTag('name', e.code.name);
|
||||
if (!newDoclet.memberof && e.astnode) {
|
||||
var memberofName = null,
|
||||
basename = null,
|
||||
var basename = null,
|
||||
scope = '';
|
||||
if ( /^((module.)?exports|this)(\.|$)/.test(newDoclet.name) ) {
|
||||
var nameStartsWith = RegExp.$1;
|
||||
|
||||
@ -115,6 +115,337 @@ exports.Parser.prototype.getVisitors = function() {
|
||||
return this._visitors;
|
||||
}
|
||||
|
||||
function pretreat(code) {
|
||||
return code
|
||||
// make starbangstar comments look like real jsdoc comments
|
||||
.replace(/\/\*\!\*/g, '/**')
|
||||
|
||||
// merge adjacent doclets
|
||||
.replace(/\*\/\/\*\*+/g, '@also')
|
||||
// make lent objectliterals documentable by giving them a dummy name
|
||||
.replace(/(\/\*\*[^\*\/]*?@lends\b[^\*\/]*?\*\/\s*)\{/g, '$1 ____ = {') // like return @lends {
|
||||
.replace(/(\/\*\*[^\*\/]*?@lends\b[^\*\/]*?\*\/)(\s*)return(\s*)\{/g, '$2$3 return $1 ____ = {'); // like @lends return {
|
||||
}
|
||||
|
||||
var tkn = { NAMEDFUNCTIONSTATEMENT: -1001 };
|
||||
exports.Parser.tkn = tkn;
|
||||
|
||||
/** @private */
|
||||
function parserFactory() {
|
||||
var cx = Packages.org.mozilla.javascript.Context.getCurrentContext();
|
||||
|
||||
var ce = new Packages.org.mozilla.javascript.CompilerEnvirons();
|
||||
ce.setRecordingComments(true);
|
||||
ce.setRecordingLocalJsDocComments(true);
|
||||
ce.setLanguageVersion(180);
|
||||
|
||||
ce.initFromContext(cx);
|
||||
return new Packages.org.mozilla.javascript.Parser(ce, ce.getErrorReporter());
|
||||
}
|
||||
|
||||
/** @private
|
||||
@memberof module:src/parser.Parser
|
||||
*/
|
||||
function getTypeName(node) {
|
||||
var type = '';
|
||||
|
||||
if (node) {
|
||||
type = ''+ Packages.org.mozilla.javascript.Token.typeToName(node.getType());
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/** @private
|
||||
@memberof module:src/parser.Parser
|
||||
*/
|
||||
function nodeToString(node) {
|
||||
var str;
|
||||
|
||||
if (!node) { return; }
|
||||
|
||||
if (node.type === Token.GETPROP) {
|
||||
str = [nodeToString(node.target), node.property.string].join('.');
|
||||
}
|
||||
else if (node.type === Token.VAR) {
|
||||
str = nodeToString(node.target)
|
||||
}
|
||||
else if (node.type === Token.NAME) {
|
||||
str = node.string;
|
||||
}
|
||||
else if (node.type === Token.STRING) {
|
||||
str = node.value;
|
||||
}
|
||||
else if (node.type === Token.NUMBER) {
|
||||
str = node.value;
|
||||
}
|
||||
else if (node.type === Token.THIS) {
|
||||
str = 'this';
|
||||
}
|
||||
else if (node.type === Token.GETELEM) {
|
||||
str = node.toSource(); // like: Foo['Bar']
|
||||
}
|
||||
else if (node.type === Token.NEG || node.type === Token.TRUE || node.type === Token.FALSE) {
|
||||
str = node.toSource(); // like -1
|
||||
}
|
||||
else {
|
||||
str = getTypeName(node);
|
||||
}
|
||||
|
||||
return '' + str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to find the name and type of the given node.
|
||||
* @private
|
||||
* @memberof module:src/parser.Parser
|
||||
*/
|
||||
function aboutNode(node) {
|
||||
var about = {};
|
||||
|
||||
if (node.type == Token.FUNCTION || node.type == tkn.NAMEDFUNCTIONSTATEMENT) {
|
||||
about.name = node.type == tkn.NAMEDFUNCTIONSTATEMENT? '' : '' + node.name;
|
||||
about.type = 'function';
|
||||
about.node = node;
|
||||
}
|
||||
else if (node.type == Token.VAR || node.type == Token.LET || node.type == Token.CONST) {
|
||||
about.name = nodeToString(node.target);
|
||||
if (node.initializer) { // like var i = 0;
|
||||
about.node = node.initializer;
|
||||
about.value = nodeToString(about.node);
|
||||
about.type = getTypeName(node.initializer);
|
||||
if (about.type === 'FUNCTION' && about.node.name) {
|
||||
about.node.type = tkn.NAMEDFUNCTIONSTATEMENT;
|
||||
}
|
||||
}
|
||||
else { // like var i;
|
||||
about.node = node.target;
|
||||
about.value = nodeToString(about.node);
|
||||
about.type = 'undefined';
|
||||
}
|
||||
}
|
||||
else if (node.type === Token.ASSIGN || node.type === Token.COLON) {
|
||||
about.name = nodeToString(node.left);
|
||||
if (node.type === Token.COLON) {
|
||||
|
||||
// objlit keys with unsafe variable-name characters must be quoted
|
||||
if (!/^[$_a-z][$_a-z0-9]*$/i.test(about.name) ) {
|
||||
about.name = '"'+about.name.replace(/"/g, '\\"')+'"';
|
||||
}
|
||||
}
|
||||
about.node = node.right;
|
||||
about.value = nodeToString(about.node);
|
||||
about.type = getTypeName(node.right);
|
||||
|
||||
if (about.type === 'FUNCTION' && about.node.name) {
|
||||
about.node.type = tkn.NAMEDFUNCTIONSTATEMENT;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// type 39 (NAME)
|
||||
var string = nodeToString(node);
|
||||
if (string) {
|
||||
about.name = string;
|
||||
}
|
||||
}
|
||||
|
||||
// get names of the formal parameters declared for this function
|
||||
if (about.node && about.node.getParamCount) {
|
||||
var paramCount = about.node.getParamCount();
|
||||
if (typeof paramCount === 'number') {
|
||||
about.node.flattenSymbolTable(true);
|
||||
var paramNames = [];
|
||||
for (var i = 0, len = paramCount; i < len; i++) {
|
||||
paramNames.push(''+about.node.getParamOrVarName(i));
|
||||
}
|
||||
about.paramnames = paramNames;
|
||||
}
|
||||
}
|
||||
|
||||
return about;
|
||||
}
|
||||
|
||||
/** @private
|
||||
@memberof module:src/parser.Parser
|
||||
*/
|
||||
function isValidJsdoc(commentSrc) {
|
||||
return commentSrc && commentSrc.indexOf('/***') !== 0; /*** ignore comments that start with many stars ***/
|
||||
}
|
||||
|
||||
/** @private
|
||||
* @memberof module:src/parser.Parser
|
||||
*/
|
||||
function makeVarsFinisher(funcDoc) {
|
||||
var func = function(e) {
|
||||
//no need to evaluate all things related to funcDoc again, just use it
|
||||
if (funcDoc && e.doclet && e.doclet.alias) {
|
||||
funcDoc.meta.vars[e.code.name] = e.doclet.longname;
|
||||
}
|
||||
}
|
||||
return func;
|
||||
}
|
||||
|
||||
/** @private
|
||||
* @memberof module:src/parser.Parser
|
||||
* @param {string} name Full symbol name.
|
||||
* @return {string} Basename.
|
||||
*/
|
||||
function getBasename(name) {
|
||||
if (name !== undefined) {
|
||||
return name.replace(/^([$a-z_][$a-z_0-9]*).*?$/i, '$1');
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/** @private */
|
||||
function visitNode(node) {
|
||||
var e,
|
||||
nodeComments,
|
||||
comment,
|
||||
commentSrc,
|
||||
i,
|
||||
l;
|
||||
|
||||
// look for stand-alone doc comments
|
||||
if (node.type === Token.SCRIPT && node.comments) {
|
||||
// note: ALL comments are seen in this block...
|
||||
nodeComments = node.comments.toArray();
|
||||
for (i = 0, l = nodeComments.length; i < l; i++) {
|
||||
comment = nodeComments[i];
|
||||
if (comment.commentType !== Token.CommentType.JSDOC) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (commentSrc = ''+comment.toSource()) {
|
||||
|
||||
e = {
|
||||
comment: commentSrc,
|
||||
lineno: comment.getLineno(),
|
||||
filename: currentSourceName
|
||||
};
|
||||
|
||||
if ( isValidJsdoc(commentSrc) ) {
|
||||
currentParser.fire('jsdocCommentFound', e, currentParser);
|
||||
}
|
||||
}
|
||||
}
|
||||
e = null;
|
||||
}
|
||||
else if (node.type === Token.ASSIGN) {
|
||||
e = {
|
||||
id: 'astnode'+node.hashCode(), // the id of the ASSIGN node
|
||||
comment: String(node.getJsDoc()||'@undocumented'),
|
||||
lineno: node.left.getLineno(),
|
||||
filename: currentSourceName,
|
||||
astnode: node,
|
||||
code: aboutNode(node),
|
||||
event: "symbolFound",
|
||||
finishers: [currentParser.addDocletRef]
|
||||
};
|
||||
|
||||
var basename = getBasename(e.code.name);
|
||||
|
||||
if (basename !== 'this') {
|
||||
e.code.funcscope = currentParser.resolveVar(node, basename);
|
||||
}
|
||||
}
|
||||
else if (node.type === Token.COLON) { // assignment within an object literal
|
||||
e = {
|
||||
id: 'astnode'+node.hashCode(), // the id of the COLON node
|
||||
comment: String(node.left.getJsDoc()||'@undocumented'),
|
||||
lineno: node.left.getLineno(),
|
||||
filename: currentSourceName,
|
||||
astnode: node,
|
||||
code: aboutNode(node),
|
||||
event: "symbolFound",
|
||||
finishers: [currentParser.addDocletRef, currentParser.resolveEnum]
|
||||
};
|
||||
}
|
||||
else if (node.type == Token.VAR || node.type == Token.LET || node.type == Token.CONST) {
|
||||
|
||||
if (node.variables) {
|
||||
return true; // we'll get each var separately on future visits
|
||||
}
|
||||
|
||||
if (node.parent.variables.toArray()[0] === node) { // like /** blah */ var a=1, b=2, c=3;
|
||||
// the first var assignment gets any jsDoc before the whole var series
|
||||
if (typeof node.setJsDoc !== 'undefined') { node.setJsDoc( node.parent.getJsDoc() ); }
|
||||
//node.jsDoc = node.parent.jsDoc;
|
||||
}
|
||||
|
||||
e = {
|
||||
id: 'astnode'+node.hashCode(), // the id of the VARIABLE node
|
||||
comment: String(node.getJsDoc()||'@undocumented'),
|
||||
lineno: node.getLineno(),
|
||||
filename: currentSourceName,
|
||||
astnode: node,
|
||||
code: aboutNode(node),
|
||||
event: "symbolFound",
|
||||
finishers: [currentParser.addDocletRef]
|
||||
};
|
||||
|
||||
// keep track of vars in a function or global scope
|
||||
var func = "__global__",
|
||||
funcDoc = null;
|
||||
if (node.enclosingFunction) {
|
||||
func = 'astnode'+node.enclosingFunction.hashCode();
|
||||
}
|
||||
funcDoc = currentParser.refs[func];
|
||||
if (funcDoc) {
|
||||
funcDoc.meta.vars = funcDoc.meta.vars || {};
|
||||
funcDoc.meta.vars[e.code.name] = false;
|
||||
e.finishers.push(makeVarsFinisher(funcDoc));
|
||||
}
|
||||
}
|
||||
else if (node.type == Token.FUNCTION || node.type == tkn.NAMEDFUNCTIONSTATEMENT) {
|
||||
e = {
|
||||
id: 'astnode'+node.hashCode(), // the id of the COLON node
|
||||
comment: String(node.getJsDoc()||'@undocumented'),
|
||||
lineno: node.getLineno(),
|
||||
filename: currentSourceName,
|
||||
astnode: node,
|
||||
code: aboutNode(node),
|
||||
event: "symbolFound",
|
||||
finishers: [currentParser.addDocletRef]
|
||||
};
|
||||
|
||||
e.code.name = (node.type == tkn.NAMEDFUNCTIONSTATEMENT)? '' : String(node.name) || '';
|
||||
//console.log(':: e.code.name is', e.code.name);
|
||||
|
||||
// keep track of vars in a function or global scope
|
||||
var func = "__global__",
|
||||
funcDoc = null;
|
||||
if (node.enclosingFunction) {
|
||||
func = 'astnode'+node.enclosingFunction.hashCode();
|
||||
}
|
||||
funcDoc = currentParser.refs[func];
|
||||
if (funcDoc) {
|
||||
funcDoc.meta.vars = funcDoc.meta.vars || {};
|
||||
funcDoc.meta.vars[e.code.name] = false;
|
||||
e.finishers.push(makeVarsFinisher(funcDoc));
|
||||
}
|
||||
|
||||
var basename = getBasename(e.code.name)
|
||||
e.code.funcscope = currentParser.resolveVar(node, basename);
|
||||
}
|
||||
|
||||
if (!e) { e = {finishers: []}; }
|
||||
for(var i = 0, l = currentParser._visitors.length; i < l; i++) {
|
||||
currentParser._visitors[i].visitNode(node, e, currentParser, currentSourceName);
|
||||
if (e.stopPropagation) { break; }
|
||||
}
|
||||
|
||||
if (!e.preventDefault && isValidJsdoc(e.comment)) {
|
||||
currentParser.fire(e.event, e, currentParser);
|
||||
}
|
||||
|
||||
for (var i = 0, l = e.finishers.length; i < l; i++) {
|
||||
e.finishers[i].call(currentParser, e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @private */
|
||||
exports.Parser.prototype._parseSourceCode = function(sourceCode, sourceName) {
|
||||
var e = {filename: sourceName};
|
||||
@ -141,21 +472,6 @@ exports.Parser.prototype._parseSourceCode = function(sourceCode, sourceName) {
|
||||
currentSourceName = '';
|
||||
}
|
||||
|
||||
function pretreat(code) {
|
||||
return code
|
||||
// make starbangstar comments look like real jsdoc comments
|
||||
.replace(/\/\*\!\*/g, '/**')
|
||||
|
||||
// merge adjacent doclets
|
||||
.replace(/\*\/\/\*\*+/g, '@also')
|
||||
// make lent objectliterals documentable by giving them a dummy name
|
||||
.replace(/(\/\*\*[^\*\/]*?@lends\b[^\*\/]*?\*\/\s*)\{/g, '$1 ____ = {') // like return @lends {
|
||||
.replace(/(\/\*\*[^\*\/]*?@lends\b[^\*\/]*?\*\/)(\s*)return(\s*)\{/g, '$2$3 return $1 ____ = {'); // like @lends return {
|
||||
}
|
||||
|
||||
var tkn = { NAMEDFUNCTIONSTATEMENT: -1001 };
|
||||
exports.Parser.tkn = tkn;
|
||||
|
||||
/**
|
||||
* Given a node, determine what the node is a member of.
|
||||
* @param {astnode} node
|
||||
@ -331,322 +647,6 @@ exports.Parser.prototype.resolveEnum = function(e) {
|
||||
}
|
||||
}
|
||||
|
||||
/** @private */
|
||||
function visitNode(node) {
|
||||
var e,
|
||||
nodeComments,
|
||||
comment,
|
||||
commentSrc,
|
||||
i,
|
||||
l;
|
||||
|
||||
// look for stand-alone doc comments
|
||||
if (node.type === Token.SCRIPT && node.comments) {
|
||||
// note: ALL comments are seen in this block...
|
||||
nodeComments = node.comments.toArray();
|
||||
for (i = 0, l = nodeComments.length; i < l; i++) {
|
||||
comment = nodeComments[i];
|
||||
if (comment.commentType !== Token.CommentType.JSDOC) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (commentSrc = ''+comment.toSource()) {
|
||||
|
||||
e = {
|
||||
comment: commentSrc,
|
||||
lineno: comment.getLineno(),
|
||||
filename: currentSourceName
|
||||
};
|
||||
|
||||
if ( isValidJsdoc(commentSrc) ) {
|
||||
currentParser.fire('jsdocCommentFound', e, currentParser);
|
||||
}
|
||||
}
|
||||
}
|
||||
e = null;
|
||||
}
|
||||
else if (node.type === Token.ASSIGN) {
|
||||
e = {
|
||||
id: 'astnode'+node.hashCode(), // the id of the ASSIGN node
|
||||
comment: String(node.getJsDoc()||'@undocumented'),
|
||||
lineno: node.left.getLineno(),
|
||||
filename: currentSourceName,
|
||||
astnode: node,
|
||||
code: aboutNode(node),
|
||||
event: "symbolFound",
|
||||
finishers: [currentParser.addDocletRef]
|
||||
};
|
||||
|
||||
var basename = getBasename(e.code.name);
|
||||
|
||||
if (basename !== 'this') {
|
||||
e.code.funcscope = currentParser.resolveVar(node, basename);
|
||||
}
|
||||
}
|
||||
else if (node.type === Token.COLON) { // assignment within an object literal
|
||||
e = {
|
||||
id: 'astnode'+node.hashCode(), // the id of the COLON node
|
||||
comment: String(node.left.getJsDoc()||'@undocumented'),
|
||||
lineno: node.left.getLineno(),
|
||||
filename: currentSourceName,
|
||||
astnode: node,
|
||||
code: aboutNode(node),
|
||||
event: "symbolFound",
|
||||
finishers: [currentParser.addDocletRef, currentParser.resolveEnum]
|
||||
};
|
||||
}
|
||||
else if (node.type == Token.VAR || node.type == Token.LET || node.type == Token.CONST) {
|
||||
|
||||
if (node.variables) {
|
||||
return true; // we'll get each var separately on future visits
|
||||
}
|
||||
|
||||
if (node.parent.variables.toArray()[0] === node) { // like /** blah */ var a=1, b=2, c=3;
|
||||
// the first var assignment gets any jsDoc before the whole var series
|
||||
if (typeof node.setJsDoc !== 'undefined') { node.setJsDoc( node.parent.getJsDoc() ); }
|
||||
//node.jsDoc = node.parent.jsDoc;
|
||||
}
|
||||
|
||||
e = {
|
||||
id: 'astnode'+node.hashCode(), // the id of the VARIABLE node
|
||||
comment: String(node.getJsDoc()||'@undocumented'),
|
||||
lineno: node.getLineno(),
|
||||
filename: currentSourceName,
|
||||
astnode: node,
|
||||
code: aboutNode(node),
|
||||
event: "symbolFound",
|
||||
finishers: [currentParser.addDocletRef]
|
||||
};
|
||||
|
||||
// keep track of vars in a function or global scope
|
||||
var func = "__global__",
|
||||
funcDoc = null;
|
||||
if (node.enclosingFunction) {
|
||||
func = 'astnode'+node.enclosingFunction.hashCode();
|
||||
}
|
||||
funcDoc = currentParser.refs[func];
|
||||
if (funcDoc) {
|
||||
funcDoc.meta.vars = funcDoc.meta.vars || {};
|
||||
funcDoc.meta.vars[e.code.name] = false;
|
||||
e.finishers.push(makeVarsFinisher(funcDoc));
|
||||
}
|
||||
}
|
||||
else if (node.type == Token.FUNCTION || node.type == tkn.NAMEDFUNCTIONSTATEMENT) {
|
||||
e = {
|
||||
id: 'astnode'+node.hashCode(), // the id of the COLON node
|
||||
comment: String(node.getJsDoc()||'@undocumented'),
|
||||
lineno: node.getLineno(),
|
||||
filename: currentSourceName,
|
||||
astnode: node,
|
||||
code: aboutNode(node),
|
||||
event: "symbolFound",
|
||||
finishers: [currentParser.addDocletRef]
|
||||
};
|
||||
|
||||
e.code.name = (node.type == tkn.NAMEDFUNCTIONSTATEMENT)? '' : String(node.name) || '';
|
||||
//console.log(':: e.code.name is', e.code.name);
|
||||
|
||||
// keep track of vars in a function or global scope
|
||||
var func = "__global__",
|
||||
funcDoc = null;
|
||||
if (node.enclosingFunction) {
|
||||
func = 'astnode'+node.enclosingFunction.hashCode();
|
||||
}
|
||||
funcDoc = currentParser.refs[func];
|
||||
if (funcDoc) {
|
||||
funcDoc.meta.vars = funcDoc.meta.vars || {};
|
||||
funcDoc.meta.vars[e.code.name] = false;
|
||||
e.finishers.push(makeVarsFinisher(funcDoc));
|
||||
}
|
||||
|
||||
var basename = getBasename(e.code.name)
|
||||
e.code.funcscope = currentParser.resolveVar(node, basename);
|
||||
}
|
||||
|
||||
if (!e) { e = {finishers: []}; }
|
||||
for(var i = 0, l = currentParser._visitors.length; i < l; i++) {
|
||||
currentParser._visitors[i].visitNode(node, e, currentParser, currentSourceName);
|
||||
if (e.stopPropagation) { break; }
|
||||
}
|
||||
|
||||
if (!e.preventDefault && isValidJsdoc(e.comment)) {
|
||||
currentParser.fire(e.event, e, currentParser);
|
||||
}
|
||||
|
||||
for (var i = 0, l = e.finishers.length; i < l; i++) {
|
||||
e.finishers[i].call(currentParser, e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @private */
|
||||
function parserFactory() {
|
||||
var cx = Packages.org.mozilla.javascript.Context.getCurrentContext();
|
||||
|
||||
var ce = new Packages.org.mozilla.javascript.CompilerEnvirons();
|
||||
ce.setRecordingComments(true);
|
||||
ce.setRecordingLocalJsDocComments(true);
|
||||
ce.setLanguageVersion(180);
|
||||
|
||||
ce.initFromContext(cx);
|
||||
return new Packages.org.mozilla.javascript.Parser(ce, ce.getErrorReporter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to find the name and type of the given node.
|
||||
* @private
|
||||
* @memberof module:src/parser.Parser
|
||||
*/
|
||||
function aboutNode(node) {
|
||||
var about = {};
|
||||
|
||||
if (node.type == Token.FUNCTION || node.type == tkn.NAMEDFUNCTIONSTATEMENT) {
|
||||
about.name = node.type == tkn.NAMEDFUNCTIONSTATEMENT? '' : '' + node.name;
|
||||
about.type = 'function';
|
||||
about.node = node;
|
||||
}
|
||||
else if (node.type == Token.VAR || node.type == Token.LET || node.type == Token.CONST) {
|
||||
about.name = nodeToString(node.target);
|
||||
if (node.initializer) { // like var i = 0;
|
||||
about.node = node.initializer;
|
||||
about.value = nodeToString(about.node);
|
||||
about.type = getTypeName(node.initializer);
|
||||
if (about.type === 'FUNCTION' && about.node.name) {
|
||||
about.node.type = tkn.NAMEDFUNCTIONSTATEMENT;
|
||||
}
|
||||
}
|
||||
else { // like var i;
|
||||
about.node = node.target;
|
||||
about.value = nodeToString(about.node);
|
||||
about.type = 'undefined';
|
||||
}
|
||||
}
|
||||
else if (node.type === Token.ASSIGN || node.type === Token.COLON) {
|
||||
about.name = nodeToString(node.left);
|
||||
if (node.type === Token.COLON) {
|
||||
|
||||
// objlit keys with unsafe variable-name characters must be quoted
|
||||
if (!/^[$_a-z][$_a-z0-9]*$/i.test(about.name) ) {
|
||||
about.name = '"'+about.name.replace(/"/g, '\\"')+'"';
|
||||
}
|
||||
}
|
||||
about.node = node.right;
|
||||
about.value = nodeToString(about.node);
|
||||
about.type = getTypeName(node.right);
|
||||
|
||||
if (about.type === 'FUNCTION' && about.node.name) {
|
||||
about.node.type = tkn.NAMEDFUNCTIONSTATEMENT;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// type 39 (NAME)
|
||||
var string = nodeToString(node);
|
||||
if (string) {
|
||||
about.name = string;
|
||||
}
|
||||
}
|
||||
|
||||
// get names of the formal parameters declared for this function
|
||||
if (about.node && about.node.getParamCount) {
|
||||
var paramCount = about.node.getParamCount();
|
||||
if (typeof paramCount === 'number') {
|
||||
about.node.flattenSymbolTable(true);
|
||||
var paramNames = [];
|
||||
for (var i = 0, len = paramCount; i < len; i++) {
|
||||
paramNames.push(''+about.node.getParamOrVarName(i));
|
||||
}
|
||||
about.paramnames = paramNames;
|
||||
}
|
||||
}
|
||||
|
||||
return about;
|
||||
}
|
||||
|
||||
/** @private
|
||||
@memberof module:src/parser.Parser
|
||||
*/
|
||||
function nodeToString(node) {
|
||||
var str;
|
||||
|
||||
if (!node) { return; }
|
||||
|
||||
if (node.type === Token.GETPROP) {
|
||||
str = [nodeToString(node.target), node.property.string].join('.');
|
||||
}
|
||||
else if (node.type === Token.VAR) {
|
||||
str = nodeToString(node.target)
|
||||
}
|
||||
else if (node.type === Token.NAME) {
|
||||
str = node.string;
|
||||
}
|
||||
else if (node.type === Token.STRING) {
|
||||
str = node.value;
|
||||
}
|
||||
else if (node.type === Token.NUMBER) {
|
||||
str = node.value;
|
||||
}
|
||||
else if (node.type === Token.THIS) {
|
||||
str = 'this';
|
||||
}
|
||||
else if (node.type === Token.GETELEM) {
|
||||
str = node.toSource(); // like: Foo['Bar']
|
||||
}
|
||||
else if (node.type === Token.NEG || node.type === Token.TRUE || node.type === Token.FALSE) {
|
||||
str = node.toSource(); // like -1
|
||||
}
|
||||
else {
|
||||
str = getTypeName(node);
|
||||
}
|
||||
|
||||
return '' + str;
|
||||
}
|
||||
|
||||
/** @private
|
||||
@memberof module:src/parser.Parser
|
||||
*/
|
||||
function getTypeName(node) {
|
||||
var type = '';
|
||||
|
||||
if (node) {
|
||||
type = ''+ Packages.org.mozilla.javascript.Token.typeToName(node.getType());
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/** @private
|
||||
@memberof module:src/parser.Parser
|
||||
*/
|
||||
function isValidJsdoc(commentSrc) {
|
||||
return commentSrc && commentSrc.indexOf('/***') !== 0; /*** ignore comments that start with many stars ***/
|
||||
}
|
||||
|
||||
/** @private
|
||||
* @memberof module:src/parser.Parser
|
||||
*/
|
||||
function makeVarsFinisher(funcDoc) {
|
||||
var func = function(e) {
|
||||
//no need to evaluate all things related to funcDoc again, just use it
|
||||
if (funcDoc && e.doclet && e.doclet.alias) {
|
||||
funcDoc.meta.vars[e.code.name] = e.doclet.longname;
|
||||
}
|
||||
}
|
||||
return func;
|
||||
}
|
||||
|
||||
/** @private
|
||||
* @memberof module:src/parser.Parser
|
||||
* @param {string} name Full symbol name.
|
||||
* @return {string} Basename.
|
||||
*/
|
||||
function getBasename(name) {
|
||||
if (name !== undefined) {
|
||||
return name.replace(/^([$a-z_][$a-z_0-9]*).*?$/i, '$1');
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
Fired whenever the parser encounters a JSDoc comment in the current source code.
|
||||
@event jsdocCommentFound
|
||||
|
||||
@ -22,6 +22,45 @@ var jsdoc = {
|
||||
}
|
||||
};
|
||||
|
||||
function trim(text, newlines) {
|
||||
if (!text) { return ''; }
|
||||
|
||||
if (newlines) {
|
||||
return text.replace(/^[\n\r\f]+|[\n\r\f]+$/g, '');
|
||||
}
|
||||
else {
|
||||
return text.replace(/^\s+|\s+$/g, '');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Parse the parameter name and parameter desc from the tag text.
|
||||
@inner
|
||||
@method parseParamText
|
||||
@memberof module:jsdoc/tag
|
||||
@param {string} tagText
|
||||
@returns {Array.<string, string, boolean, boolean>} [pname, pdesc, poptional, pdefault].
|
||||
*/
|
||||
function parseParamText(tagText) {
|
||||
var pname, pdesc, poptional, pdefault;
|
||||
|
||||
// like: pname, pname pdesc, or name - pdesc
|
||||
tagText.match(/^(\[[^\]]+\]|\S+)((?:\s*\-\s*|\s+)(\S[\s\S]*))?$/);
|
||||
pname = RegExp.$1;
|
||||
pdesc = RegExp.$3;
|
||||
|
||||
if ( /^\[\s*(.+?)\s*\]$/.test(pname) ) {
|
||||
pname = RegExp.$1;
|
||||
poptional = true;
|
||||
|
||||
if ( /^(.+?)\s*=\s*(.+)$/.test(pname) ) {
|
||||
pname = RegExp.$1;
|
||||
pdefault = RegExp.$2;
|
||||
}
|
||||
}
|
||||
return { name: pname, desc: pdesc, optional: poptional, default: pdefault };
|
||||
}
|
||||
|
||||
/**
|
||||
Constructs a new tag object. Calls the tag validator.
|
||||
@class
|
||||
@ -99,42 +138,3 @@ exports.Tag = function(tagTitle, tagBody, meta) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function trim(text, newlines) {
|
||||
if (!text) { return ''; }
|
||||
|
||||
if (newlines) {
|
||||
return text.replace(/^[\n\r\f]+|[\n\r\f]+$/g, '');
|
||||
}
|
||||
else {
|
||||
return text.replace(/^\s+|\s+$/g, '');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Parse the parameter name and parameter desc from the tag text.
|
||||
@inner
|
||||
@method parseParamText
|
||||
@memberof module:jsdoc/tag
|
||||
@param {string} tagText
|
||||
@returns {Array.<string, string, boolean, boolean>} [pname, pdesc, poptional, pdefault].
|
||||
*/
|
||||
function parseParamText(tagText) {
|
||||
var pname, pdesc, poptional, pdefault;
|
||||
|
||||
// like: pname, pname pdesc, or name - pdesc
|
||||
tagText.match(/^(\[[^\]]+\]|\S+)((?:\s*\-\s*|\s+)(\S[\s\S]*))?$/);
|
||||
pname = RegExp.$1;
|
||||
pdesc = RegExp.$3;
|
||||
|
||||
if ( /^\[\s*(.+?)\s*\]$/.test(pname) ) {
|
||||
pname = RegExp.$1;
|
||||
poptional = true;
|
||||
|
||||
if ( /^(.+?)\s*=\s*(.+)$/.test(pname) ) {
|
||||
pname = RegExp.$1;
|
||||
pdefault = RegExp.$2;
|
||||
}
|
||||
}
|
||||
return { name: pname, desc: pdesc, optional: poptional, default: pdefault };
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
var _synonyms = {},
|
||||
_definitions = {},
|
||||
_namespaces = [],
|
||||
dictionary,
|
||||
hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
|
||||
/** @private */
|
||||
@ -29,7 +30,7 @@ TagDefinition.prototype.synonym = function(synonymName) {
|
||||
}
|
||||
|
||||
/** @exports jsdoc/tag/dictionary */
|
||||
var dictionary = {
|
||||
dictionary = {
|
||||
/** @function */
|
||||
defineTag: function(title, opts) {
|
||||
_definitions[title] = new TagDefinition(title, opts);
|
||||
|
||||
@ -7,6 +7,91 @@
|
||||
@license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
*/
|
||||
|
||||
/** @private */
|
||||
function setDocletKindToTitle(doclet, tag) {
|
||||
doclet.addTag( 'kind', tag.title );
|
||||
}
|
||||
|
||||
function setDocletScopeToTitle(doclet, tag) {
|
||||
doclet.addTag( 'scope', tag.title );
|
||||
}
|
||||
|
||||
function setDocletNameToValue(doclet, tag) {
|
||||
if (tag.value && tag.value.description) { // as in a long tag
|
||||
doclet.addTag( 'name', tag.value.description);
|
||||
}
|
||||
else if (tag.text) { // or a short tag
|
||||
doclet.addTag('name', tag.text);
|
||||
}
|
||||
}
|
||||
|
||||
function setDocletDescriptionToValue(doclet, tag) {
|
||||
if (tag.value) {
|
||||
doclet.addTag( 'description', tag.value );
|
||||
}
|
||||
}
|
||||
|
||||
function setNameToFile(doclet, tag) {
|
||||
if (doclet.meta.filename) {
|
||||
var name = 'file:';
|
||||
if (doclet.meta.path) { name += doclet.meta.path + java.lang.System.getProperty("file.separator"); }
|
||||
doclet.addTag( 'name', name + doclet.meta.filename );
|
||||
}
|
||||
}
|
||||
|
||||
function setDocletMemberof(doclet, tag) {
|
||||
if (tag.value && tag.value !== '<global>') {
|
||||
doclet.setMemberof(tag.value);
|
||||
}
|
||||
}
|
||||
|
||||
function applyNamespace(docletOrNs, tag) {
|
||||
if (typeof docletOrNs === 'string') { // ns
|
||||
tag.value = app.jsdoc.name.applyNamespace(tag.value, docletOrNs);
|
||||
}
|
||||
else { // doclet
|
||||
if (!docletOrNs.name) {
|
||||
return; // error?
|
||||
}
|
||||
|
||||
//doclet.displayname = doclet.name;
|
||||
docletOrNs.longname = app.jsdoc.name.applyNamespace(docletOrNs.name, tag.title);
|
||||
}
|
||||
}
|
||||
|
||||
function setDocletNameToFilename(doclet, tag) {
|
||||
var name = (doclet.meta.path ? (doclet.meta.path + java.lang.System.getProperty("file.separator")) : "") + doclet.meta.filename;
|
||||
name = name.replace(/\.js$/i, '');
|
||||
|
||||
for (var i = 0, len = env.opts._.length; i < len; i++) {
|
||||
if (name.indexOf(env.opts._[i]) === 0) {
|
||||
name = name.replace(env.opts._[0], '');
|
||||
break
|
||||
}
|
||||
}
|
||||
doclet.name = name;
|
||||
}
|
||||
|
||||
function parseBorrows(doclet, tag) {
|
||||
var m = /^(\S+)(?:\s+as\s+(\S+))?$/.exec(tag.text);
|
||||
if (m) {
|
||||
if (m[1] && m[2]) {
|
||||
return { target: m[1], source: m[2] };
|
||||
}
|
||||
else if (m[1]) {
|
||||
return { target: m[1] };
|
||||
}
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function firstWordOf(string) {
|
||||
var m = /^(\S+)/.exec(string);
|
||||
if (m) { return m[1]; }
|
||||
else { return ''; }
|
||||
}
|
||||
|
||||
/** Populate the given dictionary with all known JSDoc tag definitions.
|
||||
@param {module:jsdoc/tag/dictionary} dictionary
|
||||
*/
|
||||
@ -560,88 +645,3 @@ exports.defineTags = function(dictionary) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** @private */
|
||||
function setDocletKindToTitle(doclet, tag) {
|
||||
doclet.addTag( 'kind', tag.title );
|
||||
}
|
||||
|
||||
function setDocletScopeToTitle(doclet, tag) {
|
||||
doclet.addTag( 'scope', tag.title );
|
||||
}
|
||||
|
||||
function setDocletNameToValue(doclet, tag) {
|
||||
if (tag.value && tag.value.description) { // as in a long tag
|
||||
doclet.addTag( 'name', tag.value.description);
|
||||
}
|
||||
else if (tag.text) { // or a short tag
|
||||
doclet.addTag('name', tag.text);
|
||||
}
|
||||
}
|
||||
|
||||
function setDocletDescriptionToValue(doclet, tag) {
|
||||
if (tag.value) {
|
||||
doclet.addTag( 'description', tag.value );
|
||||
}
|
||||
}
|
||||
|
||||
function setNameToFile(doclet, tag) {
|
||||
if (doclet.meta.filename) {
|
||||
var name = 'file:';
|
||||
if (doclet.meta.path) { name += doclet.meta.path + java.lang.System.getProperty("file.separator"); }
|
||||
doclet.addTag( 'name', name + doclet.meta.filename );
|
||||
}
|
||||
}
|
||||
|
||||
function setDocletMemberof(doclet, tag) {
|
||||
if (tag.value && tag.value !== '<global>') {
|
||||
doclet.setMemberof(tag.value);
|
||||
}
|
||||
}
|
||||
|
||||
function applyNamespace(docletOrNs, tag) {
|
||||
if (typeof docletOrNs === 'string') { // ns
|
||||
tag.value = app.jsdoc.name.applyNamespace(tag.value, docletOrNs);
|
||||
}
|
||||
else { // doclet
|
||||
if (!docletOrNs.name) {
|
||||
return; // error?
|
||||
}
|
||||
|
||||
//doclet.displayname = doclet.name;
|
||||
docletOrNs.longname = app.jsdoc.name.applyNamespace(docletOrNs.name, tag.title);
|
||||
}
|
||||
}
|
||||
|
||||
function setDocletNameToFilename(doclet, tag) {
|
||||
var name = (doclet.meta.path ? (doclet.meta.path + java.lang.System.getProperty("file.separator")) : "") + doclet.meta.filename;
|
||||
name = name.replace(/\.js$/i, '');
|
||||
|
||||
for (var i = 0, len = env.opts._.length; i < len; i++) {
|
||||
if (name.indexOf(env.opts._[i]) === 0) {
|
||||
name = name.replace(env.opts._[0], '');
|
||||
break
|
||||
}
|
||||
}
|
||||
doclet.name = name;
|
||||
}
|
||||
|
||||
function parseBorrows(doclet, tag) {
|
||||
var m = /^(\S+)(?:\s+as\s+(\S+))?$/.exec(tag.text);
|
||||
if (m) {
|
||||
if (m[1] && m[2]) {
|
||||
return { target: m[1], source: m[2] };
|
||||
}
|
||||
else if (m[1]) {
|
||||
return { target: m[1] };
|
||||
}
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function firstWordOf(string) {
|
||||
var m = /^(\S+)/.exec(string);
|
||||
if (m) { return m[1]; }
|
||||
else { return ''; }
|
||||
}
|
||||
|
||||
@ -6,6 +6,95 @@
|
||||
*/
|
||||
|
||||
|
||||
function parseOptional(type) {
|
||||
var optional = null;
|
||||
|
||||
// {sometype=} means optional
|
||||
if ( /(.+)=$/.test(type) ) {
|
||||
type = RegExp.$1;
|
||||
optional = true;
|
||||
}
|
||||
|
||||
return { type: type, optional: optional };
|
||||
}
|
||||
|
||||
function parseNullable(type) {
|
||||
var nullable = null;
|
||||
|
||||
// {?sometype} means nullable, {!sometype} means not-nullable
|
||||
if ( /^([\?\!])(.+)$/.test(type) ) {
|
||||
type = RegExp.$2;
|
||||
nullable = (RegExp.$1 === '?')? true : false;
|
||||
}
|
||||
|
||||
return { type: type, nullable: nullable };
|
||||
}
|
||||
|
||||
function parseVariable(type) {
|
||||
var variable = null;
|
||||
|
||||
// {...sometype} means variable number of that type
|
||||
if ( /^(\.\.\.)(.+)$/.test(type) ) {
|
||||
type = RegExp.$2;
|
||||
variable = true;
|
||||
}
|
||||
|
||||
return { type: type, variable: variable };
|
||||
}
|
||||
|
||||
function parseTypes(type) {
|
||||
var types = [];
|
||||
|
||||
if ( type.indexOf('|') !== -1 ) {
|
||||
// remove optional parens, like: { ( string | number ) }
|
||||
// see: http://code.google.com/closure/compiler/docs/js-for-compiler.html#types
|
||||
if ( /^\s*\(\s*(.+)\s*\)\s*$/.test(type) ) {
|
||||
type = RegExp.$1;
|
||||
}
|
||||
types = type.split(/\s*\|\s*/g);
|
||||
}
|
||||
else if (type) {
|
||||
types = [type];
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
/** @private */
|
||||
function trim(text) {
|
||||
return text.trim();
|
||||
}
|
||||
|
||||
function getTagType(tagValue) {
|
||||
var type = '',
|
||||
text = '',
|
||||
count = 0;
|
||||
|
||||
// type expressions start with '{'
|
||||
if (tagValue[0] === '{') {
|
||||
count++;
|
||||
|
||||
// find matching closer '}'
|
||||
for (var i = 1, leni = tagValue.length; i < leni; i++) {
|
||||
if (tagValue[i] === '\\') { i++; continue; } // backslash escapes the next character
|
||||
|
||||
if (tagValue[i] === '{') { count++; }
|
||||
else if (tagValue[i] === '}') { count--; }
|
||||
|
||||
if (count === 0) {
|
||||
type = trim(tagValue.slice(1, i))
|
||||
.replace(/\\\{/g, '{') // unescape escaped curly braces
|
||||
.replace(/\\\}/g, '}');
|
||||
text = trim(tagValue.slice(i+1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return { type: type, text: text };
|
||||
}
|
||||
exports.getTagType = getTagType;
|
||||
|
||||
|
||||
/**
|
||||
@param {string} tagValue
|
||||
@returns {object} Hash with type, text, optional, nullable, and variable properties
|
||||
@ -42,91 +131,3 @@ exports.parse = function(tagValue) {
|
||||
variable: variable.variable
|
||||
};
|
||||
}
|
||||
|
||||
function parseOptional(type) {
|
||||
var optional = null;
|
||||
|
||||
// {sometype=} means optional
|
||||
if ( /(.+)=$/.test(type) ) {
|
||||
type = RegExp.$1;
|
||||
optional = true;
|
||||
}
|
||||
|
||||
return { type: type, optional: optional };
|
||||
}
|
||||
|
||||
function parseNullable(type) {
|
||||
var nullable = null;
|
||||
|
||||
// {?sometype} means nullable, {!sometype} means not-nullable
|
||||
if ( /^([\?\!])(.+)$/.test(type) ) {
|
||||
type = RegExp.$2;
|
||||
nullable = (RegExp.$1 === '?')? true : false;
|
||||
}
|
||||
|
||||
return { type: type, nullable: nullable };
|
||||
}
|
||||
|
||||
function parseVariable(type) {
|
||||
var variable = null;
|
||||
|
||||
// {...sometype} means variable number of that type
|
||||
if ( /^(\.\.\.)(.+)$/.test(type) ) {
|
||||
type = RegExp.$2;
|
||||
variable = true;
|
||||
}
|
||||
|
||||
return { type: type, variable: variable };
|
||||
}
|
||||
|
||||
function parseTypes(type) {
|
||||
var types = [];
|
||||
|
||||
if ( type.indexOf('|') !== -1 ) {
|
||||
// remove optional parens, like: { ( string | number ) }
|
||||
// see: http://code.google.com/closure/compiler/docs/js-for-compiler.html#types
|
||||
if ( /^\s*\(\s*(.+)\s*\)\s*$/.test(type) ) {
|
||||
type = RegExp.$1;
|
||||
}
|
||||
types = type.split(/\s*\|\s*/g);
|
||||
}
|
||||
else if (type) {
|
||||
types = [type];
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
function getTagType(tagValue) {
|
||||
var type = '',
|
||||
text = '',
|
||||
count = 0;
|
||||
|
||||
// type expressions start with '{'
|
||||
if (tagValue[0] === '{') {
|
||||
count++;
|
||||
|
||||
// find matching closer '}'
|
||||
for (var i = 1, leni = tagValue.length; i < leni; i++) {
|
||||
if (tagValue[i] === '\\') { i++; continue; } // backslash escapes the next character
|
||||
|
||||
if (tagValue[i] === '{') { count++; }
|
||||
else if (tagValue[i] === '}') { count--; }
|
||||
|
||||
if (count === 0) {
|
||||
type = trim(tagValue.slice(1, i))
|
||||
.replace(/\\\{/g, '{') // unescape escaped curly braces
|
||||
.replace(/\\\}/g, '}');
|
||||
text = trim(tagValue.slice(i+1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return { type: type, text: text };
|
||||
}
|
||||
exports.getTagType = getTagType;
|
||||
|
||||
/** @private */
|
||||
function trim(text) {
|
||||
return text.trim();
|
||||
}
|
||||
|
||||
@ -10,6 +10,24 @@
|
||||
|
||||
var dictionary = require('jsdoc/tag/dictionary');
|
||||
|
||||
function UnknownTagError(tagName, meta) {
|
||||
this.name = 'UnknownTagError';
|
||||
this.message = 'The @' + tagName + ' tag is not a known tag. File: ' + meta.filename + ', Line: ' + meta.lineno + '\n' + meta.comment;
|
||||
}
|
||||
UnknownTagError.prototype = Error.prototype;
|
||||
|
||||
function TagValueRequiredError(tagName, meta) {
|
||||
this.name = 'TagValueRequiredError';
|
||||
this.message = 'The @' + tagName + ' tag requires a value. File: ' + meta.filename + ', Line: ' + meta.lineno + '\n' + meta.comment;
|
||||
}
|
||||
TagValueRequiredError.prototype = Error.prototype;
|
||||
|
||||
function TagValueNotPermittedError(tagName, meta) {
|
||||
this.name = 'TagValueNotPermittedError';
|
||||
this.message = 'The @' + tagName + ' tag does not permit a value. File: ' + meta.filename + ', Line: ' + meta.lineno + '\n' + meta.comment;
|
||||
}
|
||||
TagValueNotPermittedError.prototype = Error.prototype;
|
||||
|
||||
/**
|
||||
Validate the given tag.
|
||||
*/
|
||||
@ -31,22 +49,3 @@ exports.validate = function(tag, meta) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function UnknownTagError(tagName, meta) {
|
||||
this.name = 'UnknownTagError';
|
||||
this.message = 'The @' + tagName + ' tag is not a known tag. File: ' + meta.filename + ', Line: ' + meta.lineno + '\n' + meta.comment;
|
||||
}
|
||||
UnknownTagError.prototype = Error.prototype;
|
||||
|
||||
function TagValueRequiredError(tagName, meta) {
|
||||
this.name = 'TagValueRequiredError';
|
||||
this.message = 'The @' + tagName + ' tag requires a value. File: ' + meta.filename + ', Line: ' + meta.lineno + '\n' + meta.comment;
|
||||
}
|
||||
TagValueRequiredError.prototype = Error.prototype;
|
||||
|
||||
function TagValueNotPermittedError(tagName, meta) {
|
||||
this.name = 'TagValueNotPermittedError';
|
||||
this.message = 'The @' + tagName + ' tag does not permit a value. File: ' + meta.filename + ', Line: ' + meta.lineno + '\n' + meta.comment;
|
||||
}
|
||||
TagValueNotPermittedError.prototype = Error.prototype;
|
||||
|
||||
|
||||
@ -5,18 +5,6 @@
|
||||
@license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
*/
|
||||
|
||||
/**
|
||||
@param {any} object
|
||||
*/
|
||||
exports.dump = function(object) {
|
||||
indentBy = 0;
|
||||
output = '';
|
||||
|
||||
walk(object);
|
||||
outdent(false);
|
||||
return output;
|
||||
}
|
||||
|
||||
const INDENTATION = ' '; // 4 spaces
|
||||
var indentBy,
|
||||
output;
|
||||
@ -62,6 +50,45 @@ seen.has = function(object) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function stringify(o) {
|
||||
return JSON.stringify(o);
|
||||
}
|
||||
|
||||
function getValue(o) { // see: https://developer.mozilla.org/en/JavaScript/Reference/Operators/Special/typeof
|
||||
if (o === null) { return 'null'; }
|
||||
if ( /^(string|boolean|number|undefined)$/.test(typeof o) ) {
|
||||
return ''+stringify(o);
|
||||
}
|
||||
}
|
||||
|
||||
function isUnwalkable(o) { // some objects are unwalkable, like Java native objects
|
||||
return (typeof o === 'object' && typeof o.constructor === 'undefined');
|
||||
}
|
||||
|
||||
function isArray(o) {
|
||||
return o && (o instanceof Array) || o.constructor === Array;
|
||||
}
|
||||
|
||||
function isRegExp(o) {
|
||||
return (o instanceof RegExp) ||
|
||||
(typeof o.constructor !== 'undefined' && o.constructor.name === 'RegExp');
|
||||
}
|
||||
|
||||
function isDate(o) {
|
||||
return o && (o instanceof Date) ||
|
||||
(typeof o.constructor !== 'undefined' && o.constructor.name === 'Date');
|
||||
}
|
||||
|
||||
function isFunction(o) {
|
||||
return o && (typeof o === 'function' || o instanceof Function);// ||
|
||||
//(typeof o.constructor !== 'undefined' && (o.constructor||{}).name === 'Function');
|
||||
}
|
||||
|
||||
function isObject(o) {
|
||||
return o && o instanceof Object ||
|
||||
(typeof o.constructor !== 'undefined' && o.constructor.name === 'Object');
|
||||
}
|
||||
|
||||
function walk(object) {
|
||||
var value;
|
||||
|
||||
@ -116,42 +143,14 @@ function walk(object) {
|
||||
}
|
||||
}
|
||||
|
||||
function getValue(o) { // see: https://developer.mozilla.org/en/JavaScript/Reference/Operators/Special/typeof
|
||||
if (o === null) { return 'null'; }
|
||||
if ( /^(string|boolean|number|undefined)$/.test(typeof o) ) {
|
||||
return ''+stringify(o);
|
||||
}
|
||||
/**
|
||||
@param {any} object
|
||||
*/
|
||||
exports.dump = function(object) {
|
||||
indentBy = 0;
|
||||
output = '';
|
||||
|
||||
walk(object);
|
||||
outdent(false);
|
||||
return output;
|
||||
}
|
||||
|
||||
function stringify(o) {
|
||||
return JSON.stringify(o);
|
||||
}
|
||||
|
||||
function isUnwalkable(o) { // some objects are unwalkable, like Java native objects
|
||||
return (typeof o === 'object' && typeof o.constructor === 'undefined');
|
||||
}
|
||||
|
||||
function isArray(o) {
|
||||
return o && (o instanceof Array) || o.constructor === Array;
|
||||
}
|
||||
|
||||
function isRegExp(o) {
|
||||
return (o instanceof RegExp) ||
|
||||
(typeof o.constructor !== 'undefined' && o.constructor.name === 'RegExp');
|
||||
}
|
||||
|
||||
function isDate(o) {
|
||||
return o && (o instanceof Date) ||
|
||||
(typeof o.constructor !== 'undefined' && o.constructor.name === 'Date');
|
||||
}
|
||||
|
||||
function isFunction(o) {
|
||||
return o && (typeof o === 'function' || o instanceof Function);// ||
|
||||
//(typeof o.constructor !== 'undefined' && (o.constructor||{}).name === 'Function');
|
||||
}
|
||||
|
||||
function isObject(o) {
|
||||
return o && o instanceof Object ||
|
||||
(typeof o.constructor !== 'undefined' && o.constructor.name === 'Object');
|
||||
}
|
||||
|
||||
|
||||
@ -5,59 +5,23 @@
|
||||
var hash = require('pajhome/hash');
|
||||
var dictionary = require('jsdoc/tag/dictionary');
|
||||
|
||||
exports.globalName = 'global';
|
||||
exports.fileExtension = '.html';
|
||||
|
||||
/** Find symbol {@link ...} and {@tutorial ...} strings in text and turn into html links */
|
||||
exports.resolveLinks = function(str) {
|
||||
str = str.replace(/(?:\[(.+?)\])?\{@link +(.+?)\}/gi,
|
||||
function(match, content, longname) {
|
||||
return toLink(longname, content);
|
||||
}
|
||||
);
|
||||
|
||||
str = str.replace(/(?:\[(.+?)\])?\{@tutorial +(.+?)\}/gi,
|
||||
function(match, content, tutorial) {
|
||||
return toTutorial(tutorial, content);
|
||||
}
|
||||
);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
// two-way lookup
|
||||
var linkMap = {
|
||||
longnameToUrl: {},
|
||||
urlToLongname: {}
|
||||
};
|
||||
|
||||
exports.registerLink = function(longname, url) {
|
||||
linkMap.longnameToUrl[longname] = url;
|
||||
linkMap.urlToLongname[url] = longname;
|
||||
}
|
||||
var files = {};
|
||||
|
||||
// each container gets its own html file
|
||||
var containers = ['class', 'module', 'external', 'namespace', 'mixin'];
|
||||
|
||||
/** Turn a doclet into a URL. */
|
||||
exports.createLink = function(doclet) {
|
||||
var url = '';
|
||||
|
||||
if (containers.indexOf(doclet.kind) < 0) {
|
||||
var longname = doclet.longname,
|
||||
filename = strToFilename(doclet.memberof || exports.globalName);
|
||||
|
||||
url = filename + exports.fileExtension + '#' + getNamespace(doclet.kind) + doclet.name;
|
||||
}
|
||||
else {
|
||||
var longname = doclet.longname,
|
||||
filename = strToFilename(longname);
|
||||
|
||||
url = filename + exports.fileExtension;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
/** @external {jsdoc.tutorial.Tutorial} */
|
||||
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';
|
||||
|
||||
function getNamespace(kind) {
|
||||
if (dictionary.isNamespace(kind)) {
|
||||
@ -66,6 +30,15 @@ function getNamespace(kind) {
|
||||
return '';
|
||||
}
|
||||
|
||||
function makeFilenameUnique(filename, str) {
|
||||
//add suffix underscore until filename gets unique
|
||||
while (filename in files && files[filename] !== str) {
|
||||
filename += '_';
|
||||
}
|
||||
files[filename] = str;
|
||||
return filename;
|
||||
}
|
||||
|
||||
// compute it here just once
|
||||
var nsprefix = /^(event|module|external):/;
|
||||
|
||||
@ -79,15 +52,15 @@ function strToFilename(str) {
|
||||
return makeFilenameUnique(basename, str);
|
||||
}
|
||||
|
||||
var files = {};
|
||||
// two-way lookup
|
||||
var linkMap = {
|
||||
longnameToUrl: {},
|
||||
urlToLongname: {}
|
||||
};
|
||||
|
||||
function makeFilenameUnique(filename, str) {
|
||||
//add suffix underscore until filename gets unique
|
||||
while (filename in files && files[filename] !== str) {
|
||||
filename += '_';
|
||||
}
|
||||
files[filename] = str;
|
||||
return filename;
|
||||
exports.registerLink = function(longname, url) {
|
||||
linkMap.longnameToUrl[longname] = url;
|
||||
linkMap.urlToLongname[url] = longname;
|
||||
}
|
||||
|
||||
function toLink(longname, content) {
|
||||
@ -121,16 +94,6 @@ function toLink(longname, content) {
|
||||
}
|
||||
}
|
||||
|
||||
/** @external {jsdoc.tutorial.Tutorial} */
|
||||
var tutorials;
|
||||
|
||||
/** Sets tutorials map.
|
||||
@param {jsdoc.tutorial.Tutorial} root - Root tutorial node.
|
||||
*/
|
||||
exports.setTutorials = function(root) {
|
||||
tutorials = root;
|
||||
};
|
||||
|
||||
var toTutorial = exports.toTutorial = function(tutorial, content) {
|
||||
if (!tutorial) {
|
||||
throw new Error('Missing required parameter: tutorial');
|
||||
@ -147,6 +110,43 @@ var toTutorial = exports.toTutorial = function(tutorial, content) {
|
||||
return '<a href="'+exports.tutorialToUrl(tutorial)+'">'+content+'</a>';
|
||||
}
|
||||
|
||||
/** Find symbol {@link ...} and {@tutorial ...} strings in text and turn into html links */
|
||||
exports.resolveLinks = function(str) {
|
||||
str = str.replace(/(?:\[(.+?)\])?\{@link +(.+?)\}/gi,
|
||||
function(match, content, longname) {
|
||||
return toLink(longname, content);
|
||||
}
|
||||
);
|
||||
|
||||
str = str.replace(/(?:\[(.+?)\])?\{@tutorial +(.+?)\}/gi,
|
||||
function(match, content, tutorial) {
|
||||
return toTutorial(tutorial, content);
|
||||
}
|
||||
);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/** Turn a doclet into a URL. */
|
||||
exports.createLink = function(doclet) {
|
||||
var url = '';
|
||||
|
||||
if (containers.indexOf(doclet.kind) < 0) {
|
||||
var longname = doclet.longname,
|
||||
filename = strToFilename(doclet.memberof || exports.globalName);
|
||||
|
||||
url = filename + exports.fileExtension + '#' + getNamespace(doclet.kind) + doclet.name;
|
||||
}
|
||||
else {
|
||||
var longname = doclet.longname,
|
||||
filename = strToFilename(longname);
|
||||
|
||||
url = filename + exports.fileExtension;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
exports.longnameToUrl = linkMap.longnameToUrl;
|
||||
|
||||
exports.tutorialToUrl = function(tutorial) {
|
||||
|
||||
@ -381,6 +381,20 @@
|
||||
// once for all
|
||||
view.nav = nav;
|
||||
|
||||
function generate(title, docs, filename) {
|
||||
var data = {
|
||||
title: title,
|
||||
docs: docs
|
||||
};
|
||||
|
||||
var path = outdir + '/' + filename,
|
||||
html = view.render('container.tmpl', data);
|
||||
|
||||
html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a>
|
||||
|
||||
fs.writeFileSync(path, html)
|
||||
}
|
||||
|
||||
for (var longname in helper.longnameToUrl) {
|
||||
if ( hasOwnProp.call(helper.longnameToUrl, longname) ) {
|
||||
var classes = find({kind: 'class', longname: longname});
|
||||
@ -416,20 +430,6 @@
|
||||
, 'index.html');
|
||||
|
||||
|
||||
function generate(title, docs, filename) {
|
||||
var data = {
|
||||
title: title,
|
||||
docs: docs
|
||||
};
|
||||
|
||||
var path = outdir + '/' + filename,
|
||||
html = view.render('container.tmpl', data);
|
||||
|
||||
html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a>
|
||||
|
||||
fs.writeFileSync(path, html)
|
||||
}
|
||||
|
||||
function generateTutorial(title, tutorial, filename) {
|
||||
var data = {
|
||||
title: title,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user