diff --git a/jsdoc b/jsdoc index 968a60af..509b480e 100755 --- a/jsdoc +++ b/jsdoc @@ -3,6 +3,6 @@ # rhino discards the path to the current script file, so we must add it back PWD=`pwd` BASEDIR=`dirname $0` -java -classpath ${BASEDIR}/lib/js.jar org.mozilla.javascript.tools.shell.Main ${BASEDIR}/jsdoc.js --dirname=${PWD}/${BASEDIR} $@ +java -classpath ${BASEDIR}/lib/js.jar org.mozilla.javascript.tools.shell.Main -modules ${BASEDIR}/node_modules -modules ${BASEDIR}/rhino_modules ${BASEDIR}/jsdoc.js --dirname=${PWD}/${BASEDIR} $@ #java -classpath ${BASEDIR}/lib/js.jar org.mozilla.javascript.tools.debugger.Main -debug ${BASEDIR}/jsdoc.js --dirname=${PWD}/${BASEDIR} $@ \ No newline at end of file diff --git a/jsdoc.js b/jsdoc.js index a29cf364..180551dd 100644 --- a/jsdoc.js +++ b/jsdoc.js @@ -30,7 +30,6 @@ for (var i = 0; i < arguments.length; i++) { } } -load(__dirname + '/lib/require.js'); load(__dirname + '/lib/rhino-shim.js'); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// diff --git a/lib/require.js b/lib/require.js deleted file mode 100644 index 10432706..00000000 --- a/lib/require.js +++ /dev/null @@ -1,222 +0,0 @@ -/* - Rhino-Require is Public Domain - - - The author or authors of this code dedicate any and all copyright interest - in this code to the public domain. We make this dedication for the benefit - of the public at large and to the detriment of our heirs and successors. We - intend this dedication to be an overt act of relinquishment in perpetuity of - all present and future rights to this code under copyright law. - */ - -(function(global) { - - var require = global.require = function(id) { - if (typeof arguments[0] !== 'string') throw 'USAGE: require(moduleId)'; - - var moduleContent = '', - moduleUrl; - - moduleUrl = require.resolve(id); - moduleContent = ''; - - var file = new java.io.File(moduleUrl); - try { - var scanner = new java.util.Scanner(file).useDelimiter("\\Z"); - moduleContent = String( scanner.next() ); - } - catch(e) { - throw 'Unable to read file at: '+moduleUrl+', '+e; - } - - if (moduleContent) { - try { - var f = new Function('require', 'exports', 'module', '__dirname', moduleContent), - exports = require.cache[moduleUrl] || {}, - module = { id: id, uri: moduleUrl, exports: exports }; - - require._root.unshift(toDir(moduleUrl)); - (function(__dirname) { - - /*debug*///var lineno=1;print('\n== '+moduleUrl+' ===============\n1'+moduleContent.replace(/(\n)/g, function(m, i){return '\n'+(++lineno);})); - f.call({}, require, exports, module, __dirname); - })(require._root[0]); - require._root.shift(); - } - catch(e) { - throw 'Unable to require source code from "' + moduleUrl + '": ' + e.toSource(); - } - - exports = module.exports || exports; - require.cache[id] = exports; - } - else { - throw 'The requested module cannot be returned: no content for id: "' + id + '" in paths: ' + require.paths.join(', '); - } - - return exports; - } - require._root = [__dirname]; // the dir of the script that is calling require() - require.paths = []; - require.cache = {}; // cache module exports. Like: {id: exported} - - var SLASH = Packages.java.io.File.separator; - - /** Given a module id, try to find the path to the associated module. - */ - require.resolve = function(id) { - var parts = id.match(/^(\.\/|\/)?(.+)$/), - isRelative = false, - isAbsolute = false, - isInModule = false, - basename = id, - url = ''; - - if (parts) { - isRelative = parts[1] === './'; - isAbsolute = parts[1] === '/'; - isInModule = !(isRelative || isAbsolute); - basename = parts[2]; - } - - if (typeof basename === 'undefined') { - throw new Error('Malformed module identifier: '+id); - } - - if (isAbsolute) { - rootedId = id; - } - else if (isRelative) { - var root = require._root[0], - rootedId = root + '/' + basename; - } - - if (rootedId) { - if ( url = loadAsFile(rootedId) ) { return url; } - else if ( url = loadAsDir(rootedId) ) { return url; } - } - else if (isInModule) { - var url, - paths = require.paths; - - for (var i = 0, len = paths.length; i < len; i++) { - rootedId = paths[i] + '/' + basename; - - if ( url = loadAsFile(rootedId) ) { return url; } - else if ( url = loadAsDir(rootedId) ) { return url; } - } - if (url = findInNodemodules(require._root[0], basename, 'rhino_modules')) { return url; } - if (url = findInNodemodules(require._root[0], basename, 'node_modules')) { return url; } - } - - throw new Error('Module not found: '+id); - } - - function loadAsFile(id) { - if ( isFile(id) ) { return id; } - - if ( isFile(id + '.js') ) { return id + '.js'; } - } - - function loadAsDir(id) { - // look for the "main" property of the package.json file - if ( isFile(id + '/' + 'package.json') ) { - var packageJson = readFileSync(id + '/' + 'package.json', 'utf-8'); - eval( 'packageJson = '+ packageJson); - if (packageJson.hasOwnProperty('main')) { - var main = deDotPath(id + '/' + packageJson.main); - return require.resolve(main); - } - } - - if ( isFile(id + '/' + 'index.js') ) { - return id + '/' + 'index.js'; - } - } - - function findInNodemodules(root, id, moduleFolderName) { - var dirs = root.split('/'), - dir = '', - rootedId; - - while (dirs.length) { - dir = dirs.join('/'); - rootedId = dir + '/' + moduleFolderName + '/' + id; - - if ( url = loadAsFile(rootedId) ) { return url; } - else if ( url = loadAsDir(rootedId) ) { return url; } - - dirs.pop(); - } - } - - /** Given a path, return the base directory of that path. - @example toDir('/foo/bar/somefile.js'); => '/foo/bar' - */ - function toDir(path) { - var file = new java.io.File(path); - - if (file.isDirectory()) { - return path; - } - - var parts = path.split('/'); - parts.pop(); - return parts.join('/'); - } - - /** Returns true if the given path exists and is a file. - */ - function isFile(path) { - var file = new java.io.File(path); - - if (file.isFile()) { - return true; - } - - return false; - } - - /** Returns true if the given path exists and is a directory. - */ - function isDir(path) { - var file = new java.io.File(path); - - if (file.isDirectory()) { - return true; - } - - return false; - } - - /** - Resolve dots in filepaths. - */ - function deDotPath(path) { - return String(path) - .replace(/(\/|\\)[^\/\\]+\/\.\.(\/|\\)/g, '/') - .replace(/(\/|\\)\.(\/|\\|$)/g, '/'); - } - - function readFileSync(filename, encoding, callback) { - if (typeof arguments[1] === 'function') { - encoding = null; - callback = arguments[1]; - } - - encoding = encoding || java.lang.System.getProperty('file.encoding'); - - try { - var content = new java.util.Scanner( - new java.io.File(filename), - encoding - ).useDelimiter("\\Z"); - - return String( content.next() ); - } - catch (e) { - return ''; - } - } - -})(this); \ No newline at end of file diff --git a/rhino_modules/fs/index.js b/rhino_modules/fs.js similarity index 85% rename from rhino_modules/fs/index.js rename to rhino_modules/fs.js index 2cc5e18d..8022dd6e 100644 --- a/rhino_modules/fs/index.js +++ b/rhino_modules/fs.js @@ -1,10 +1,10 @@ -function readFileSync(filename, encoding) { +exports.readFileSync = function(filename, encoding) { encoding = encoding || 'utf-8'; return readFile(filename, encoding); -} +}; -function readdirSync(path) { +var readdirSync = exports.readdirSync = function(path) { var dir, files; @@ -14,9 +14,9 @@ function readdirSync(path) { files = dir.list(); return files; -} +}; -function ls(dir, recurse, _allFiles, _path) { +var ls = exports.ls = function(dir, recurse, _allFiles, _path) { var files, file; @@ -56,9 +56,9 @@ function ls(dir, recurse, _allFiles, _path) { } return _allFiles; -} +}; -function stat(path, encoding) { +var stat = exports.stat = function(path, encoding) { var f = new java.io.File(path) return { isFile: function() { @@ -69,9 +69,9 @@ function stat(path, encoding) { } } -} +}; -function mkPath(/**Array*/ 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++) { @@ -80,7 +80,7 @@ function mkPath(/**Array*/ path) { makeDir(make); } } -} +}; function makeDir(/**string*/ path) { var dirPath = toDir(path); @@ -102,7 +102,7 @@ function exists(path) { return true; } -function toDir(path) { +var toDir = exports.toDir = function(path) { var f = new java.io.File(path); if (f.isDirectory()){ @@ -113,9 +113,9 @@ function toDir(path) { parts.pop(); return parts.join('/'); -} +}; -function copyFile(inFile, outDir, fileName) { +exports.copyFile = function(inFile, outDir, fileName) { if (fileName == null) fileName = toFile(inFile); outDir = toDir(outDir); @@ -131,14 +131,14 @@ function copyFile(inFile, outDir, fileName) { } bos.close(); bis.close(); -} +}; function toFile(path) { var parts = path.split(/[\\\/]/); return parts.pop(); } -function writeFileSync(filename, data, encoding) { +exports.writeFileSync = function(filename, data, encoding) { encoding = encoding || 'utf-8'; var out = new Packages.java.io.PrintWriter( @@ -155,16 +155,4 @@ function writeFileSync(filename, data, encoding) { out.flush(); out.close(); } -} - -module.exports = { - readFileSync: readFileSync, - writeFileSync: writeFileSync, - readdirSync: readdirSync, - stat: stat, - - ls: ls, - mkPath: mkPath, - toDir: toDir, - copyFile: copyFile -}; \ No newline at end of file +}; diff --git a/rhino_modules/jsdoc/borrow.js b/rhino_modules/jsdoc/borrow.js index e2f40266..90f689dc 100644 --- a/rhino_modules/jsdoc/borrow.js +++ b/rhino_modules/jsdoc/borrow.js @@ -4,67 +4,64 @@ @author Michael Mathews @license Apache License 2.0 - See file 'LICENSE.md' in this project. */ -(function() { - // requires docs to have been indexed: docs.index must be defined here - /** - Take a copy of the docs for borrowed symbols and attach them to the - docs for the borrowing symbol. This process changes the symbols involved, - moving docs from the "borrowed" array and into the general docs, then - deleting the "borrowed" array. - */ - exports.resolveBorrows = function(docs) { - if (!docs.index) { - throw 'Docs has not been indexed: docs.index must be defined here.'; - } - - docs.forEach(function(doc) { - if (doc.borrowed) { - doc.borrowed.forEach(function(b, i) { - var lent = docs.index[b.from], // lent is an array - asName = b['as'] || b.from; - - if (lent) { - var cloned = doop(lent); - - cloned.forEach(function(clone) { - asName = asName.replace(/^prototype\./, '#'); - var parts = asName.split('#'); - - if (parts.length === 2) clone.scope = 'instance'; - else clone.scope = 'static'; - - asName = parts.pop(); - clone.name = asName; - clone.memberof = doc.longname; - clone.longname = clone.memberof + (clone.scope === 'instance'? '#': '.') + clone.name; - docs.push(clone); - }); - - } - }); - - delete doc.borrowed; - } - }); +// requires docs to have been indexed: docs.index must be defined here +/** + Take a copy of the docs for borrowed symbols and attach them to the + docs for the borrowing symbol. This process changes the symbols involved, + moving docs from the "borrowed" array and into the general docs, then + deleting the "borrowed" array. + */ +exports.resolveBorrows = function(docs) { + if (!docs.index) { + throw 'Docs has not been indexed: docs.index must be defined here.'; } - /** - Deep clone a simple object. - @private - */ - function doop(o) { - if (o instanceof Object && o.constructor != Function) { - var clone = o instanceof Array ? [] : {}, prop; - - for (prop in o){ - if ( o.hasOwnProperty(prop) ) { - clone[prop] = (o[prop] instanceof Object)? doop(o[prop]) : o[prop]; + docs.forEach(function(doc) { + if (doc.borrowed) { + doc.borrowed.forEach(function(b, i) { + var lent = docs.index[b.from], // lent is an array + asName = b['as'] || b.from; + + if (lent) { + var cloned = doop(lent); + + cloned.forEach(function(clone) { + asName = asName.replace(/^prototype\./, '#'); + var parts = asName.split('#'); + + if (parts.length === 2) clone.scope = 'instance'; + else clone.scope = 'static'; + + asName = parts.pop(); + clone.name = asName; + clone.memberof = doc.longname; + clone.longname = clone.memberof + (clone.scope === 'instance'? '#': '.') + clone.name; + docs.push(clone); + }); + } - } - return clone; + }); + + delete doc.borrowed; } - return o; - }; - -})(); \ No newline at end of file + }); +} + +/** + Deep clone a simple object. + @private + */ +function doop(o) { + if (o instanceof Object && o.constructor != Function) { + var clone = o instanceof Array ? [] : {}, prop; + + for (prop in o){ + if ( o.hasOwnProperty(prop) ) { + clone[prop] = (o[prop] instanceof Object)? doop(o[prop]) : o[prop]; + } + } + return clone; + } + return o; +}; diff --git a/rhino_modules/jsdoc/doclet.js b/rhino_modules/jsdoc/doclet.js index b97e5bc8..66dd1177 100644 --- a/rhino_modules/jsdoc/doclet.js +++ b/rhino_modules/jsdoc/doclet.js @@ -10,298 +10,296 @@ @requires jsdoc/name @requires jsdoc/tag/dictionary */ -(function() { - var jsdoc = { - tag: { - Tag: require('jsdoc/tag').Tag, - dictionary: require('jsdoc/tag/dictionary') - }, - name: require('jsdoc/name') - }; - - /** - @class - @classdesc Represents a single JSDoc comment. - @param {string} docletSrc - The raw source code of the jsdoc comment. - @param {object=} meta - Properties describing the code related to this comment. - */ - exports.Doclet = function(docletSrc, meta) { - var newTags = []; - - /** The original text of the comment from the source code. */ - this.comment = docletSrc; - this.setMeta(meta); - - docletSrc = unwrap(docletSrc); - docletSrc = fixDescription(docletSrc); - newTags = toTags.call(this, docletSrc); +var jsdoc = { + tag: { + Tag: require('jsdoc/tag').Tag, + dictionary: require('jsdoc/tag/dictionary') + }, + name: require('jsdoc/name') +}; + +/** + @class + @classdesc Represents a single JSDoc comment. + @param {string} docletSrc - The raw source code of the jsdoc comment. + @param {object=} meta - Properties describing the code related to this comment. + */ +exports.Doclet = function(docletSrc, meta) { + var newTags = []; + + /** The original text of the comment from the source code. */ + this.comment = docletSrc; + this.setMeta(meta); + + docletSrc = unwrap(docletSrc); + docletSrc = fixDescription(docletSrc); - for (var i = 0, leni = newTags.length; i < leni; i++) { - this.addTag(newTags[i].title, newTags[i].text); - } - - this.postProcess(); - } - - /** Called once after all tags have been added. */ - exports.Doclet.prototype.postProcess = function() { - if (!this.preserveName) { jsdoc.name.resolve(this); } - if (this.name && !this.longname) { - this.setLongname(this.name); - } - if (this.memberof === '') { - delete(this.memberof); - } - if (!this.kind && this.meta && this.meta.code) { - this.addTag( 'kind', codetypeToKind(this.meta.code.type) ); - } - } - - /** Add a tag to this doclet. - @param {string} title - The title of the tag being added. - @param {string} [text] - The text of the tag being added. - */ - exports.Doclet.prototype.addTag = function(title, text) { - var tagDef = jsdoc.tag.dictionary.lookUp(title), - newTag = new jsdoc.tag.Tag(title, text, this.meta); + newTags = toTags.call(this, docletSrc); - if (tagDef && tagDef.onTagged) { - tagDef.onTagged(this, newTag) - } - - if (!tagDef) { - this.tags = this.tags || []; - this.tags.push(newTag); - } - - applyTag.call(this, newTag); - } - - /** Set the `memberof` property of this doclet. - @param {string} sid - The longname of the symbol that this doclet is a member of. - */ - exports.Doclet.prototype.setMemberof = function(sid) { - if (/^\.?/.test(sid)) { sid = sid.replace(/^.?/, ''); } - /** - The longname of the symbol that contains this one, if any. - @type string - */ - this.memberof = sid.replace(/\.prototype/g, '#'); - } - - /** Set the `longname` property of this doclet. - @param {string} name - */ - exports.Doclet.prototype.setLongname = function(name) { - if (/^\.?/.test(name)) { name = name.replace(/^\.?/, ''); } - - /** - The fully resolved symbol name. - @type string - */ - this.longname = name; - if (jsdoc.tag.dictionary.isNamespace(this.kind)) { - this.longname = jsdoc.name.applyNamespace(this.longname, this.kind); - } - } - - /** Add a symbol to this doclet's `borrowed` array. - @param {string} source - The longname of the symbol that is the source. - @param {string} target - The name the symbol is being assigned to. - */ - exports.Doclet.prototype.borrow = function(source, target) { - var about = {from: source}; - if (target) about.as = target; - - if (!this.borrowed) { - /** - A list of symbols that are borrowed by this one, if any. - @type Array. - */ - this.borrowed = []; - } - this.borrowed.push(about); - } - - exports.Doclet.prototype.mix = function(source) { - if (!this.mixes) { - /** - A list of symbols that are mixed into this one, if any. - @type Array. - */ - this.mixes = []; - } - this.mixes.push(source); - } - - /** Add a symbol to this doclet's `augments` array. - @param {string} base - The longname of the base symbol. - */ - exports.Doclet.prototype.augment = function(base) { - if (!this.augments) { - /** - A list of symbols that are augmented by this one, if any. - @type Array. - */ - this.augments = []; - } - this.augments.push(base); - } - - /** - Set the `meta` property of this doclet. - @param {object} meta - */ - exports.Doclet.prototype.setMeta = function(meta) { - if (!this.meta) { - /** - Information about the source code associated with this doclet. - @namespace - */ - this.meta = {}; - } - - if (meta.lineno) { - /** - The line number of the code associated with this doclet. - @type number - */ - this.meta.lineno = meta.lineno; - } - - if (meta.lineno) { - /** - The name of the file containing the code associated with this doclet. - @type string - */ - this.meta.filename = meta.filename; - } - - /** - Information about the code symbol. - @namespace - */ - this.meta.code = (this.meta.code || {}); - if (meta.id) this.meta.code.id = meta.id; - if (meta.code) { - if (meta.code.name) { - /** The name of the symbol in the source code. */ - this.meta.code.name = meta.code.name; - } - if (meta.code.type) { - /** The type of the symbol in the source code. */ - this.meta.code.type = meta.code.type; - } - if (meta.code.node) { - this.meta.code.node = meta.code.node; - } - if (meta.code.funcscope) { - this.meta.code.funcscope = meta.code.funcscope; - } - if (meta.code.value) { - /** The value of the symbol in the source code. */ - this.meta.code.value = meta.code.value; - } - } - } - - 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 'property'; - } - - return kind; + for (var i = 0, leni = newTags.length; i < leni; i++) { + this.addTag(newTags[i].title, newTags[i].text); } - - /** - 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 each(tagSrc in tagSrcs) { - tags.push( {title: tagSrc.title, text: tagSrc.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 + + this.postProcess(); +} - return docletSrc; - } - - function fixDescription(docletSrc) { - if (!/^\s*@/.test(docletSrc)) { - docletSrc = '@description ' + docletSrc; - } - return docletSrc; - } - - function split(docletSrc) { - var tagSrcs = []; - - // 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) { - var [, tagTitle, tagText] = parsedTag; +/** Called once after all tags have been added. */ +exports.Doclet.prototype.postProcess = function() { + if (!this.preserveName) { jsdoc.name.resolve(this); } + if (this.name && !this.longname) { + this.setLongname(this.name); + } + if (this.memberof === '') { + delete(this.memberof); + } + if (!this.kind && this.meta && this.meta.code) { + this.addTag( 'kind', codetypeToKind(this.meta.code.type) ); + } +} - if (tagTitle) { - tagSrcs.push({ - title: tagTitle, - text: tagText - }); - } +/** Add a tag to this doclet. + @param {string} title - The title of the tag being added. + @param {string} [text] - The text of the tag being added. +*/ +exports.Doclet.prototype.addTag = function(title, text) { + var tagDef = jsdoc.tag.dictionary.lookUp(title), + newTag = new jsdoc.tag.Tag(title, text, this.meta); + + if (tagDef && tagDef.onTagged) { + tagDef.onTagged(this, newTag) + } + + if (!tagDef) { + this.tags = this.tags || []; + this.tags.push(newTag); + } + + applyTag.call(this, newTag); +} + +/** Set the `memberof` property of this doclet. + @param {string} sid - The longname of the symbol that this doclet is a member of. +*/ +exports.Doclet.prototype.setMemberof = function(sid) { + if (/^\.?/.test(sid)) { sid = sid.replace(/^.?/, ''); } + /** + The longname of the symbol that contains this one, if any. + @type string + */ + this.memberof = sid.replace(/\.prototype/g, '#'); +} + +/** Set the `longname` property of this doclet. + @param {string} name +*/ +exports.Doclet.prototype.setLongname = function(name) { + if (/^\.?/.test(name)) { name = name.replace(/^\.?/, ''); } + + /** + The fully resolved symbol name. + @type string + */ + this.longname = name; + if (jsdoc.tag.dictionary.isNamespace(this.kind)) { + this.longname = jsdoc.name.applyNamespace(this.longname, this.kind); + } +} + +/** Add a symbol to this doclet's `borrowed` array. + @param {string} source - The longname of the symbol that is the source. + @param {string} target - The name the symbol is being assigned to. +*/ +exports.Doclet.prototype.borrow = function(source, target) { + var about = {from: source}; + if (target) about.as = target; + + if (!this.borrowed) { + /** + A list of symbols that are borrowed by this one, if any. + @type Array. + */ + this.borrowed = []; + } + this.borrowed.push(about); +} + +exports.Doclet.prototype.mix = function(source) { + if (!this.mixes) { + /** + A list of symbols that are mixed into this one, if any. + @type Array. + */ + this.mixes = []; + } + this.mixes.push(source); +} + +/** Add a symbol to this doclet's `augments` array. + @param {string} base - The longname of the base symbol. +*/ +exports.Doclet.prototype.augment = function(base) { + if (!this.augments) { + /** + A list of symbols that are augmented by this one, if any. + @type Array. + */ + this.augments = []; + } + this.augments.push(base); +} + +/** + Set the `meta` property of this doclet. + @param {object} meta +*/ +exports.Doclet.prototype.setMeta = function(meta) { + if (!this.meta) { + /** + Information about the source code associated with this doclet. + @namespace + */ + this.meta = {}; + } + + if (meta.lineno) { + /** + The line number of the code associated with this doclet. + @type number + */ + this.meta.lineno = meta.lineno; + } + + if (meta.lineno) { + /** + The name of the file containing the code associated with this doclet. + @type string + */ + this.meta.filename = meta.filename; + } + + /** + Information about the code symbol. + @namespace + */ + this.meta.code = (this.meta.code || {}); + if (meta.id) this.meta.code.id = meta.id; + if (meta.code) { + if (meta.code.name) { + /** The name of the symbol in the source code. */ + this.meta.code.name = meta.code.name; + } + if (meta.code.type) { + /** The type of the symbol in the source code. */ + this.meta.code.type = meta.code.type; + } + if (meta.code.node) { + this.meta.code.node = meta.code.node; + } + if (meta.code.funcscope) { + this.meta.code.funcscope = meta.code.funcscope; + } + if (meta.code.value) { + /** The value of the symbol in the source code. */ + this.meta.code.value = meta.code.value; + } + } +} + +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 'property'; + } + + 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 each(tagSrc in tagSrcs) { + tags.push( {title: tagSrc.title, text: tagSrc.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 = []; + + // 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) { + var [, tagTitle, tagText] = parsedTag; + + if (tagTitle) { + tagSrcs.push({ + title: tagTitle, + text: tagText + }); } } - }); - - return tagSrcs; - } + } + }); -})(); \ No newline at end of file + return tagSrcs; +} diff --git a/rhino_modules/jsdoc/name.js b/rhino_modules/jsdoc/name.js index 5a6d7a32..fcc56701 100644 --- a/rhino_modules/jsdoc/name.js +++ b/rhino_modules/jsdoc/name.js @@ -5,178 +5,177 @@ @author Michael Mathews @license Apache License 2.0 - See file 'LICENSE.md' in this project. */ -(function() { - var jsdoc = { - tagDictionary: require('jsdoc/tag/dictionary') - }; + +var jsdoc = { + tagDictionary: require('jsdoc/tag/dictionary') + }; + +var puncToScope = { '.': 'static', '~': 'inner', '#': 'instance' }, + scopeToPunc = { 'static': '.', 'inner': '~', 'instance': '#' }, + Token = Packages.org.mozilla.javascript.Token; - var puncToScope = { '.': 'static', '~': 'inner', '#': 'instance' }, - scopeToPunc = { 'static': '.', 'inner': '~', 'instance': '#' }, - Token = Packages.org.mozilla.javascript.Token; - - /** - Resolves the longname, memberof, variation and name values of the given doclet. - @param {module:jsdoc/doclet.Doclet} doclet - */ - exports.resolve = function(doclet) { - var name = doclet.name, - memberof = doclet.memberof || '', - about = {}, - parentDoc; +/** + Resolves the longname, memberof, variation and name values of the given doclet. + @param {module:jsdoc/doclet.Doclet} doclet + */ +exports.resolve = function(doclet) { + var name = doclet.name, + memberof = doclet.memberof || '', + about = {}, + parentDoc; - name = name? (''+name).replace(/\.prototype\.?/g, '#') : ''; - - // member of a var in an outer scope? - if (name && !memberof && doclet.meta.code && doclet.meta.code.funcscope) { - name = doclet.longname = doclet.meta.code.funcscope + '~' + name; - } + name = name? (''+name).replace(/\.prototype\.?/g, '#') : ''; + + // member of a var in an outer scope? + if (name && !memberof && doclet.meta.code && doclet.meta.code.funcscope) { + name = doclet.longname = doclet.meta.code.funcscope + '~' + name; + } - if (memberof) { // @memberof tag given - memberof = memberof.replace(/\.prototype\.?/g, '#'); - - // the name is a fullname, like @name foo.bar, @memberof foo - if (name && name.indexOf(memberof) === 0) { - about = exports.shorten(name); - } - else if (name && /([#.~])$/.test(memberof) ) { // like @memberof foo# or @memberof foo~ - about = exports.shorten(memberof + name); - } - else if (name && doclet.scope ) { // like @memberof foo# or @memberof foo~ - about = exports.shorten(memberof + scopeToPunc[doclet.scope] + name); - } + if (memberof) { // @memberof tag given + memberof = memberof.replace(/\.prototype\.?/g, '#'); + + // the name is a fullname, like @name foo.bar, @memberof foo + if (name && name.indexOf(memberof) === 0) { + about = exports.shorten(name); } - else { // no @memberof - about = exports.shorten(name); + else if (name && /([#.~])$/.test(memberof) ) { // like @memberof foo# or @memberof foo~ + about = exports.shorten(memberof + name); } + else if (name && doclet.scope ) { // like @memberof foo# or @memberof foo~ + about = exports.shorten(memberof + scopeToPunc[doclet.scope] + name); + } + } + else { // no @memberof + about = exports.shorten(name); + } - if (about.name) { - doclet.name = about.name; - } - - if (about.memberof) { - doclet.setMemberof(about.memberof); - } - - if (about.longname && !doclet.longname) { - doclet.setLongname(about.longname); - } - - if (doclet.scope === 'global') { // via @global tag? - doclet.setLongname(doclet.name); - delete doclet.memberof; - } - else if (about.scope) { - if (about.memberof === '') { // via @memberof ? - delete doclet.scope; - } - else { - doclet.scope = puncToScope[about.scope]; - } + if (about.name) { + doclet.name = about.name; + } + + if (about.memberof) { + doclet.setMemberof(about.memberof); + } + + if (about.longname && !doclet.longname) { + doclet.setLongname(about.longname); + } + + if (doclet.scope === 'global') { // via @global tag? + doclet.setLongname(doclet.name); + delete doclet.memberof; + } + else if (about.scope) { + if (about.memberof === '') { // via @memberof ? + delete doclet.scope; } else { - if (doclet.name && doclet.memberof && !doclet.longname) { - doclet.scope = 'static'; // default scope when none is provided - - doclet.setLongname(doclet.memberof + scopeToPunc[doclet.scope] + doclet.name); - } - } - - if (about.variation) { - doclet.variation = about.variation; + doclet.scope = puncToScope[about.scope]; } } - - /** - @inner - @memberof module:jsdoc/name - @param {string} name - @param {string} kind - @returns {string} The name with unsafe names enclosed in quotes. - */ - function quoteUnsafe(name, kind) { // docspaced names may have unsafe characters which need to be quoted by us - if ( (jsdoc.tagDictionary.lookUp(kind).setsDocletDocspace) && /[^$_a-zA-Z0-9\/]/.test(name) ) { - if (!/^[a-z_$-\/]+:\"/i.test(name)) { - return '"' + name.replace(/\"/g, '"') + '"'; - } - } - - return name; - } - - RegExp.escape = RegExp.escape || function(str) { - var specials = new RegExp("[.*+?|()\\[\\]{}\\\\]", "g"); // .*+?|()[]{}\ - return str.replace(specials, "\\$&"); - } - - /** - @method module:jsdoc/name.applyNamespace - @param {string} longname The full longname of the symbol. - @param {string} ns The namespace to be applied. - @returns {string} The longname with the namespace applied. - */ - exports.applyNamespace = function(longname, ns) { - var nameParts = exports.shorten(longname), - name = nameParts.name, - longname = nameParts.longname; - - if ( !/^[a-zA-Z]+?:.+$/i.test(name) ) { - longname = longname.replace( new RegExp(RegExp.escape(name)+'$'), ns + ':' + name ); - } - - return longname; - } - - /** - Given a longname like "a.b#c(2)", slice it up into ["a.b", "#", 'c', '2'], - representing the memberof, the scope, the name, and variation. - @param {string} longname - @returns {object} Representing the properties of the given name. - */ - exports.shorten = function(longname) { - // quoted strings in a longname are atomic, convert to tokens - var atoms = [], token; - - // handle quoted names like foo["bar"] - longname = longname.replace(/(\[?".+?"\]?)/g, function($) { - var dot = ''; - if ( /^\[/.test($) ) { - dot = '.'; - $ = $.replace( /^\[/g, '' ).replace( /\]$/g, '' ); - } + else { + if (doclet.name && doclet.memberof && !doclet.longname) { + doclet.scope = 'static'; // default scope when none is provided - token = '@{' + atoms.length + '}@'; - atoms.push($); - - return dot + token; // foo["bar"] => foo.@{1}@ - }); - - longname = longname.replace( /\.prototype\.?/g, '#' ); - - var parts = longname? - (longname.match( /^(:?(.+)([#.~]))?(.+?)$/ ) || []).reverse() - : ['']; - - var name = parts[0] || '', // ensure name is always initialised to avoid error being thrown when calling replace on undefined [gh-24] - scope = parts[1] || '', // ., ~, or # - memberof = parts[2] || '', - variation; - - // like /** @name foo.bar(2) */ - if ( /(.+)\(([^)]+)\)$/.test(name) ) { - name = RegExp.$1, variation = RegExp.$2; + doclet.setLongname(doclet.memberof + scopeToPunc[doclet.scope] + doclet.name); } - - //// restore quoted strings back again - var i = atoms.length; - while (i--) { - longname = longname.replace('@{'+i+'}@', atoms[i]); - memberof = memberof.replace('@{'+i+'}@', atoms[i]); - scope = scope.replace('@{'+i+'}@', atoms[i]); - name = name.replace('@{'+i+'}@', atoms[i]); - } - - //// - return {longname: longname, memberof: memberof, scope: scope, name: name, variation: variation}; } -})(); \ No newline at end of file + if (about.variation) { + doclet.variation = about.variation; + } +} + +/** + @inner + @memberof module:jsdoc/name + @param {string} name + @param {string} kind + @returns {string} The name with unsafe names enclosed in quotes. + */ +function quoteUnsafe(name, kind) { // docspaced names may have unsafe characters which need to be quoted by us + if ( (jsdoc.tagDictionary.lookUp(kind).setsDocletDocspace) && /[^$_a-zA-Z0-9\/]/.test(name) ) { + if (!/^[a-z_$-\/]+:\"/i.test(name)) { + return '"' + name.replace(/\"/g, '"') + '"'; + } + } + + return name; +} + +RegExp.escape = RegExp.escape || function(str) { + var specials = new RegExp("[.*+?|()\\[\\]{}\\\\]", "g"); // .*+?|()[]{}\ + return str.replace(specials, "\\$&"); +} + +/** + @method module:jsdoc/name.applyNamespace + @param {string} longname The full longname of the symbol. + @param {string} ns The namespace to be applied. + @returns {string} The longname with the namespace applied. + */ +exports.applyNamespace = function(longname, ns) { + var nameParts = exports.shorten(longname), + name = nameParts.name, + longname = nameParts.longname; + + if ( !/^[a-zA-Z]+?:.+$/i.test(name) ) { + longname = longname.replace( new RegExp(RegExp.escape(name)+'$'), ns + ':' + name ); + } + + return longname; +} + +/** + Given a longname like "a.b#c(2)", slice it up into ["a.b", "#", 'c', '2'], + representing the memberof, the scope, the name, and variation. + @param {string} longname + @returns {object} Representing the properties of the given name. + */ +exports.shorten = function(longname) { + // quoted strings in a longname are atomic, convert to tokens + var atoms = [], token; + + // handle quoted names like foo["bar"] + longname = longname.replace(/(\[?".+?"\]?)/g, function($) { + var dot = ''; + if ( /^\[/.test($) ) { + dot = '.'; + $ = $.replace( /^\[/g, '' ).replace( /\]$/g, '' ); + } + + token = '@{' + atoms.length + '}@'; + atoms.push($); + + return dot + token; // foo["bar"] => foo.@{1}@ + }); + + longname = longname.replace( /\.prototype\.?/g, '#' ); + + var parts = longname? + (longname.match( /^(:?(.+)([#.~]))?(.+?)$/ ) || []).reverse() + : ['']; + + var name = parts[0] || '', // ensure name is always initialised to avoid error being thrown when calling replace on undefined [gh-24] + scope = parts[1] || '', // ., ~, or # + memberof = parts[2] || '', + variation; + + // like /** @name foo.bar(2) */ + if ( /(.+)\(([^)]+)\)$/.test(name) ) { + name = RegExp.$1, variation = RegExp.$2; + } + + //// restore quoted strings back again + var i = atoms.length; + while (i--) { + longname = longname.replace('@{'+i+'}@', atoms[i]); + memberof = memberof.replace('@{'+i+'}@', atoms[i]); + scope = scope.replace('@{'+i+'}@', atoms[i]); + name = name.replace('@{'+i+'}@', atoms[i]); + } + + //// + return {longname: longname, memberof: memberof, scope: scope, name: name, variation: variation}; +} + diff --git a/rhino_modules/jsdoc/opts/parser.js b/rhino_modules/jsdoc/opts/parser.js index 8c961a96..9470182a 100644 --- a/rhino_modules/jsdoc/opts/parser.js +++ b/rhino_modules/jsdoc/opts/parser.js @@ -4,70 +4,69 @@ @author Michael Mathews @license Apache License 2.0 - See file 'LICENSE.md' in this project. */ -(function() { - var common = { - args: require('common/args') + +var common = { + args: require('common/args') +}; + +var argParser = new common.args.ArgParser(), + ourOptions, + defaults = { + template: 'default', + destination: './out/' }; - - var argParser = new common.args.ArgParser(), - ourOptions, - defaults = { - template: 'default', - destination: './out/' - }; - - argParser.addOption('t', 'template', true, 'The name of the template to use. Default: the "default" template'); - argParser.addOption('c', 'configure', true, 'The path to the configuration file. Default: jsdoc __dirname + /conf.json'); - argParser.addOption('e', 'encoding', true, 'Assume this encoding when reading all source files. Default: utf-8'); - argParser.addOption('T', 'test', false, 'Run all tests and quit.'); - argParser.addOption('d', 'destination', true, 'The path to the output folder. Use "console" to dump data to the console. Default: console'); - argParser.addOption('r', 'recurse', false, 'Recurse into subdirectories when scanning for source code files.'); - argParser.addOption('h', 'help', false, 'Print this message and quit.'); - argParser.addOption('X', 'explain', false, 'Dump all found doclet internals to console and quit.'); - argParser.addOption('q', 'query', true, 'Provide a querystring to define custom variable names/values to add to the options hash.'); + +argParser.addOption('t', 'template', true, 'The name of the template to use. Default: the "default" template'); +argParser.addOption('c', 'configure', true, 'The path to the configuration file. Default: jsdoc __dirname + /conf.json'); +argParser.addOption('e', 'encoding', true, 'Assume this encoding when reading all source files. Default: utf-8'); +argParser.addOption('T', 'test', false, 'Run all tests and quit.'); +argParser.addOption('d', 'destination', true, 'The path to the output folder. Use "console" to dump data to the console. Default: console'); +argParser.addOption('r', 'recurse', false, 'Recurse into subdirectories when scanning for source code files.'); +argParser.addOption('h', 'help', false, 'Print this message and quit.'); +argParser.addOption('X', 'explain', false, 'Dump all found doclet internals to console and quit.'); +argParser.addOption('q', 'query', true, 'Provide a querystring to define custom variable names/values to add to the options hash.'); // TODO [-R, recurseonly] = a number representing the depth to recurse // TODO [-f, filter] = a regex to filter on <-- this can be better defined in the configs? - /** - Set the options for this app. - @throws {Error} Illegal arguments will throw errors. - @param {string|String[]} args The command line arguments for this app. - */ - exports.parse = function(args) { - args = args || []; - - if (typeof args === 'string' || args.constructor === String) { - args = (''+args).split(/\s+/g); - } - - ourOptions = argParser.parse(args, defaults); - +/** + Set the options for this app. + @throws {Error} Illegal arguments will throw errors. + @param {string|String[]} args The command line arguments for this app. + */ +exports.parse = function(args) { + args = args || []; + + if (typeof args === 'string' || args.constructor === String) { + args = (''+args).split(/\s+/g); + } + + ourOptions = argParser.parse(args, defaults); + + return ourOptions; +} + +/** + Display help message for options. + */ +exports.help = function() { + return argParser.help(); +} + +/** + Get a named option. + @param {string} name The name of the option. + @return {string} The value associated with the given name. + *//** + Get all the options for this app. + @return {Object} A collection of key/values representing all the options. + */ +exports.get = function(name) { + if (typeof name === 'undefined') { return ourOptions; } - - /** - Display help message for options. - */ - exports.help = function() { - return argParser.help(); + else { + return ourOptions[name]; } - - /** - Get a named option. - @param {string} name The name of the option. - @return {string} The value associated with the given name. - *//** - Get all the options for this app. - @return {Object} A collection of key/values representing all the options. - */ - exports.get = function(name) { - if (typeof name === 'undefined') { - return ourOptions; - } - else { - return ourOptions[name]; - } - } -})(); \ No newline at end of file +} diff --git a/rhino_modules/jsdoc/package.js b/rhino_modules/jsdoc/package.js index e4fcbf25..9452a6f4 100644 --- a/rhino_modules/jsdoc/package.js +++ b/rhino_modules/jsdoc/package.js @@ -8,62 +8,61 @@ @module jsdoc/package @see http://wiki.commonjs.org/wiki/Packages/1.0 */ -(function() { - /** - @class - @classdesc Represents a JavaScript package. - @param {string} json - The contents of package.json. - */ - exports.Package = function(json) { - /** The source files associated with this package. - @type {Array} - */ - this.files = []; - - /** The kind of this package. - @readonly - @default - @type {string} - */ - this.kind = 'package'; - - json = JSON.parse(json); - - /** The name of this package. - This value is found in the package.json file passed in as a command line option. - @type {string} - */ - this.name = json.name; - - /** The longname of this package. - @type {string} - */ - this.longname = this.kind + ':' + this.name; - - /** The description of this package. - @type {string} - */ - this.description = json.description; - - /** - The hash summary of the source file. - @type {string} - @since 3.2.0 - */ - this.version = json.version; - - /** - * The licenses of this package. - * @type {Array} - * @example - * "licenses": [ - * { - * "type": "GPLv2", - * "url": "http://www.example.com/licenses/gpl.html" - * } - * ] - */ - this.licenses = json.licenses; - } -})(); \ No newline at end of file +/** + @class + @classdesc Represents a JavaScript package. + @param {string} json - The contents of package.json. + */ +exports.Package = function(json) { + /** The source files associated with this package. + @type {Array} + */ + this.files = []; + + /** The kind of this package. + @readonly + @default + @type {string} + */ + this.kind = 'package'; + + json = JSON.parse(json); + + /** The name of this package. + This value is found in the package.json file passed in as a command line option. + @type {string} + */ + this.name = json.name; + + /** The longname of this package. + @type {string} + */ + this.longname = this.kind + ':' + this.name; + + /** The description of this package. + @type {string} + */ + this.description = json.description; + + /** + The hash summary of the source file. + @type {string} + @since 3.2.0 + */ + this.version = json.version; + + /** + * The licenses of this package. + * @type {Array} + * @example + * "licenses": [ + * { + * "type": "GPLv2", + * "url": "http://www.example.com/licenses/gpl.html" + * } + * ] + */ + this.licenses = json.licenses; +} + diff --git a/rhino_modules/jsdoc/src/handlers.js b/rhino_modules/jsdoc/src/handlers.js index 348906fa..fd431ab6 100644 --- a/rhino_modules/jsdoc/src/handlers.js +++ b/rhino_modules/jsdoc/src/handlers.js @@ -2,151 +2,151 @@ @module jsdoc/src/handlers */ -(function() { - var currentModule = null; + +var currentModule = null; + +/** + Attach these event handlers to a particular instance of a parser. + @param parser + */ +exports.attachTo = function(parser) { + var jsdoc = {doclet: require('jsdoc/doclet')}; - /** - Attach these event handlers to a particular instance of a parser. - @param parser - */ - exports.attachTo = function(parser) { - var jsdoc = {doclet: require('jsdoc/doclet')}; + // handles JSDoc comments that include a @name tag -- the code is ignored in such a case + parser.on('jsdocCommentFound', function(e) { + var newDoclet = new jsdoc.doclet.Doclet(e.comment, e); - // handles JSDoc comments that include a @name tag -- the code is ignored in such a case - parser.on('jsdocCommentFound', function(e) { - var newDoclet = new jsdoc.doclet.Doclet(e.comment, e); - - if (!newDoclet.name) { - return false; // only interested in virtual comments (with a @name) here - } - - addDoclet.call(this, newDoclet); - if (newDoclet.kind === 'module') { - currentModule = newDoclet.longname; - } - e.doclet = newDoclet; - }); + if (!newDoclet.name) { + return false; // only interested in virtual comments (with a @name) here + } - // handles named symbols in the code, may or may not have a JSDoc comment attached - parser.on('symbolFound', function(e) { - var subDoclets = e.comment.split(/@also\b/g); - - for (var i = 0, l = subDoclets.length; i < l; i++) { - newSymbolDoclet.call(this, subDoclets[i], e); - } - }); + addDoclet.call(this, newDoclet); + if (newDoclet.kind === 'module') { + currentModule = newDoclet.longname; + } + e.doclet = newDoclet; + }); + + // handles named symbols in the code, may or may not have a JSDoc comment attached + parser.on('symbolFound', function(e) { + var subDoclets = e.comment.split(/@also\b/g); - function newSymbolDoclet(docletSrc, e) { - var newDoclet = new jsdoc.doclet.Doclet(docletSrc, e); + for (var i = 0, l = subDoclets.length; i < l; i++) { + newSymbolDoclet.call(this, subDoclets[i], e); + } + }); + + function newSymbolDoclet(docletSrc, e) { + var 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 - // try again, without the comment - e.comment = '@undocumented'; - newDoclet = new jsdoc.doclet.Doclet(e.comment, e); - } - - if (newDoclet.alias) { - if (newDoclet.alias === '{@thisClass}') { - memberofName = this.resolveThis(e.astnode); - - // "class" refers to the owner of the prototype, not the prototype itself - if ( /^(.+?)(\.prototype|#)$/.test(memberofName) ) { - memberofName = RegExp.$1; - } - newDoclet.alias = memberofName; + // an undocumented symbol right after a virtual comment? rhino mistakenly connected the two + if (newDoclet.name) { // there was a @name in comment + // try again, without the comment + e.comment = '@undocumented'; + newDoclet = new jsdoc.doclet.Doclet(e.comment, e); + } + + if (newDoclet.alias) { + if (newDoclet.alias === '{@thisClass}') { + memberofName = this.resolveThis(e.astnode); + + // "class" refers to the owner of the prototype, not the prototype itself + if ( /^(.+?)(\.prototype|#)$/.test(memberofName) ) { + memberofName = RegExp.$1; } - newDoclet.addTag('name', newDoclet.alias); - newDoclet.postProcess(); + newDoclet.alias = memberofName; } - 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, - scope; - if ( /^((module.)?exports|this)(\.|$)/.test(newDoclet.name) ) { - var nameStartsWith = RegExp.$1; - - newDoclet.name = newDoclet.name.replace(/^(exports|this)(\.|$)/, ''); + newDoclet.addTag('name', newDoclet.alias); + newDoclet.postProcess(); + } + 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, + scope; + if ( /^((module.)?exports|this)(\.|$)/.test(newDoclet.name) ) { + var nameStartsWith = RegExp.$1; + + newDoclet.name = newDoclet.name.replace(/^(exports|this)(\.|$)/, ''); - // like /** @module foo */ exports.bar = 1; - if (nameStartsWith === 'exports' && currentModule) { + // like /** @module foo */ exports.bar = 1; + if (nameStartsWith === 'exports' && currentModule) { + memberofName = currentModule; + scope = 'static'; + } + else if (newDoclet.name === 'module.exports' && currentModule) { + newDoclet.addTag('name', currentModule); + newDoclet.postProcess(); + } + else { + // like /** @module foo */ exports = {bar: 1}; + // or /** blah */ this.foo = 1; + memberofName = this.resolveThis(e.astnode); + scope = nameStartsWith === 'exports'? 'static' : 'instance'; + + // like /** @module foo */ this.bar = 1; + if (nameStartsWith === 'this' && currentModule && !memberofName) { memberofName = currentModule; scope = 'static'; } - else if (newDoclet.name === 'module.exports' && currentModule) { - newDoclet.addTag('name', currentModule); - newDoclet.postProcess(); - } - else { - // like /** @module foo */ exports = {bar: 1}; - // or /** blah */ this.foo = 1; - memberofName = this.resolveThis(e.astnode); - scope = nameStartsWith === 'exports'? 'static' : 'instance'; - - // like /** @module foo */ this.bar = 1; - if (nameStartsWith === 'this' && currentModule && !memberofName) { - memberofName = currentModule; - scope = 'static'; - } - } - - if (memberofName) { - if (newDoclet.name) { - newDoclet.name = memberofName + (scope === 'instance'? '#' : '.') + newDoclet.name; - } - else { newDoclet.name = memberofName; } - } - } - else { - memberofName = this.astnodeToMemberof(e.astnode); } - if (memberofName) { newDoclet.addTag( 'memberof', memberofName); } - else { - if (currentModule) { - if (!newDoclet.scope) newDoclet.addTag( 'inner'); - if (!newDoclet.memberof && newDoclet.scope !== 'global') newDoclet.addTag( 'memberof', currentModule); + if (memberofName) { + if (newDoclet.name) { + newDoclet.name = memberofName + (scope === 'instance'? '#' : '.') + newDoclet.name; } + else { newDoclet.name = memberofName; } } } + else { + memberofName = this.astnodeToMemberof(e.astnode); + } - newDoclet.postProcess(); - } - else { - return false; - } - - addDoclet.call(this, newDoclet); - e.doclet = newDoclet; - } - - //parser.on('fileBegin', function(e) { }); - - parser.on('fileComplete', function(e) { - currentModule = null; - }); - - function addDoclet(newDoclet) { - if (newDoclet) { - e = { doclet: newDoclet }; - this.fire('newDoclet', e); - - if (!e.defaultPrevented) { - if ( !filter(newDoclet) ) { - this.addResult(newDoclet); + if (memberofName) { newDoclet.addTag( 'memberof', memberofName); } + else { + if (currentModule) { + if (!newDoclet.scope) newDoclet.addTag( 'inner'); + if (!newDoclet.memberof && newDoclet.scope !== 'global') newDoclet.addTag( 'memberof', currentModule); } } } - } - - function filter(doclet) { - // you can't document prototypes - if ( /#$/.test(doclet.longname) ) return true; - // you can't document symbols added by the parser with a dummy name - if (doclet.meta.code && doclet.meta.code.name === '____') return true; + newDoclet.postProcess(); + } + else { return false; } + + addDoclet.call(this, newDoclet); + e.doclet = newDoclet; } -})(); \ No newline at end of file + + //parser.on('fileBegin', function(e) { }); + + parser.on('fileComplete', function(e) { + currentModule = null; + }); + + function addDoclet(newDoclet) { + if (newDoclet) { + e = { doclet: newDoclet }; + this.fire('newDoclet', e); + + if (!e.defaultPrevented) { + if ( !filter(newDoclet) ) { + this.addResult(newDoclet); + } + } + } + } + + function filter(doclet) { + // you can't document prototypes + if ( /#$/.test(doclet.longname) ) return true; + // you can't document symbols added by the parser with a dummy name + if (doclet.meta.code && doclet.meta.code.name === '____') return true; + + return false; + } +} + diff --git a/rhino_modules/jsdoc/src/parser.js b/rhino_modules/jsdoc/src/parser.js index 8e4daa95..5461ef33 100644 --- a/rhino_modules/jsdoc/src/parser.js +++ b/rhino_modules/jsdoc/src/parser.js @@ -5,498 +5,495 @@ * @requires common/events */ -(function() { - var Token = Packages.org.mozilla.javascript.Token, - currentParser = null, - currentSourceName = ''; - - /** - * @class - * @mixes module:common/events - * - * @example Create a new parser. - * var jsdocParser = new (require('jsdoc/src/parser').Parser)(); - */ - exports.Parser = function() { - this._resultBuffer = []; - this.refs = {}; - } - require('common/util').mixin(exports.Parser.prototype, require('common/events')); +var Token = Packages.org.mozilla.javascript.Token, + currentParser = null, + currentSourceName = ''; - /** - * Parse the given source files for JSDoc comments. - * @param {Array.} sourceFiles An array of filepaths to the JavaScript sources. - * @param {string} [encoding=utf8] - * - * @fires jsdocCommentFound - * @fires symbolFound - * @fires newDoclet - * @fires fileBegin - * @fires fileComplete - * - * @example Parse two source files. - * var myFiles = ['file1.js', 'file2.js']; - * var docs = jsdocParser.parse(myFiles); - */ - exports.Parser.prototype.parse = function(sourceFiles, encoding) { - const SCHEMA = 'javascript:'; - var sourceCode = '', - filename = ''; - - if (typeof sourceFiles === 'string') { sourceFiles = [sourceFiles]; } - - for (i = 0, leni = sourceFiles.length; i < leni; i++) { - if (sourceFiles[i].indexOf(SCHEMA) === 0) { - sourceCode = sourceFiles[i].substr(SCHEMA.length); - filename = '[[string' + i + ']]'; - } - else { - filename = sourceFiles[i]; - try { - sourceCode = require('fs').readFileSync(filename, encoding); - } - catch(e) { - console.log('FILE READ ERROR: in module:jsdoc/parser.parseFiles: "' + filename + '" ' + e); - continue; - } - } - - currentParser = this; - this._parseSourceCode(sourceCode, filename); - currentParser = null; - } - - return this._resultBuffer; - } +/** + * @class + * @mixes module:common/events + * + * @example Create a new parser. + * var jsdocParser = new (require('jsdoc/src/parser').Parser)(); + */ +exports.Parser = function() { + this._resultBuffer = []; + this.refs = {}; +} +require('common/util').mixin(exports.Parser.prototype, require('common/events')); + +/** + * Parse the given source files for JSDoc comments. + * @param {Array.} sourceFiles An array of filepaths to the JavaScript sources. + * @param {string} [encoding=utf8] + * + * @fires jsdocCommentFound + * @fires symbolFound + * @fires newDoclet + * @fires fileBegin + * @fires fileComplete + * + * @example Parse two source files. + * var myFiles = ['file1.js', 'file2.js']; + * var docs = jsdocParser.parse(myFiles); + */ +exports.Parser.prototype.parse = function(sourceFiles, encoding) { + const SCHEMA = 'javascript:'; + var sourceCode = '', + filename = ''; - /** - * @returns {Array} The accumulated results of any calls to parse. - */ - exports.Parser.prototype.results = function() { - return this._resultBuffer; - } + if (typeof sourceFiles === 'string') { sourceFiles = [sourceFiles]; } - /** - * @param {Object} o The parse result to add to the result buffer. - */ - exports.Parser.prototype.addResult = function(o) { - this._resultBuffer.push(o); - } - - /** - * Empty any accumulated results of calls to parse. - */ - exports.Parser.prototype.clear = function() { - currentParser = null; - currentSourceName = ''; - this._resultBuffer = []; - } - - /** @private */ - exports.Parser.prototype._parseSourceCode = function(sourceCode, sourceName) { - currentSourceName = sourceName; - - sourceCode = pretreat(sourceCode); - - var ast = parserFactory().parse(sourceCode, sourceName, 1); - - var e = {filename: currentSourceName}; - this.fire('fileBegin', e); - - if (!e.defaultPrevented) { - ast.visit( - new Packages.org.mozilla.javascript.ast.NodeVisitor({ - visit: visitNode - }) - ); - } - - this.fire('fileComplete', e); - - currentSourceName = ''; - } - - function pretreat(code) { - return code - // merge adjacent doclets - .replace(/\*\/\/\*\*+/g, '@also') - // make lent objectliterals documentable by giving them a dummy name - .replace(/(\/\*\*[\s\S]*?@lends\b[\s\S]*?\*\/\s*)\{/g, '$1____ = {'); - } - - /** - * Given a node, determine what the node is a member of. - * @param {astnode} node - * @returns {string} The long name of the node that this is a member of. - */ - exports.Parser.prototype.astnodeToMemberof = function(node) { - var memberof = {}; - - if (node.type === Token.VAR || node.type === Token.FUNCTION) { - if (node.enclosingFunction) { // an inner var or func - memberof.id = 'astnode'+node.enclosingFunction.hashCode(); - memberof.doclet = this.refs[memberof.id]; - if (!memberof.doclet) { - return '~'; - } - return (memberof.doclet.longname||memberof.doclet.name) + '~'; - } + for (i = 0, leni = sourceFiles.length; i < leni; i++) { + if (sourceFiles[i].indexOf(SCHEMA) === 0) { + sourceCode = sourceFiles[i].substr(SCHEMA.length); + filename = '[[string' + i + ']]'; } else { - memberof.id = 'astnode'+node.parent.hashCode(); - memberof.doclet = this.refs[memberof.id]; - if (!memberof.doclet) return ''; // global? - return memberof.doclet.longname||memberof.doclet.name; + filename = sourceFiles[i]; + try { + sourceCode = require('fs').readFileSync(filename, encoding); + } + catch(e) { + console.log('FILE READ ERROR: in module:jsdoc/parser.parseFiles: "' + filename + '" ' + e); + continue; + } } + + currentParser = this; + this._parseSourceCode(sourceCode, filename); + currentParser = null; } - /** - * Resolve what "this" refers too, relative to a node. - * @param {astnode} node - The "this" node - * @returns {string} The longname of the enclosing node. - */ - exports.Parser.prototype.resolveThis = function(node) { - var memberof = {}; - - if (node.enclosingFunction) { + return this._resultBuffer; +} + +/** + * @returns {Array} The accumulated results of any calls to parse. + */ +exports.Parser.prototype.results = function() { + return this._resultBuffer; +} + +/** + * @param {Object} o The parse result to add to the result buffer. + */ +exports.Parser.prototype.addResult = function(o) { + this._resultBuffer.push(o); +} + +/** + * Empty any accumulated results of calls to parse. + */ +exports.Parser.prototype.clear = function() { + currentParser = null; + currentSourceName = ''; + this._resultBuffer = []; +} + +/** @private */ +exports.Parser.prototype._parseSourceCode = function(sourceCode, sourceName) { + currentSourceName = sourceName; + + sourceCode = pretreat(sourceCode); + + var ast = parserFactory().parse(sourceCode, sourceName, 1); + + var e = {filename: currentSourceName}; + this.fire('fileBegin', e); + + if (!e.defaultPrevented) { + ast.visit( + new Packages.org.mozilla.javascript.ast.NodeVisitor({ + visit: visitNode + }) + ); + } + + this.fire('fileComplete', e); + + currentSourceName = ''; +} + +function pretreat(code) { + return code + // merge adjacent doclets + .replace(/\*\/\/\*\*+/g, '@also') + // make lent objectliterals documentable by giving them a dummy name + .replace(/(\/\*\*[\s\S]*?@lends\b[\s\S]*?\*\/\s*)\{/g, '$1____ = {'); +} + +/** + * Given a node, determine what the node is a member of. + * @param {astnode} node + * @returns {string} The long name of the node that this is a member of. + */ +exports.Parser.prototype.astnodeToMemberof = function(node) { + var memberof = {}; + + if (node.type === Token.VAR || node.type === Token.FUNCTION) { + if (node.enclosingFunction) { // an inner var or func memberof.id = 'astnode'+node.enclosingFunction.hashCode(); memberof.doclet = this.refs[memberof.id]; - if (!memberof.doclet) { - return ''; // TODO handle global this? - } - - if (memberof.doclet['this']) { - return memberof.doclet['this']; - } - // like: Foo.constructor = function(n) { /** blah */ this.name = n; } - else if (memberof.doclet.kind === 'function' && memberof.doclet.memberof) { - return memberof.doclet.memberof; - } - // walk up to the closest class we can find - else if (memberof.doclet.kind === 'class' || memberof.doclet.kind === 'module') { - return memberof.doclet.longname||memberof.doclet.name; - } - else { - if (node.enclosingFunction){ - return this.resolveThis(node.enclosingFunction/*memberof.doclet.meta.code.val*/); - } - else return ''; // TODO handle global this? + return '~'; } + return (memberof.doclet.longname||memberof.doclet.name) + '~'; } - else if (node.parent) { - var parent = node.parent; - if (parent.type === Token.COLON) parent = parent.parent; // go up one more - - memberof.id = 'astnode'+parent.hashCode(); - memberof.doclet = this.refs[memberof.id]; - - if (!memberof.doclet) return ''; // global? - + } + else { + memberof.id = 'astnode'+node.parent.hashCode(); + memberof.doclet = this.refs[memberof.id]; + if (!memberof.doclet) return ''; // global? + return memberof.doclet.longname||memberof.doclet.name; + } +} + +/** + * Resolve what "this" refers too, relative to a node. + * @param {astnode} node - The "this" node + * @returns {string} The longname of the enclosing node. + */ +exports.Parser.prototype.resolveThis = function(node) { + var memberof = {}; + + if (node.enclosingFunction) { + memberof.id = 'astnode'+node.enclosingFunction.hashCode(); + memberof.doclet = this.refs[memberof.id]; + + if (!memberof.doclet) { + return ''; // TODO handle global this? + } + + if (memberof.doclet['this']) { + return memberof.doclet['this']; + } + // like: Foo.constructor = function(n) { /** blah */ this.name = n; } + else if (memberof.doclet.kind === 'function' && memberof.doclet.memberof) { + return memberof.doclet.memberof; + } + // walk up to the closest class we can find + else if (memberof.doclet.kind === 'class' || memberof.doclet.kind === 'module') { return memberof.doclet.longname||memberof.doclet.name; } else { - return ''; // global? + if (node.enclosingFunction){ + return this.resolveThis(node.enclosingFunction/*memberof.doclet.meta.code.val*/); + } + else return ''; // TODO handle global this? } } - - /** - * Resolve what function a var is limited to. - * @param {astnode} node - * @param {string} basename The leftmost name in the long name: in foo.bar.zip the basename is foo. - */ - exports.Parser.prototype.resolveVar = function(node, basename) { - var doclet, - enclosingFunction = node.enclosingFunction; + else if (node.parent) { + var parent = node.parent; + if (parent.type === Token.COLON) parent = parent.parent; // go up one more - if (!enclosingFunction) { return ''; } // global - doclet = this.refs['astnode'+enclosingFunction.hashCode()]; + memberof.id = 'astnode'+parent.hashCode(); + memberof.doclet = this.refs[memberof.id]; + + if (!memberof.doclet) return ''; // global? + + return memberof.doclet.longname||memberof.doclet.name; + } + else { + return ''; // global? + } +} - if ( doclet && doclet.meta.vars && ~doclet.meta.vars.indexOf(basename) ) { - return doclet.longname; - } - - return this.resolveVar(enclosingFunction, basename); +/** + * Resolve what function a var is limited to. + * @param {astnode} node + * @param {string} basename The leftmost name in the long name: in foo.bar.zip the basename is foo. + */ +exports.Parser.prototype.resolveVar = function(node, basename) { + var doclet, + enclosingFunction = node.enclosingFunction; + + if (!enclosingFunction) { return ''; } // global + doclet = this.refs['astnode'+enclosingFunction.hashCode()]; + + if ( doclet && doclet.meta.vars && ~doclet.meta.vars.indexOf(basename) ) { + return doclet.longname; } - /** @private */ - function visitNode(node) { - var e, - commentSrc; + return this.resolveVar(enclosingFunction, basename); +} - // look for stand-alone doc comments - if (node.type === Token.SCRIPT && node.comments) { - // note: ALL comments are seen in this block... - for each(var comment in node.comments.toArray()) { - if (comment.commentType !== Token.CommentType.JSDOC) { - continue; - } - - if (commentSrc = ''+comment.toSource()) { +/** @private */ +function visitNode(node) { + var e, + commentSrc; - e = { - comment: commentSrc, - lineno: comment.getLineno(), - filename: currentSourceName - }; - - if ( isValidJsdoc(commentSrc) ) { - currentParser.fire('jsdocCommentFound', e, currentParser); - } - } + // look for stand-alone doc comments + if (node.type === Token.SCRIPT && node.comments) { + // note: ALL comments are seen in this block... + for each(var comment in node.comments.toArray()) { + if (comment.commentType !== Token.CommentType.JSDOC) { + continue; } - } - else if (node.type === Token.ASSIGN) { - e = { - id: 'astnode'+node.hashCode(), // the id of the ASSIGN node - comment: String(node.jsDoc||'@undocumented'), - lineno: node.getLineno(), - filename: currentSourceName, - astnode: node, - code: aboutNode(node) - }; - var basename = e.code.name.replace(/^([$a-z_][$a-z_0-9]*).*?$/i, '$1'); - - if (basename !== 'this') e.code.funcscope = currentParser.resolveVar(node, basename); + if (commentSrc = ''+comment.toSource()) { - if ( isValidJsdoc(e.comment) ) { - currentParser.fire('symbolFound', e, currentParser); - } - - if (e.doclet) { - currentParser.refs['astnode'+e.code.node.hashCode()] = e.doclet; // allow lookup from value => doclet - } - } - 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.jsDoc||'@undocumented'), - lineno: node.getLineno(), - filename: currentSourceName, - astnode: node, - code: aboutNode(node) - }; - - if ( isValidJsdoc(e.comment) ) { - currentParser.fire('symbolFound', e, currentParser); - } - - if (e.doclet) { - currentParser.refs['astnode'+e.code.node.hashCode()] = e.doclet; // allow lookup from value => doclet - } - } - 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 - node.jsDoc = node.parent.jsDoc; - } - - e = { - id: 'astnode'+node.hashCode(), // the id of the VARIABLE node - comment: String(node.jsDoc||'@undocumented'), - lineno: node.getLineno(), - filename: currentSourceName, - astnode: node, - code: aboutNode(node) - }; - - // keep track of vars in a function scope - if (node.enclosingFunction) { - var func = 'astnode'+node.enclosingFunction.hashCode(), - funcDoc = currentParser.refs[func]; - - if (funcDoc) { - funcDoc.meta.vars = funcDoc.meta.vars || []; - funcDoc.meta.vars.push(e.code.name); - } - } - - if ( isValidJsdoc(e.comment) ) { - currentParser.fire('symbolFound', e, currentParser); - } - - if (e.doclet) { - currentParser.refs['astnode'+e.code.node.hashCode()] = e.doclet; // allow lookup from value => doclet - } - } - else if (node.type == Token.FUNCTION) { - e = { - id: 'astnode'+node.hashCode(), // the id of the COLON node - comment: String(node.jsDoc||'@undocumented'), - lineno: node.getLineno(), - filename: currentSourceName, - astnode: node, - code: aboutNode(node) - }; - - e.code.name = String(node.name) || ''; - - // keep track of vars in a function scope - if (node.enclosingFunction) { - var func = 'astnode'+node.enclosingFunction.hashCode(), - funcDoc = currentParser.refs[func]; - - if (funcDoc) { - funcDoc.meta.vars = funcDoc.meta.vars || []; - funcDoc.meta.vars.push(e.code.name); - } - } - - var basename = e.code.name.replace(/^([$a-z_][$a-z_0-9]*).*?$/i, '$1'); - e.code.funcscope = currentParser.resolveVar(node, basename); - - if ( isValidJsdoc(e.comment) ) { - currentParser.fire('symbolFound', e, currentParser); - } - - if (e.doclet) { - currentParser.refs['astnode'+e.code.node.hashCode()] = e.doclet; // allow lookup from value => doclet - } - else if (!currentParser.refs['astnode'+e.code.node.hashCode()]) { // keep references to undocumented anonymous functions too as they might have scoped vars - currentParser.refs['astnode'+e.code.node.hashCode()] = { - longname: '', - meta: { code: e.code } + e = { + comment: commentSrc, + lineno: comment.getLineno(), + filename: currentSourceName }; - } - } - - 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) { - about = {}; - - if (node.type == Token.FUNCTION) { - about.name = '' + node.name; - - about.type = 'function'; - about.node = node; - - return about; - } - - 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); - } - else { // like var i; - about.node = node.target; - about.value = nodeToString(about.node); - about.type = 'undefined'; - } - - return about; - } - - 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, '\\"')+'"'; + + if ( isValidJsdoc(commentSrc) ) { + currentParser.fire('jsdocCommentFound', e, currentParser); } } - about.node = node.right; - about.value = nodeToString(about.node); - about.type = getTypeName(node.right); - return about; + } + } + else if (node.type === Token.ASSIGN) { + e = { + id: 'astnode'+node.hashCode(), // the id of the ASSIGN node + comment: String(node.jsDoc||'@undocumented'), + lineno: node.getLineno(), + filename: currentSourceName, + astnode: node, + code: aboutNode(node) + }; + + var basename = e.code.name.replace(/^([$a-z_][$a-z_0-9]*).*?$/i, '$1'); + + if (basename !== 'this') e.code.funcscope = currentParser.resolveVar(node, basename); + + if ( isValidJsdoc(e.comment) ) { + currentParser.fire('symbolFound', e, currentParser); } - // type 39 (NAME) - var string = nodeToString(node); - if (string) { - about.name = string; - return about; + if (e.doclet) { + currentParser.refs['astnode'+e.code.node.hashCode()] = e.doclet; // allow lookup from value => doclet } - + } + 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.jsDoc||'@undocumented'), + lineno: node.getLineno(), + filename: currentSourceName, + astnode: node, + code: aboutNode(node) + }; + + if ( isValidJsdoc(e.comment) ) { + currentParser.fire('symbolFound', e, currentParser); + } + + if (e.doclet) { + currentParser.refs['astnode'+e.code.node.hashCode()] = e.doclet; // allow lookup from value => doclet + } + } + 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 + node.jsDoc = node.parent.jsDoc; + } + + e = { + id: 'astnode'+node.hashCode(), // the id of the VARIABLE node + comment: String(node.jsDoc||'@undocumented'), + lineno: node.getLineno(), + filename: currentSourceName, + astnode: node, + code: aboutNode(node) + }; + + // keep track of vars in a function scope + if (node.enclosingFunction) { + var func = 'astnode'+node.enclosingFunction.hashCode(), + funcDoc = currentParser.refs[func]; + + if (funcDoc) { + funcDoc.meta.vars = funcDoc.meta.vars || []; + funcDoc.meta.vars.push(e.code.name); + } + } + + if ( isValidJsdoc(e.comment) ) { + currentParser.fire('symbolFound', e, currentParser); + } + + if (e.doclet) { + currentParser.refs['astnode'+e.code.node.hashCode()] = e.doclet; // allow lookup from value => doclet + } + } + else if (node.type == Token.FUNCTION) { + e = { + id: 'astnode'+node.hashCode(), // the id of the COLON node + comment: String(node.jsDoc||'@undocumented'), + lineno: node.getLineno(), + filename: currentSourceName, + astnode: node, + code: aboutNode(node) + }; + + e.code.name = String(node.name) || ''; + + // keep track of vars in a function scope + if (node.enclosingFunction) { + var func = 'astnode'+node.enclosingFunction.hashCode(), + funcDoc = currentParser.refs[func]; + + if (funcDoc) { + funcDoc.meta.vars = funcDoc.meta.vars || []; + funcDoc.meta.vars.push(e.code.name); + } + } + + var basename = e.code.name.replace(/^([$a-z_][$a-z_0-9]*).*?$/i, '$1'); + e.code.funcscope = currentParser.resolveVar(node, basename); + + if ( isValidJsdoc(e.comment) ) { + currentParser.fire('symbolFound', e, currentParser); + } + + if (e.doclet) { + currentParser.refs['astnode'+e.code.node.hashCode()] = e.doclet; // allow lookup from value => doclet + } + else if (!currentParser.refs['astnode'+e.code.node.hashCode()]) { // keep references to undocumented anonymous functions too as they might have scoped vars + currentParser.refs['astnode'+e.code.node.hashCode()] = { + longname: '', + meta: { code: e.code } + }; + } + } + + 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) { + about = {}; + + if (node.type == Token.FUNCTION) { + about.name = '' + node.name; + + about.type = 'function'; + about.node = node; + 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('.'); + 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); } - 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 { - str = getTypeName(node); + else { // like var i; + about.node = node.target; + about.value = nodeToString(about.node); + about.type = 'undefined'; } - 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 about; + } + + 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, '\\"')+'"'; + } } - - return type; + about.node = node.right; + about.value = nodeToString(about.node); + about.type = getTypeName(node.right); + return about; } - /** @private - @memberof module:src/parser.Parser - */ - function isValidJsdoc(commentSrc) { - return commentSrc.indexOf('/***') !== 0; /*** ignore comments that start with many stars ***/ + // type 39 (NAME) + var string = nodeToString(node); + if (string) { + about.name = string; + return about; + } + + 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 { + 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.indexOf('/***') !== 0; /*** ignore comments that start with many stars ***/ +} /** Fired whenever the parser encounters a JSDoc comment in the current source code. @@ -506,4 +503,4 @@ @param {string} e.comment The text content of the JSDoc comment @param {number} e.lineno The line number associated with the found comment. @param {string} e.filename The file name associated with the found comment. - */ \ No newline at end of file +*/ \ No newline at end of file diff --git a/rhino_modules/jsdoc/src/scanner.js b/rhino_modules/jsdoc/src/scanner.js index 39e3a35d..9b8ff7e6 100644 --- a/rhino_modules/jsdoc/src/scanner.js +++ b/rhino_modules/jsdoc/src/scanner.js @@ -6,64 +6,63 @@ @license Apache License 2.0 - See file 'LICENSE.md' in this project. */ -(function() { - var common = { - mixin: require('common/util').mixin, - events: require('common/events') - }; + +var common = { + mixin: require('common/util').mixin, + events: require('common/events') +}; + +var fs = require('fs'); + +/** + @constructor + @mixes module:common.events + */ +exports.Scanner = function() { +} +common.mixin(exports.Scanner.prototype, common.events); + +/** + Recursively searches the given searchPaths for js files. + @param {Array.} searchPaths + @param {number} [depth=1] + @fires sourceFileFound + */ +exports.Scanner.prototype.scan = function(searchPaths, depth, includeMatch, excludeMatch) { + var filePaths = [], + that = this; + + searchPaths = searchPaths || []; + depth = depth || 1; + + searchPaths.forEach(function($) { + if ( fs.stat($).isFile() ) { + filePaths.push($); + } + else { + filePaths = filePaths.concat(fs.ls($, depth)); + } + }); - var fs = require('fs'); + filePaths = filePaths.filter(function($) { + if (includeMatch && !includeMatch.test($)) { + return false + } + + if (excludeMatch && excludeMatch.test($)) { + return false + } + + return true; + }); - /** - @constructor - @mixes module:common.events - */ - exports.Scanner = function() { - } - common.mixin(exports.Scanner.prototype, common.events); + filePaths = filePaths.filter(function($) { + var e = { fileName: $ }; + that.fire('sourceFileFound', e); + + return !e.defaultPrevented; + }); - /** - Recursively searches the given searchPaths for js files. - @param {Array.} searchPaths - @param {number} [depth=1] - @fires sourceFileFound - */ - exports.Scanner.prototype.scan = function(searchPaths, depth, includeMatch, excludeMatch) { - var filePaths = [], - that = this; + return filePaths; +} - searchPaths = searchPaths || []; - depth = depth || 1; - - searchPaths.forEach(function($) { - if ( fs.stat($).isFile() ) { - filePaths.push($); - } - else { - filePaths = filePaths.concat(fs.ls($, depth)); - } - }); - - filePaths = filePaths.filter(function($) { - if (includeMatch && !includeMatch.test($)) { - return false - } - - if (excludeMatch && excludeMatch.test($)) { - return false - } - - return true; - }); - - filePaths = filePaths.filter(function($) { - var e = { fileName: $ }; - that.fire('sourceFileFound', e); - - return !e.defaultPrevented; - }); - - return filePaths; - } - -})(); \ No newline at end of file diff --git a/rhino_modules/jsdoc/tag.js b/rhino_modules/jsdoc/tag.js index d42500b4..c68f6a2f 100644 --- a/rhino_modules/jsdoc/tag.js +++ b/rhino_modules/jsdoc/tag.js @@ -11,126 +11,124 @@ @requires jsdoc/tag/validator @requires jsdoc/tag/type */ -(function() { + - var jsdoc = { - tag: { - dictionary: require('jsdoc/tag/dictionary'), - validator: require('jsdoc/tag/validator'), - type: require('jsdoc/tag/type') - } - }; - - /** - Constructs a new tag object. Calls the tag validator. - @class - @classdesc Represents a single doclet tag. - @param {string} tagTitle - @param {string=} tagBody - @param {object=} meta - */ - exports.Tag = function(tagTitle, tagBody, meta) { - var tagDef = jsdoc.tag.dictionary.lookUp(tagTitle), - meta = meta || {}; - - this.originalTitle = trim(tagTitle); - - /** The title part of the tag: @title text */ - this.title = jsdoc.tag.dictionary.normalise( this.originalTitle ); - - /** The text part of the tag: @title text */ - this.text = trim(tagBody, tagDef.keepsWhitespace); - - if (this.text) { - - if (tagDef.onTagText) { - this.text = tagDef.onTagText(this.text); - } - - if (tagDef.canHaveType) { +var jsdoc = { + tag: { + dictionary: require('jsdoc/tag/dictionary'), + validator: require('jsdoc/tag/validator'), + type: require('jsdoc/tag/type') + } +}; + +/** + Constructs a new tag object. Calls the tag validator. + @class + @classdesc Represents a single doclet tag. + @param {string} tagTitle + @param {string=} tagBody + @param {object=} meta + */ +exports.Tag = function(tagTitle, tagBody, meta) { + var tagDef = jsdoc.tag.dictionary.lookUp(tagTitle), + meta = meta || {}; + + this.originalTitle = trim(tagTitle); + + /** The title part of the tag: @title text */ + this.title = jsdoc.tag.dictionary.normalise( this.originalTitle ); + + /** The text part of the tag: @title text */ + this.text = trim(tagBody, tagDef.keepsWhitespace); + + if (this.text) { + + if (tagDef.onTagText) { + this.text = tagDef.onTagText(this.text); + } + + if (tagDef.canHaveType) { + + /** The value propertiy represents the result of parsing the tag text. */ + this.value = {}; - /** The value propertiy represents the result of parsing the tag text. */ - this.value = {}; - - var [ - /*Array.*/ typeNames, - /*any*/ remainingText, - /*?boolean*/ optional, - /*?boolean*/ nullable, - /*?boolean*/ variable - ] = jsdoc.tag.type.parse(this.text); - - if (typeNames.length) { - this.value.type = { - names: typeNames, - optional: optional, - nullable: nullable, - variable: variable - }; - } + var [ + /*Array.*/ typeNames, + /*any*/ remainingText, + /*?boolean*/ optional, + /*?boolean*/ nullable, + /*?boolean*/ variable + ] = jsdoc.tag.type.parse(this.text); + + if (typeNames.length) { + this.value.type = { + names: typeNames, + optional: optional, + nullable: nullable, + variable: variable + }; + } - if (remainingText) { - if (tagDef.canHaveName) { - var [paramName, paramDesc, paramOptional, paramDefault] - = parseParamText(remainingText); - - // note the dash is a special case: as a param name it means "no name" - if (paramName && paramName !== '-') { this.value.name = paramName; } - - if (paramDesc) { this.value.description = paramDesc; } - if (paramOptional) { this.value.optional = paramOptional; } - if (paramDefault) { this.value.defaultvalue = paramDefault; } - } - else { - this.value.description = remainingText; - } + if (remainingText) { + if (tagDef.canHaveName) { + var [paramName, paramDesc, paramOptional, paramDefault] + = parseParamText(remainingText); + + // note the dash is a special case: as a param name it means "no name" + if (paramName && paramName !== '-') { this.value.name = paramName; } + + if (paramDesc) { this.value.description = paramDesc; } + if (paramOptional) { this.value.optional = paramOptional; } + if (paramDefault) { this.value.defaultvalue = paramDefault; } + } + else { + this.value.description = remainingText; } } - else { - this.value = this.text; - } - } - - jsdoc.tag.validator.validate(this, meta); - } + } + else { + this.value = this.text; + } + } + + jsdoc.tag.validator.validate(this, meta); +} + +function trim(text, newlines) { + if (!text) { return ''; } - 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, ''); - } + 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; - /** - 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]*))?$/); + // 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; - pdesc = RegExp.$3; - - if ( /^\[\s*(.+?)\s*\]$/.test(pname) ) { + poptional = true; + + if ( /^(.+?)\s*=\s*(.+)$/.test(pname) ) { pname = RegExp.$1; - poptional = true; - - if ( /^(.+?)\s*=\s*(.+)$/.test(pname) ) { - pname = RegExp.$1; - pdefault = RegExp.$2; - } + pdefault = RegExp.$2; } - return [pname, pdesc, poptional, pdefault]; } - -})(); \ No newline at end of file + return [pname, pdesc, poptional, pdefault]; +} diff --git a/rhino_modules/jsdoc/tag/dictionary.js b/rhino_modules/jsdoc/tag/dictionary.js index b0484168..ab186f4c 100644 --- a/rhino_modules/jsdoc/tag/dictionary.js +++ b/rhino_modules/jsdoc/tag/dictionary.js @@ -3,71 +3,74 @@ @author Michael Mathews @license Apache License 2.0 - See file 'LICENSE.md' in this project. */ -(function() { - var _synonyms = {}, - _definitions = {}, - _namespaces = []; + +var _synonyms = {}, + _definitions = {}, + _namespaces = []; + +function _TagDefinition(title, etc) { + etc = etc || {}; - function _TagDefinition(title, etc) { - etc = etc || {}; - - this.title = dictionary.normalise(title); - - for (var p in etc) { - if (etc.hasOwnProperty(p)) { - this[p] = etc[p]; - } + this.title = dictionary.normalise(title); + + for (var p in etc) { + if (etc.hasOwnProperty(p)) { + this[p] = etc[p]; } } - - _TagDefinition.prototype.synonym = function(synonymName) { - _synonyms[synonymName.toLowerCase()] = this.title; - return this; // chainable - } - - /** @exports jsdoc/tag/dictionary */ - var dictionary = { - /** @function */ - defineTag: function(title, opts) { - _definitions[title] = new _TagDefinition(title, opts); - - if (opts.isNamespace) { - _namespaces.push(title); - } - - return _definitions[title]; - }, - - /** @function */ - lookUp: function(title) { - title = dictionary.normalise(title); - - if ( _definitions.hasOwnProperty(title) ) { - return _definitions[title]; - } - - return false; - }, +} + +_TagDefinition.prototype.synonym = function(synonymName) { + _synonyms[synonymName.toLowerCase()] = this.title; + return this; // chainable +} + +/** @exports jsdoc/tag/dictionary */ +var dictionary = { + /** @function */ + defineTag: function(title, opts) { + _definitions[title] = new _TagDefinition(title, opts); - /** @function */ - isNamespace: function(kind) { - return ( ~ _namespaces.indexOf(kind) ); - }, - - /** @function */ - normalise: function(title) { - canonicalName = title.toLowerCase(); - - if ( _synonyms.hasOwnProperty(canonicalName) ) { - return _synonyms[canonicalName]; - } - - return canonicalName; + if (opts.isNamespace) { + _namespaces.push(title); } - }; + + return _definitions[title]; + }, + + /** @function */ + lookUp: function(title) { + title = dictionary.normalise(title); + + if ( _definitions.hasOwnProperty(title) ) { + return _definitions[title]; + } + + return false; + }, - require('jsdoc/tag/dictionary/definitions').defineTags(dictionary); + /** @function */ + isNamespace: function(kind) { + return ( ~ _namespaces.indexOf(kind) ); + }, - module.exports = dictionary; - -})(); \ No newline at end of file + /** @function */ + normalise: function(title) { + canonicalName = title.toLowerCase(); + + if ( _synonyms.hasOwnProperty(canonicalName) ) { + return _synonyms[canonicalName]; + } + + return canonicalName; + } +}; + +require('jsdoc/tag/dictionary/definitions').defineTags(dictionary); + +for (var prop in dictionary) { + if (dictionary.hasOwnProperty(prop)) { + exports[prop] = dictionary[prop]; + } +} + diff --git a/rhino_modules/jsdoc/tag/dictionary/definitions.js b/rhino_modules/jsdoc/tag/dictionary/definitions.js index d62d8d7b..b1a70acd 100644 --- a/rhino_modules/jsdoc/tag/dictionary/definitions.js +++ b/rhino_modules/jsdoc/tag/dictionary/definitions.js @@ -5,576 +5,575 @@ @author Michael Mathews @license Apache License 2.0 - See file 'LICENSE.md' in this project. */ -(function() { - /** Populate the given dictionary with all known JSDoc tag definitions. - @param {module:jsdoc/tag/dictionary} dictionary - */ - exports.defineTags = function(dictionary) { - - dictionary.defineTag('access', { - mustHaveValue: true, - onTagged: function(doclet, tag) { - // only valid values are private and protected, public is default - if ( /^(private|protected)$/i.test(tag.value) ) { - doclet.access = tag.value.toLowerCase(); - } - else { - delete doclet.access; - } - } - }); - - dictionary.defineTag('alias', { - mustHaveValue: true, - onTagged: function(doclet, tag) { - doclet.alias = tag.value; - } - }); - - dictionary.defineTag('author', { - mustHaveValue: true, - onTagged: function(doclet, tag) { - if (!doclet.author) { doclet.author = []; } - doclet.author.push(tag.value); - } - }); - - // I add on to that - dictionary.defineTag('augments', { - mustHaveValue: true, - onTagged: function(doclet, tag) { - doclet.augment( firstWordOf(tag.value) ); - } - }) - .synonym('extends'); - - // that adds on to me - dictionary.defineTag('borrows', { - mustHaveValue: true, - onTagged: function(doclet, tag) { - var [target, source] = parseBorrows(doclet, tag); - doclet.borrow(target, source); - } - }); - - // that adds all of it's members to me - dictionary.defineTag('mixes', { - mustHaveValue: true, - onTagged: function(doclet, tag) { - var source = firstWordOf(tag.value); - doclet.mix(source); - } - }); - - dictionary.defineTag('class', { - onTagged: function(doclet, tag) { - doclet.addTag('kind', 'class'); - - // handle special case where both @class and @constructor tags exist in same doclet - if (tag.originalTitle === 'class') { - var looksLikeDesc = (tag.value || '').match(/\S+\s+\S+/); // multiple words after @class? - if ( looksLikeDesc || /@construct(s|or)\b/i.test(doclet.comment) ) { - doclet.classdesc = tag.value; // treat the @class tag as a @classdesc tag instead - return; - } - } - - setDocletNameToValue(doclet, tag); - } - }) - .synonym('constructor'); - - dictionary.defineTag('classdesc', { - onTagged: function(doclet, tag) { - doclet.classdesc = tag.value; - } - }); - - dictionary.defineTag('constant', { - canHaveType: true, - onTagged: function(doclet, tag) { - setDocletKindToTitle(doclet, tag); - setDocletNameToValue(doclet, tag); - if (tag.value && tag.value.type) { - doclet.type = tag.value.type; - } - } - }) - .synonym('const'); - - dictionary.defineTag('copyright', { - mustHaveValue: true, - onTagged: function(doclet, tag) { - doclet.copyright = tag.value; - } - }); - - dictionary.defineTag('constructs', { - onTagged: function(doclet, tag) { - var ownerClassName; - if (!tag.value) { - ownerClassName = '{@thisClass}'; // this can be resolved later in the handlers - } - else { - ownerClassName = firstWordOf(tag.value); - } - doclet.addTag('alias', ownerClassName); - doclet.addTag('kind', 'class'); - } - }); - dictionary.defineTag('defaultvalue', { - onTagged: function(doclet, tag) { - if (tag.value) { - doclet.defaultvalue = tag.value; - } - else if (doclet.meta && doclet.meta.code && typeof doclet.meta.code.value !== 'undefined') { - if (doclet.meta.code.type && /STRING|NUMBER|NAME|TRUE|FALSE/.test(doclet.meta.code.type)) { - doclet.defaultvalue = doclet.meta.code.value; - if (doclet.meta.code.type === 'STRING') { - // TODO: handle escaped quotes in values - doclet.defaultvalue = '"'+doclet.defaultvalue.replace(/"/g, '\\"')+'"' - } - - if (doclet.defaultvalue === 'TRUE' || doclet.defaultvalue == 'FALSE') { - doclet.defaultvalue = doclet.defaultvalue.toLowerCase(); - } - } - else if (doclet.meta.code.type === 'NULL') { - // TODO: handle escaped quotes in values - doclet.defaultvalue = 'null' - } - } - } - }) - .synonym('default'); - - dictionary.defineTag('deprecated', { - // value is optional - onTagged: function(doclet, tag) { - doclet.deprecated = tag.value || true; - } - }); - - dictionary.defineTag('description', { - mustHaveValue: true - }) - .synonym('desc'); - - dictionary.defineTag('event', { - onTagged: function(doclet, tag) { - setDocletKindToTitle(doclet, tag); - setDocletNameToValue(doclet, tag); - applyNamespace(doclet, tag); - } - }); - - dictionary.defineTag('example', { - keepsWhitespace: true, - mustHaveValue: true, - onTagged: function(doclet, tag) { - if (!doclet.examples) { doclet.examples = []; } - doclet.examples.push(tag.value); - } - }); - - dictionary.defineTag('exception', { - mustHaveValue: true, - canHaveType: true, - onTagged: function(doclet, tag) { - if (!doclet.exceptions) { doclet.exceptions = []; } - doclet.exceptions.push(tag.value); - if (tag.value && tag.value.type) { - doclet.type = tag.value.type; - } - } - }) - .synonym('throws'); - - dictionary.defineTag('external', { - canHaveType: true, - isNamespace: true, - onTagged: function(doclet, tag) { - setDocletKindToTitle(doclet, tag); - setDocletNameToValue(doclet, tag); - if (tag.value && tag.value.type) { - doclet.type = tag.value.type; - } - } - }); - - dictionary.defineTag('exports', { - mustHaveValue: true, - onTagged: function(doclet, tag) { - var modName = firstWordOf(tag.value); - - doclet.addTag('alias', modName); - doclet.addTag('kind', 'module'); - } - }); - - dictionary.defineTag('file', { - onTagged: function(doclet, tag) { - setNameToFile(doclet, tag); - setDocletKindToTitle(doclet, tag); - setDocletDescriptionToValue(doclet, tag); - - doclet.preserveName = true; - } - }) - .synonym('fileoverview') - .synonym('overview'); - - dictionary.defineTag('fires', { - mustHaveValue: true, - onTagged: function(doclet, tag) { - if (!doclet.fires) { doclet.fires = []; } - doclet.fires.push(tag.value); - } - }); - - dictionary.defineTag('function', { - onTagged: function(doclet, tag) { - setDocletKindToTitle(doclet, tag); - setDocletNameToValue(doclet, tag); - } - }) - .synonym('func') - .synonym('method'); - - dictionary.defineTag('global', { - mustNotHaveValue: true, - onTagged: function(doclet, tag) { - doclet.scope = 'global'; - delete doclet.memberof; - } - }); - - dictionary.defineTag('ignore', { - mustNotHaveValue: true, - onTagged: function(doclet, tag) { - doclet.ignore = true; - } - }); - - dictionary.defineTag('inner', { - onTagged: function(doclet, tag) { - setDocletScopeToTitle(doclet, tag); - } - }); - - dictionary.defineTag('instance', { - onTagged: function(doclet, tag) { - setDocletScopeToTitle(doclet, tag); - } - }); - - dictionary.defineTag('kind', { - mustHaveValue: true - }); - - dictionary.defineTag('lends', { - onTagged: function(doclet, tag) { - doclet.alias = tag.value || ''; - doclet.addTag('undocumented'); - } - }); - - dictionary.defineTag('license', { - mustHaveValue: true, - onTagged: function(doclet, tag) { - doclet.license = tag.value; - } - }); - - dictionary.defineTag('memberof', { - mustHaveValue: true, - onTagged: function(doclet, tag) { - setDocletMemberof(doclet, tag); - } - }) - .synonym('member'); - - dictionary.defineTag('mixin', { - onTagged: function(doclet, tag) { - setDocletKindToTitle(doclet, tag); - setDocletNameToValue(doclet, tag); - } - }); - - dictionary.defineTag('module', { - canHaveType: true, - isNamespace: true, - onTagged: function(doclet, tag) { - setDocletKindToTitle(doclet, tag); - setDocletNameToValue(doclet, tag); - doclet.name || setDocletNameToFilename(doclet, tag); - if (tag.value && tag.value.type) { - doclet.type = tag.value.type; - } - } - }); - - dictionary.defineTag('name', { - mustHaveValue: true - }); - - dictionary.defineTag('namespace', { - canHaveType: true, - onTagged: function(doclet, tag) { - setDocletKindToTitle(doclet, tag); - setDocletNameToValue(doclet, tag); - if (tag.value && tag.value.type) { - doclet.type = tag.value.type; - } - } - }); - - dictionary.defineTag('param', { - mustHaveValue: true, - canHaveType: true, - canHaveName: true, - onTagged: function(doclet, tag) { - if (!doclet.params) { doclet.params = []; } - doclet.params.push(tag.value); - } - }) - .synonym('argument') - .synonym('arg'); - - dictionary.defineTag('private', { - mustNotHaveValue: true, - onTagged: function(doclet, tag) { - doclet.access = 'private'; - } - }); - - dictionary.defineTag('property', { - canHaveType: true, - onTagged: function(doclet, tag) { - setDocletKindToTitle(doclet, tag); - setDocletNameToValue(doclet, tag); - if (tag.value && tag.value.type) { - doclet.type = tag.value.type; - } - } - }) - .synonym('prop') - .synonym('var'); - - dictionary.defineTag('protected', { - mustNotHaveValue: true, - onTagged: function(doclet, tag) { - doclet.access = 'protected'; - } - }); - - dictionary.defineTag('public', { - mustNotHaveValue: true, - onTagged: function(doclet, tag) { - delete doclet.access; // public is default - } - }); - - // use this instead of old deprecated @final tag - dictionary.defineTag('readonly', { - mustNotHaveValue: true, - onTagged: function(doclet, tag) { - doclet.readonly = true; - } - }); - - dictionary.defineTag('requires', { - mustHaveValue: true, - onTagged: function(doclet, tag) { - var modName = firstWordOf(tag.value); - if (modName.indexOf('module:') !== 0) { - modName = 'module:'+modName; - } - if (!doclet.requires) { doclet.requires = []; } - doclet.requires.push(modName); - } - }); - - dictionary.defineTag('returns', { - mustHaveValue: true, - canHaveType: true, - onTagged: function(doclet, tag) { - if (!doclet.returns) { doclet.returns = []; } - doclet.returns.push(tag.value); - } - }) - .synonym('return'); - - dictionary.defineTag('see', { - mustHaveValue: true, - onTagged: function(doclet, tag) { - if (!doclet.see) { doclet.see = []; } - doclet.see.push(tag.value); - } - }); - - dictionary.defineTag('since', { - mustHaveValue: true, - onTagged: function(doclet, tag) { - doclet.since = tag.value; - } - }); - - dictionary.defineTag('static', { - onTagged: function(doclet, tag) { - setDocletScopeToTitle(doclet, tag); - } - }); - - dictionary.defineTag('summary', { - mustHaveValue: true, - onTagged: function(doclet, tag) { - doclet.summary = tag.value; - } - }); - - dictionary.defineTag('this', { - mustHaveValue: true, - onTagged: function(doclet, tag) { - if (!doclet.see) { doclet.see = []; } - doclet['this'] = firstWordOf(tag.value); - } - }); - - dictionary.defineTag('todo', { - mustHaveValue: true, - onTagged: function(doclet, tag) { - if (!doclet.todo) { doclet.todo = []; } - doclet.todo.push(tag.value); - } - }); - - dictionary.defineTag('type', { - mustHaveValue: true, - canHaveType: true, - onTagText: function(text) { - // any text must be formatted as a type, but for back compat braces are optional - if ( ! /^\{.+\}$/.test(text) ) { - text = '{ '+text+' }'; - } - return text; - }, - onTagged: function(doclet, tag) { - if (tag.value && tag.value.type) { - doclet.type = tag.value.type; - if (doclet.kind === 'function') doclet.addTag('returns', tag.text); // for backwards compatibility we allow @type for functions to imply return type - } - } - }); - - dictionary.defineTag('typedef', { - canHaveType: true, - canHaveName: true, - onTagged: function(doclet, tag) { - setDocletKindToTitle(doclet, tag); - - if (tag.value) { - if (tag.value.name) { - doclet.addTag('name', tag.value.name); - } - if (tag.value.type) { - doclet.type = tag.value.type; - } - } - } - }); - - dictionary.defineTag('undocumented', { - mustNotHaveValue: true, - onTagged: function(doclet, tag) { - doclet.undocumented = true; - doclet.comment = ''; - } - }); - - dictionary.defineTag('variation', { - mustHaveValue: true, - onTagged: function(doclet, tag) { - doclet.variation = tag.value; - } - }); - - dictionary.defineTag('version', { - mustHaveValue: true, - onTagged: function(doclet, tag) { - doclet.version = tag.value; - } - }); - } +/** Populate the given dictionary with all known JSDoc tag definitions. + @param {module:jsdoc/tag/dictionary} dictionary +*/ +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); + dictionary.defineTag('access', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + // only valid values are private and protected, public is default + if ( /^(private|protected)$/i.test(tag.value) ) { + doclet.access = tag.value.toLowerCase(); + } + else { + delete doclet.access; + } } - 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) { doclet.addTag( 'name', 'file:'+doclet.meta.filename ); } - } - - function setDocletMemberof(doclet, tag) { - doclet.setMemberof(tag.value); - } + }); + + dictionary.defineTag('alias', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + doclet.alias = tag.value; + } + }); + + dictionary.defineTag('author', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + if (!doclet.author) { doclet.author = []; } + doclet.author.push(tag.value); + } + }); + + // I add on to that + dictionary.defineTag('augments', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + doclet.augment( firstWordOf(tag.value) ); + } + }) + .synonym('extends'); + + // that adds on to me + dictionary.defineTag('borrows', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + var [target, source] = parseBorrows(doclet, tag); + doclet.borrow(target, source); + } + }); + + // that adds all of it's members to me + dictionary.defineTag('mixes', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + var source = firstWordOf(tag.value); + doclet.mix(source); + } + }); + + dictionary.defineTag('class', { + onTagged: function(doclet, tag) { + doclet.addTag('kind', 'class'); + + // handle special case where both @class and @constructor tags exist in same doclet + if (tag.originalTitle === 'class') { + var looksLikeDesc = (tag.value || '').match(/\S+\s+\S+/); // multiple words after @class? + if ( looksLikeDesc || /@construct(s|or)\b/i.test(doclet.comment) ) { + doclet.classdesc = tag.value; // treat the @class tag as a @classdesc tag instead + return; + } + } + + setDocletNameToValue(doclet, tag); + } + }) + .synonym('constructor'); + + dictionary.defineTag('classdesc', { + onTagged: function(doclet, tag) { + doclet.classdesc = tag.value; + } + }); + + dictionary.defineTag('constant', { + canHaveType: true, + onTagged: function(doclet, tag) { + setDocletKindToTitle(doclet, tag); + setDocletNameToValue(doclet, tag); + if (tag.value && tag.value.type) { + doclet.type = tag.value.type; + } + } + }) + .synonym('const'); + + dictionary.defineTag('copyright', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + doclet.copyright = tag.value; + } + }); + + dictionary.defineTag('constructs', { + onTagged: function(doclet, tag) { + var ownerClassName; + if (!tag.value) { + ownerClassName = '{@thisClass}'; // this can be resolved later in the handlers + } + else { + ownerClassName = firstWordOf(tag.value); + } + doclet.addTag('alias', ownerClassName); + doclet.addTag('kind', 'class'); + } + }); - function applyNamespace(doclet, tag) { - if (!doclet.name) return; // error? - - //doclet.displayname = doclet.name; - doclet.longname = app.jsdoc.name.applyNamespace(doclet.name, tag.title) - } - - function setDocletNameToFilename(doclet, tag) { - var name = 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 [ m[1], m[2] ]; - } - else if (m[1]) { - return [ m[1] ]; - } - } - } - - function firstWordOf(string) { - var m = /^(\S+)/.exec(string); - if (m) { return m[1]; } - else { return ''; } - } -})(); \ No newline at end of file + dictionary.defineTag('defaultvalue', { + onTagged: function(doclet, tag) { + if (tag.value) { + doclet.defaultvalue = tag.value; + } + else if (doclet.meta && doclet.meta.code && typeof doclet.meta.code.value !== 'undefined') { + if (doclet.meta.code.type && /STRING|NUMBER|NAME|TRUE|FALSE/.test(doclet.meta.code.type)) { + doclet.defaultvalue = doclet.meta.code.value; + if (doclet.meta.code.type === 'STRING') { + // TODO: handle escaped quotes in values + doclet.defaultvalue = '"'+doclet.defaultvalue.replace(/"/g, '\\"')+'"' + } + + if (doclet.defaultvalue === 'TRUE' || doclet.defaultvalue == 'FALSE') { + doclet.defaultvalue = doclet.defaultvalue.toLowerCase(); + } + } + else if (doclet.meta.code.type === 'NULL') { + // TODO: handle escaped quotes in values + doclet.defaultvalue = 'null' + } + } + } + }) + .synonym('default'); + + dictionary.defineTag('deprecated', { + // value is optional + onTagged: function(doclet, tag) { + doclet.deprecated = tag.value || true; + } + }); + + dictionary.defineTag('description', { + mustHaveValue: true + }) + .synonym('desc'); + + dictionary.defineTag('event', { + onTagged: function(doclet, tag) { + setDocletKindToTitle(doclet, tag); + setDocletNameToValue(doclet, tag); + applyNamespace(doclet, tag); + } + }); + + dictionary.defineTag('example', { + keepsWhitespace: true, + mustHaveValue: true, + onTagged: function(doclet, tag) { + if (!doclet.examples) { doclet.examples = []; } + doclet.examples.push(tag.value); + } + }); + + dictionary.defineTag('exception', { + mustHaveValue: true, + canHaveType: true, + onTagged: function(doclet, tag) { + if (!doclet.exceptions) { doclet.exceptions = []; } + doclet.exceptions.push(tag.value); + if (tag.value && tag.value.type) { + doclet.type = tag.value.type; + } + } + }) + .synonym('throws'); + + dictionary.defineTag('external', { + canHaveType: true, + isNamespace: true, + onTagged: function(doclet, tag) { + setDocletKindToTitle(doclet, tag); + setDocletNameToValue(doclet, tag); + if (tag.value && tag.value.type) { + doclet.type = tag.value.type; + } + } + }); + + dictionary.defineTag('exports', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + var modName = firstWordOf(tag.value); + + doclet.addTag('alias', modName); + doclet.addTag('kind', 'module'); + } + }); + + dictionary.defineTag('file', { + onTagged: function(doclet, tag) { + setNameToFile(doclet, tag); + setDocletKindToTitle(doclet, tag); + setDocletDescriptionToValue(doclet, tag); + + doclet.preserveName = true; + } + }) + .synonym('fileoverview') + .synonym('overview'); + + dictionary.defineTag('fires', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + if (!doclet.fires) { doclet.fires = []; } + doclet.fires.push(tag.value); + } + }); + + dictionary.defineTag('function', { + onTagged: function(doclet, tag) { + setDocletKindToTitle(doclet, tag); + setDocletNameToValue(doclet, tag); + } + }) + .synonym('func') + .synonym('method'); + + dictionary.defineTag('global', { + mustNotHaveValue: true, + onTagged: function(doclet, tag) { + doclet.scope = 'global'; + delete doclet.memberof; + } + }); + + dictionary.defineTag('ignore', { + mustNotHaveValue: true, + onTagged: function(doclet, tag) { + doclet.ignore = true; + } + }); + + dictionary.defineTag('inner', { + onTagged: function(doclet, tag) { + setDocletScopeToTitle(doclet, tag); + } + }); + + dictionary.defineTag('instance', { + onTagged: function(doclet, tag) { + setDocletScopeToTitle(doclet, tag); + } + }); + + dictionary.defineTag('kind', { + mustHaveValue: true + }); + + dictionary.defineTag('lends', { + onTagged: function(doclet, tag) { + doclet.alias = tag.value || ''; + doclet.addTag('undocumented'); + } + }); + + dictionary.defineTag('license', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + doclet.license = tag.value; + } + }); + + dictionary.defineTag('memberof', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + setDocletMemberof(doclet, tag); + } + }) + .synonym('member'); + + dictionary.defineTag('mixin', { + onTagged: function(doclet, tag) { + setDocletKindToTitle(doclet, tag); + setDocletNameToValue(doclet, tag); + } + }); + + dictionary.defineTag('module', { + canHaveType: true, + isNamespace: true, + onTagged: function(doclet, tag) { + setDocletKindToTitle(doclet, tag); + setDocletNameToValue(doclet, tag); + doclet.name || setDocletNameToFilename(doclet, tag); + if (tag.value && tag.value.type) { + doclet.type = tag.value.type; + } + } + }); + + dictionary.defineTag('name', { + mustHaveValue: true + }); + + dictionary.defineTag('namespace', { + canHaveType: true, + onTagged: function(doclet, tag) { + setDocletKindToTitle(doclet, tag); + setDocletNameToValue(doclet, tag); + if (tag.value && tag.value.type) { + doclet.type = tag.value.type; + } + } + }); + + dictionary.defineTag('param', { + mustHaveValue: true, + canHaveType: true, + canHaveName: true, + onTagged: function(doclet, tag) { + if (!doclet.params) { doclet.params = []; } + doclet.params.push(tag.value); + } + }) + .synonym('argument') + .synonym('arg'); + + dictionary.defineTag('private', { + mustNotHaveValue: true, + onTagged: function(doclet, tag) { + doclet.access = 'private'; + } + }); + + dictionary.defineTag('property', { + canHaveType: true, + onTagged: function(doclet, tag) { + setDocletKindToTitle(doclet, tag); + setDocletNameToValue(doclet, tag); + if (tag.value && tag.value.type) { + doclet.type = tag.value.type; + } + } + }) + .synonym('prop') + .synonym('var'); + + dictionary.defineTag('protected', { + mustNotHaveValue: true, + onTagged: function(doclet, tag) { + doclet.access = 'protected'; + } + }); + + dictionary.defineTag('public', { + mustNotHaveValue: true, + onTagged: function(doclet, tag) { + delete doclet.access; // public is default + } + }); + + // use this instead of old deprecated @final tag + dictionary.defineTag('readonly', { + mustNotHaveValue: true, + onTagged: function(doclet, tag) { + doclet.readonly = true; + } + }); + + dictionary.defineTag('requires', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + var modName = firstWordOf(tag.value); + if (modName.indexOf('module:') !== 0) { + modName = 'module:'+modName; + } + if (!doclet.requires) { doclet.requires = []; } + doclet.requires.push(modName); + } + }); + + dictionary.defineTag('returns', { + mustHaveValue: true, + canHaveType: true, + onTagged: function(doclet, tag) { + if (!doclet.returns) { doclet.returns = []; } + doclet.returns.push(tag.value); + } + }) + .synonym('return'); + + dictionary.defineTag('see', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + if (!doclet.see) { doclet.see = []; } + doclet.see.push(tag.value); + } + }); + + dictionary.defineTag('since', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + doclet.since = tag.value; + } + }); + + dictionary.defineTag('static', { + onTagged: function(doclet, tag) { + setDocletScopeToTitle(doclet, tag); + } + }); + + dictionary.defineTag('summary', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + doclet.summary = tag.value; + } + }); + + dictionary.defineTag('this', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + if (!doclet.see) { doclet.see = []; } + doclet['this'] = firstWordOf(tag.value); + } + }); + + dictionary.defineTag('todo', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + if (!doclet.todo) { doclet.todo = []; } + doclet.todo.push(tag.value); + } + }); + + dictionary.defineTag('type', { + mustHaveValue: true, + canHaveType: true, + onTagText: function(text) { + // any text must be formatted as a type, but for back compat braces are optional + if ( ! /^\{.+\}$/.test(text) ) { + text = '{ '+text+' }'; + } + return text; + }, + onTagged: function(doclet, tag) { + if (tag.value && tag.value.type) { + doclet.type = tag.value.type; + if (doclet.kind === 'function') doclet.addTag('returns', tag.text); // for backwards compatibility we allow @type for functions to imply return type + } + } + }); + + dictionary.defineTag('typedef', { + canHaveType: true, + canHaveName: true, + onTagged: function(doclet, tag) { + setDocletKindToTitle(doclet, tag); + + if (tag.value) { + if (tag.value.name) { + doclet.addTag('name', tag.value.name); + } + if (tag.value.type) { + doclet.type = tag.value.type; + } + } + } + }); + + dictionary.defineTag('undocumented', { + mustNotHaveValue: true, + onTagged: function(doclet, tag) { + doclet.undocumented = true; + doclet.comment = ''; + } + }); + + dictionary.defineTag('variation', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + doclet.variation = tag.value; + } + }); + + dictionary.defineTag('version', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + doclet.version = tag.value; + } + }); +} + +/** @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) { doclet.addTag( 'name', 'file:'+doclet.meta.filename ); } +} + +function setDocletMemberof(doclet, tag) { + doclet.setMemberof(tag.value); +} + +function applyNamespace(doclet, tag) { + if (!doclet.name) return; // error? + + //doclet.displayname = doclet.name; + doclet.longname = app.jsdoc.name.applyNamespace(doclet.name, tag.title) +} + +function setDocletNameToFilename(doclet, tag) { + var name = 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 [ m[1], m[2] ]; + } + else if (m[1]) { + return [ m[1] ]; + } + } +} + +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 04bdc280..457e1607 100644 --- a/rhino_modules/jsdoc/tag/type.js +++ b/rhino_modules/jsdoc/tag/type.js @@ -5,109 +5,107 @@ @license Apache License 2.0 - See file 'LICENSE.md' in this project. */ -(function() { - - /** - @param {string} tagValue - @returns {Array.} - */ - exports.parse = function(tagValue) { - if (typeof tagValue !== 'string') { tagValue = ''; } - var type = '', - text = '', - count = 0, - optional, - nullable, - variable; - - // 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; - } +/** + @param {string} tagValue + @returns {Array.} + */ +exports.parse = function(tagValue) { + if (typeof tagValue !== 'string') { tagValue = ''; } + var type = '', + text = '', + count = 0, + optional, + nullable, + variable; + + // 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; } } + } - if (type === '') { text = tagValue; } - - [type, optional] = parseOptional(type); - [type, nullable] = parseNullable(type); - [type, variable] = parseVariable(type); + if (type === '') { text = tagValue; } - type = parseTypes(type); // make it into an array + [type, optional] = parseOptional(type); + [type, nullable] = parseNullable(type); + [type, variable] = parseVariable(type); - return [type, text, optional, nullable, variable]; + type = parseTypes(type); // make it into an array + + return [type, text, optional, nullable, variable]; +} + +function parseOptional(type) { + var optional = null; + + // {sometype=} means optional + if ( /(.+)=$/.test(type) ) { + type = RegExp.$1; + optional = true; } - function parseOptional(type) { - var optional = null; - - // {sometype=} means optional - if ( /(.+)=$/.test(type) ) { + return [type, 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, nullable]; +} + +function parseVariable(type) { + var variable = null; + + // {...sometype} means variable number of that type + if ( /^(\.\.\.)(.+)$/.test(type) ) { + type = RegExp.$2; + variable = true; + } + + return [type, variable]; +} + +function parseTypes(type) { + var types = []; + + if ( ~type.indexOf('|') ) { + // 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; - optional = true; } - - return [type, optional]; + types = type.split(/\s*\|\s*/g); + } + else if (type) { + types = [type]; } - 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, nullable]; - } - - function parseVariable(type) { - var variable = null; - - // {...sometype} means variable number of that type - if ( /^(\.\.\.)(.+)$/.test(type) ) { - type = RegExp.$2; - variable = true; - } - - return [type, variable]; - } - - function parseTypes(type) { - var types = []; - - if ( ~type.indexOf('|') ) { - // 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; - } + return types; +} - /** @private */ - function trim(text) { - return text.replace(/^\s+|\s+$/g, ''); - } -})(); \ No newline at end of file +/** @private */ +function trim(text) { + return text.replace(/^\s+|\s+$/g, ''); +} diff --git a/rhino_modules/jsdoc/tag/validator.js b/rhino_modules/jsdoc/tag/validator.js index 7f714529..e4f77c6d 100644 --- a/rhino_modules/jsdoc/tag/validator.js +++ b/rhino_modules/jsdoc/tag/validator.js @@ -5,48 +5,47 @@ @author Michael Mathews @license Apache License 2.0 - See file 'LICENSE.md' in this project. */ -(function() { - - var dictionary = require('jsdoc/tag/dictionary'); - - /** - Validate the given tag. - */ - exports.validate = function(tag, meta) { - var tagDef = dictionary.lookUp(tag.title); - - if (!tagDef && !env.conf.tags.allowUnknownTags) { - throw new UnknownTagError(tag.title, meta); - } - - if (!tag.text) { - if (tagDef.mustHaveValue) { - throw new TagValueRequiredError(tag.title, meta); - } - } - else { - if (tagDef.mustNotHaveValue) { - throw new TagValueNotPermittedError(tag.title, 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; + + +var dictionary = require('jsdoc/tag/dictionary'); + +/** + Validate the given tag. + */ +exports.validate = function(tag, meta) { + var tagDef = dictionary.lookUp(tag.title); + + if (!tagDef && !env.conf.tags.allowUnknownTags) { + throw new UnknownTagError(tag.title, meta); } - 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; + + if (!tag.text) { + if (tagDef.mustHaveValue) { + throw new TagValueRequiredError(tag.title, meta); + } } - TagValueRequiredError.prototype = Error.prototype; - - function TagValueNotPermittedError(tagName, message, meta) { - this.name = 'TagValueNotPermittedError'; - this.message = 'The @' + tagName + ' tag does not permit a value: "' + message + '". File: ' + meta.filename + ', Line: ' + meta.lineno + '\n' + meta.comment; + else { + if (tagDef.mustNotHaveValue) { + throw new TagValueNotPermittedError(tag.title, meta); + } } - TagValueNotPermittedError.prototype = Error.prototype; - -})(); \ No newline at end of file +} + +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, message, meta) { + this.name = 'TagValueNotPermittedError'; + this.message = 'The @' + tagName + ' tag does not permit a value: "' + message + '". 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 b7a094d9..1e13d2e0 100644 --- a/rhino_modules/jsdoc/util/dumper.js +++ b/rhino_modules/jsdoc/util/dumper.js @@ -4,155 +4,154 @@ @author Michael Mathews @license Apache License 2.0 - See file 'LICENSE.md' in this project. */ -(function() { - /** - @param {any} object - */ - exports.dump = function(object) { - indentBy = 0; - output = ''; - - walk(object); - outdent(false); - return output; - } - - const INDENTATION = ' '; // 4 spaces - var indentBy, - output; - - function pad(depth) { - var padding = ''; - while (depth--) { - padding += INDENTATION; - } - return padding; - } - - /** - @param {string} openingBrace - The opening brace to add, like "{". - @private - @inner - @memberof module:common/dumper - */ - function indent(openingBrace) { - indentBy++; - if (openingBrace) output += openingBrace + '\n'; - } - - /** - @param {string|boolean} closingBrace - The closing brace to add, like "}" or if boolean - `false` no closing brace or trailing newline. - @private - @inner - @memberof module:common/dumper - */ - function outdent(closingBrace) { - indentBy--; - output = output.replace(/,\n$/, '\n'); // trim trailing comma - if (closingBrace === false) { output = output.replace(/\n$/, ''); } - else if (closingBrace) output += pad(indentBy) + closingBrace + ',\n'; - } - - var seen = []; - seen.has = function(object) { - for (var i = 0, l = seen.length; i < l; i++) { - if (seen[i] === object) { return true; } - } - return false; - } - - function walk(object) { - var value; - - if ( value = getValue(object) ) { - output += value + ',\n'; - } - else if ( isUnwalkable(object) ) { - output += ',\n' - } - else if ( isRegExp(object) ) { - output += ',\n' - } - else if ( isDate(object) ) { - output += ',\n' - } - else if ( isFunction(object) ) { - output += ',\n'; - } - else if ( isArray(object) ) { - if ( seen.has(object) ) { - output += ',\n'; - return; - } - else { - seen.push(object); - } - - indent('['); - for (var i = 0, leni = object.length; i < leni; i++) { - output += pad(indentBy); // + i + ': '; - walk( object[i] ); - } - outdent(']'); - } - else if ( isObject(object) ) { - if ( seen.has(object) ) { - output += ',\n'; - return; - } - else { - seen.push(object); - } - - indent('{'); - for (var p in object) { - if ( object.hasOwnProperty(p) ) { - output += pad(indentBy) + stringify(p) + ': '; - walk( object[p] ); - } - } - outdent('}'); - } - } - - 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 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'); - } -})(); \ No newline at end of file +/** + @param {any} object + */ +exports.dump = function(object) { + indentBy = 0; + output = ''; + + walk(object); + outdent(false); + return output; +} + +const INDENTATION = ' '; // 4 spaces +var indentBy, + output; + +function pad(depth) { + var padding = ''; + while (depth--) { + padding += INDENTATION; + } + return padding; +} + +/** + @param {string} openingBrace - The opening brace to add, like "{". + @private + @inner + @memberof module:common/dumper + */ +function indent(openingBrace) { + indentBy++; + if (openingBrace) output += openingBrace + '\n'; +} + +/** + @param {string|boolean} closingBrace - The closing brace to add, like "}" or if boolean + `false` no closing brace or trailing newline. + @private + @inner + @memberof module:common/dumper + */ +function outdent(closingBrace) { + indentBy--; + output = output.replace(/,\n$/, '\n'); // trim trailing comma + if (closingBrace === false) { output = output.replace(/\n$/, ''); } + else if (closingBrace) output += pad(indentBy) + closingBrace + ',\n'; +} + +var seen = []; +seen.has = function(object) { + for (var i = 0, l = seen.length; i < l; i++) { + if (seen[i] === object) { return true; } + } + return false; +} + +function walk(object) { + var value; + + if ( value = getValue(object) ) { + output += value + ',\n'; + } + else if ( isUnwalkable(object) ) { + output += ',\n' + } + else if ( isRegExp(object) ) { + output += ',\n' + } + else if ( isDate(object) ) { + output += ',\n' + } + else if ( isFunction(object) ) { + output += ',\n'; + } + else if ( isArray(object) ) { + if ( seen.has(object) ) { + output += ',\n'; + return; + } + else { + seen.push(object); + } + + indent('['); + for (var i = 0, leni = object.length; i < leni; i++) { + output += pad(indentBy); // + i + ': '; + walk( object[i] ); + } + outdent(']'); + } + else if ( isObject(object) ) { + if ( seen.has(object) ) { + output += ',\n'; + return; + } + else { + seen.push(object); + } + + indent('{'); + for (var p in object) { + if ( object.hasOwnProperty(p) ) { + output += pad(indentBy) + stringify(p) + ': '; + walk( object[p] ); + } + } + outdent('}'); + } +} + +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 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/path.js b/rhino_modules/path.js new file mode 100644 index 00000000..4f9c6832 --- /dev/null +++ b/rhino_modules/path.js @@ -0,0 +1,17 @@ + +exports.basename = function(path) { + var parts = path.split('/'); + parts.pop(); + path = parts.join('/'); + return path; +}; + +exports.existsSync = function(path) { + var file = new java.io.File(path); + + if (file.isFile()) { + return true; + } + + return false; +}; \ No newline at end of file diff --git a/rhino_modules/path/index.js b/rhino_modules/path/index.js deleted file mode 100644 index 22c4b434..00000000 --- a/rhino_modules/path/index.js +++ /dev/null @@ -1,18 +0,0 @@ - -module.exports = { - basename : function(path) { - var parts = path.split('/'); - parts.pop(); - path = parts.join('/'); - return path; - }, - existsSync: function(path) { - var file = new java.io.File(path); - - if (file.isFile()) { - return true; - } - - return false; - } -}; \ No newline at end of file diff --git a/rhino_modules/sys.js b/rhino_modules/sys.js new file mode 100644 index 00000000..d7af7e3f --- /dev/null +++ b/rhino_modules/sys.js @@ -0,0 +1,4 @@ + +exports.puts = function(str) { + print(String(str)); +}; diff --git a/rhino_modules/sys/index.js b/rhino_modules/sys/index.js deleted file mode 100644 index f7d76464..00000000 --- a/rhino_modules/sys/index.js +++ /dev/null @@ -1,6 +0,0 @@ - -module.exports = { - 'puts' : function(str) { - print(String(str)); - } -}; \ No newline at end of file