diff --git a/.jshintrc b/.jshintrc index 44926e14..8d076fa4 100644 --- a/.jshintrc +++ b/.jshintrc @@ -4,7 +4,7 @@ "eqeqeq": false, "forin": true, "immed": true, - "latedef": false, + "latedef": true, "newcap": true, "noarg": true, "noempty": false, diff --git a/jsdoc.js b/jsdoc.js index 8ac91a39..b5408f33 100644 --- a/jsdoc.js +++ b/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(); } diff --git a/rhino_modules/fs.js b/rhino_modules/fs.js index 8d085f79..2dec03be 100644 --- a/rhino_modules/fs.js +++ b/rhino_modules/fs.js @@ -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'; diff --git a/rhino_modules/jsdoc/config.js b/rhino_modules/jsdoc/config.js index 473da480..9b5bcb0d 100644 --- a/rhino_modules/jsdoc/config.js +++ b/rhino_modules/jsdoc/config.js @@ -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. */ diff --git a/rhino_modules/jsdoc/doclet.js b/rhino_modules/jsdoc/doclet.js index af46b669..66711e54 100644 --- a/rhino_modules/jsdoc/doclet.js +++ b/rhino_modules/jsdoc/doclet.js @@ -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; -} diff --git a/rhino_modules/jsdoc/readme.js b/rhino_modules/jsdoc/readme.js index bbd98a85..ee09395a 100644 --- a/rhino_modules/jsdoc/readme.js +++ b/rhino_modules/jsdoc/readme.js @@ -12,35 +12,9 @@ @author Ben Blank */ -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; diff --git a/rhino_modules/jsdoc/src/handlers.js b/rhino_modules/jsdoc/src/handlers.js index 06ef880a..0339be3a 100644 --- a/rhino_modules/jsdoc/src/handlers.js +++ b/rhino_modules/jsdoc/src/handlers.js @@ -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; diff --git a/rhino_modules/jsdoc/src/parser.js b/rhino_modules/jsdoc/src/parser.js index 5ba735c9..c128c9c8 100644 --- a/rhino_modules/jsdoc/src/parser.js +++ b/rhino_modules/jsdoc/src/parser.js @@ -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 diff --git a/rhino_modules/jsdoc/tag.js b/rhino_modules/jsdoc/tag.js index 583862df..f4a83c50 100644 --- a/rhino_modules/jsdoc/tag.js +++ b/rhino_modules/jsdoc/tag.js @@ -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.} [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.} [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 }; -} diff --git a/rhino_modules/jsdoc/tag/dictionary.js b/rhino_modules/jsdoc/tag/dictionary.js index 61cfe122..a93b9dba 100644 --- a/rhino_modules/jsdoc/tag/dictionary.js +++ b/rhino_modules/jsdoc/tag/dictionary.js @@ -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); diff --git a/rhino_modules/jsdoc/tag/dictionary/definitions.js b/rhino_modules/jsdoc/tag/dictionary/definitions.js index cb4db489..ae2446d5 100644 --- a/rhino_modules/jsdoc/tag/dictionary/definitions.js +++ b/rhino_modules/jsdoc/tag/dictionary/definitions.js @@ -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 !== '') { + 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 */ @@ -561,88 +646,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 !== '') { - 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 ''; } -} diff --git a/rhino_modules/jsdoc/tag/type.js b/rhino_modules/jsdoc/tag/type.js index d799bad9..2c73a098 100644 --- a/rhino_modules/jsdoc/tag/type.js +++ b/rhino_modules/jsdoc/tag/type.js @@ -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(); -} diff --git a/rhino_modules/jsdoc/tag/validator.js b/rhino_modules/jsdoc/tag/validator.js index bb4560cc..13dfb326 100644 --- a/rhino_modules/jsdoc/tag/validator.js +++ b/rhino_modules/jsdoc/tag/validator.js @@ -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; - diff --git a/rhino_modules/jsdoc/util/dumper.js b/rhino_modules/jsdoc/util/dumper.js index 9392401a..230fecae 100644 --- a/rhino_modules/jsdoc/util/dumper.js +++ b/rhino_modules/jsdoc/util/dumper.js @@ -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'); -} - diff --git a/rhino_modules/jsdoc/util/templateHelper.js b/rhino_modules/jsdoc/util/templateHelper.js index c32a20de..036a50d8 100644 --- a/rhino_modules/jsdoc/util/templateHelper.js +++ b/rhino_modules/jsdoc/util/templateHelper.js @@ -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 ''+content+''; } +/** 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) { diff --git a/templates/default/publish.js b/templates/default/publish.js index 7081ee7c..58a0ba12 100644 --- a/templates/default/publish.js +++ b/templates/default/publish.js @@ -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 foo + + 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 foo - - fs.writeFileSync(path, html) - } - function generateTutorial(title, tutorial, filename) { var data = { title: title,