Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

jsdoc

Package Overview
Dependencies
Maintainers
1
Versions
51
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jsdoc - npm Package Compare versions

Comparing version 3.3.0-alpha2 to 3.3.0-alpha3

Gruntfile.js

322

cli.js

@@ -6,7 +6,7 @@ /**

*
* + The module should really export an instance of `JSDoc`, and `props` should be properties of a
* `JSDoc` instance. However, Rhino interpreted `this` as a reference to `global` within the
* + The module should really export an instance of `cli`, and `props` should be properties of a
* `cli` instance. However, Rhino interpreted `this` as a reference to `global` within the
* prototype's methods, so we couldn't do that.
* + Use the `fs` and `path` modules rather than `jsdoc/fs` and `jsdoc/path`, which are not
* initialized correctly when they're loaded this early.
* + On Rhino, for unknown reasons, the `jsdoc/fs` and `jsdoc/path` modules can fail in some cases
* when they are required by this module. You may need to use `fs` and `path` instead.
*

@@ -18,5 +18,11 @@ * @private

var logger = require('jsdoc/util/logger');
var hasOwnProp = Object.prototype.hasOwnProperty;
var props = {
docs: [],
packageJson: null
packageJson: null,
shouldExitWithError: false,
tmpdir: null
};

@@ -27,9 +33,12 @@

var JSDoc = {};
var FATAL_ERROR_MESSAGE = 'Exiting JSDoc because an error occurred. See the previous log ' +
'messages for details.';
var cli = {};
// TODO: docs
JSDoc.setVersionInfo = function() {
cli.setVersionInfo = function() {
var fs = require('fs');
var path = require('path');
// allow this to throw--something is really wrong if we can't read our own package file
var info = JSON.parse( fs.readFileSync(path.join(env.dirname, 'package.json'), 'utf8') );

@@ -42,7 +51,7 @@

return JSDoc;
return cli;
};
// TODO: docs
JSDoc.loadConfig = function() {
cli.loadConfig = function() {
var _ = require('underscore');

@@ -62,3 +71,8 @@ var args = require('jsdoc/opts/args');

env.opts = args.parse(env.args);
try {
env.opts = args.parse(env.args);
}
catch (e) {
cli.exit(1, e.message + '\n' + FATAL_ERROR_MESSAGE);
}

@@ -82,3 +96,4 @@ confPath = env.opts.configure || path.join(env.dirname, 'conf.json');

catch (e) {
throw new Error('Cannot parse the config file ' + confPath + ': ' + e);
cli.exit(1, 'Cannot parse the config file ' + confPath + ': ' + e + '\n' +
FATAL_ERROR_MESSAGE);
}

@@ -89,7 +104,65 @@

return JSDoc;
return cli;
};
// TODO: docs
JSDoc.runCommand = function(cb) {
cli.configureLogger = function() {
function recoverableError() {
props.shouldExitWithError = true;
}
function fatalError() {
cli.exit(1);
}
if (env.opts.debug) {
logger.setLevel(logger.LEVELS.DEBUG);
}
else if (env.opts.verbose) {
logger.setLevel(logger.LEVELS.INFO);
}
if (env.opts.pedantic) {
logger.once('logger:warn', recoverableError);
logger.once('logger:error', fatalError);
}
else {
logger.once('logger:error', recoverableError);
}
logger.once('logger:fatal', fatalError);
return cli;
};
// TODO: docs
cli.logStart = function() {
var loggerFunc = env.opts.help ? console.log : logger.info;
cli.printVersion(loggerFunc);
logger.debug('Environment info: %j', {
env: {
conf: env.conf,
opts: env.opts
}
});
};
// TODO: docs
cli.logFinish = function() {
var delta;
var deltaSeconds;
if (env.run.finish && env.run.start) {
delta = env.run.finish.getTime() - env.run.start.getTime();
}
if (delta !== undefined) {
deltaSeconds = (delta / 1000).toFixed(2);
logger.info('Finished running in %s seconds.', deltaSeconds);
}
};
// TODO: docs
cli.runCommand = function(cb) {
var cmd;

@@ -99,21 +172,31 @@

function done(errorCode) {
if (!errorCode && props.shouldExitWithError) {
cb(1);
}
else {
cb(errorCode);
}
}
if (opts.help) {
cmd = JSDoc.printHelp;
cmd = cli.printHelp;
}
else if (opts.test) {
cmd = JSDoc.runTests;
cmd = cli.runTests;
}
else if (opts.version) {
cmd = JSDoc.printVersion;
cmd = function(callback) { callback(); };
}
else {
cmd = JSDoc.main;
cmd = cli.main;
}
cmd(cb);
cmd(done);
};
// TODO: docs
JSDoc.printHelp = function(cb) {
console.log( require('jsdoc/opts/args').help() );
cli.printHelp = function(cb) {
console.log( '\n' + require('jsdoc/opts/args').help() + '\n' );
console.log('Visit http://usejsdoc.org for more information.');
cb(0);

@@ -123,3 +206,3 @@ };

// TODO: docs
JSDoc.runTests = function(cb) {
cli.runTests = function(cb) {
var path = require('jsdoc/path');

@@ -136,13 +219,22 @@

// TODO: docs
JSDoc.printVersion = function(cb) {
console.log('JSDoc %s (%s)', env.version.number, env.version.revision);
cb(0);
cli.getVersion = function() {
return 'JSDoc ' + env.version.number + ' (' + env.version.revision + ')';
};
// TODO: docs
JSDoc.main = function(cb) {
JSDoc.scanFiles();
cli.printVersion = function(loggerFunc, cb) {
loggerFunc = loggerFunc || logger.info;
loggerFunc.call( null, cli.getVersion() );
if (cb) {
cb(0);
}
};
// TODO: docs
cli.main = function(cb) {
cli.scanFiles();
if (env.sourceFiles.length) {
JSDoc.createParser()
cli.createParser()
.parseFiles()

@@ -156,3 +248,83 @@ .processParseResults();

JSDoc.scanFiles = function() {
function getRandomId() {
var MIN = 100000;
var MAX = 999999;
return Math.floor(Math.random() * (MAX - MIN + 1) + MIN);
}
// TODO: docs
function createTempDir() {
var fs = require('jsdoc/fs');
var path = require('jsdoc/path');
var wrench = require('wrench');
var isRhino;
var tempDirname;
var tempPath;
// We only need one temp directory
if (props.tmpdir) {
return props.tmpdir;
}
isRhino = require('jsdoc/util/runtime').isRhino();
tempDirname = 'tmp-' + Date.now() + '-' + getRandomId();
tempPath = path.join(env.dirname, tempDirname);
try {
fs.mkdirSync(tempPath);
props.tmpdir = path;
}
catch (e) {
logger.fatal('Unable to create the temp directory %s: %s', tempPath, e.message);
return null;
}
try {
// Delete the temp directory on exit
if (isRhino) {
( new java.io.File(tempPath) ).deleteOnExit();
}
else {
process.on('exit', function() {
wrench.rmdirSyncRecursive(tempPath);
});
}
return tempPath;
}
catch (e) {
logger.error('Cannot automatically delete the temp directory %s on exit: %s', tempPath,
e.message);
return null;
}
}
// TODO: docs
function copyResourceDir(filepath) {
var fs = require('jsdoc/fs');
var path = require('jsdoc/path');
var wrench = require('wrench');
var resourceDir;
var tmpDir;
try {
tmpDir = createTempDir();
resourceDir = path.join( tmpDir, path.basename(filepath) + '-' + getRandomId() );
fs.mkdirSync(resourceDir);
wrench.copyDirSyncRecursive(filepath, resourceDir);
return resourceDir;
}
catch (e) {
logger.fatal('Unable to copy %s to the temp directory %s: %s', filepath, resourceDir,
e.message);
return null;
}
}
// TODO: docs
cli.scanFiles = function() {
var Filter = require('jsdoc/src/filter').Filter;

@@ -192,8 +364,35 @@ var fs = require('jsdoc/fs');

return JSDoc;
return cli;
};
JSDoc.createParser = function() {
function resolvePluginPaths(paths) {
var path = require('jsdoc/path');
var isNode = require('jsdoc/util/runtime').isNode();
var pluginPaths = [];
paths.forEach(function(plugin) {
var basename = path.basename(plugin);
var dirname = path.dirname(plugin);
var pluginPath = path.getResourcePath(dirname);
if (!pluginPath) {
logger.error('Unable to find the plugin "%s"', plugin);
return;
}
// On Node.js, the plugin needs to be inside the JSDoc directory
else if ( isNode && (pluginPath.indexOf(global.env.dirname) !== 0) ) {
pluginPath = copyResourceDir(pluginPath);
}
pluginPaths.push( path.join(pluginPath, basename) );
});
return pluginPaths;
}
cli.createParser = function() {
var handlers = require('jsdoc/src/handlers');
var parser = require('jsdoc/src/parser');
var path = require('jsdoc/path');
var plugins = require('jsdoc/plugins');

@@ -204,2 +403,3 @@

if (env.conf.plugins) {
env.conf.plugins = resolvePluginPaths(env.conf.plugins);
plugins.installPlugins(env.conf.plugins, app.jsdoc.parser);

@@ -210,6 +410,6 @@ }

return JSDoc;
return cli;
};
JSDoc.parseFiles = function() {
cli.parseFiles = function() {
var augment = require('jsdoc/augment');

@@ -222,4 +422,3 @@ var borrow = require('jsdoc/borrow');

props.docs = docs = app.jsdoc.parser.parse(env.sourceFiles,
env.opts.encoding);
props.docs = docs = app.jsdoc.parser.parse(env.sourceFiles, env.opts.encoding);

@@ -231,4 +430,4 @@ // If there is no package.json, just create an empty package

logger.debug('Adding inherited symbols...');
borrow.indexAll(docs);
augment.addInherited(docs);

@@ -239,20 +438,24 @@ borrow.resolveBorrows(docs);

return JSDoc;
return cli;
};
JSDoc.processParseResults = function() {
cli.processParseResults = function() {
if (env.opts.explain) {
JSDoc.dumpParseResults();
cli.dumpParseResults();
}
else {
JSDoc.resolveTutorials();
JSDoc.generateDocs();
cli.resolveTutorials();
cli.generateDocs();
}
return cli;
};
JSDoc.dumpParseResults = function() {
cli.dumpParseResults = function() {
global.dump(props.docs);
return cli;
};
JSDoc.resolveTutorials = function() {
cli.resolveTutorials = function() {
var resolver = require('jsdoc/tutorial/resolver');

@@ -264,5 +467,7 @@

}
return cli;
};
JSDoc.generateDocs = function() {
cli.generateDocs = function() {
var path = require('jsdoc/path');

@@ -275,5 +480,16 @@ var resolver = require('jsdoc/tutorial/resolver');

env.opts.template = (function() {
var isNode = require('jsdoc/util/runtime').isNode();
var publish = env.opts.template || 'templates/default';
// if we don't find it, keep the user-specified value so the error message is useful
return path.getResourcePath(publish) || env.opts.template;
var templatePath = path.getResourcePath(publish);
if (templatePath && isNode) {
// On Node.js, the template needs to be inside the JSDoc folder
if (templatePath.indexOf(env.dirname) !== 0) {
templatePath = copyResourceDir(templatePath);
}
}
// if we didn't find the template, keep the user-specified value so the error message is
// useful
return templatePath || env.opts.template;
})();

@@ -285,3 +501,3 @@

catch(e) {
throw new Error('Unable to load template: ' + e.message || e);
logger.fatal('Unable to load template: ' + e.message || e);
}

@@ -291,4 +507,3 @@

if (template.publish && typeof template.publish === 'function') {
// convert this from a URI back to a path if necessary
env.opts.template = path._uriToPath(env.opts.template);
logger.printInfo('Generating output files...');
template.publish(

@@ -299,12 +514,19 @@ taffy(props.docs),

);
logger.info('complete.');
}
else {
throw new Error(env.opts.template + ' does not export a "publish" function. Global ' +
logger.fatal(env.opts.template + ' does not export a "publish" function. Global ' +
'"publish" functions are no longer supported.');
}
return cli;
};
return JSDoc;
// TODO: docs
cli.exit = function(exitCode) {
process.exit(exitCode || 0);
};
return cli;
})();

3

CONTRIBUTING.md

@@ -48,5 +48,2 @@ Pull Requests

should be separate branches and merge requests.
Also, if you want to change `package.json`, note that you must make your changes
in `Jake/templates/package.json.tmpl`, then run `jake`.

@@ -53,0 +50,0 @@ 5. **Add tests**

@@ -129,6 +129,3 @@ #!/usr/bin/env node

function cb(errorCode) {
process.exit(errorCode || 0);
}
var logger = require('jsdoc/util/logger');
var path = require('jsdoc/path');

@@ -142,2 +139,13 @@ var runtime = require('jsdoc/util/runtime');

if (!global.env.opts.test) {
cli.configureLogger();
}
cli.logStart();
function cb(errorCode) {
cli.logFinish();
cli.exit(errorCode || 0);
}
// On Rhino, we use a try/catch block so we can log the Java exception (if available)

@@ -150,7 +158,6 @@ if ( runtime.isRhino() ) {

if (e.rhinoException) {
e.rhinoException.printStackTrace();
process.exit(1);
logger.fatal( e.rhinoException.printStackTrace() );
} else {
console.trace(e);
process.exit(1);
cli.exit(1);
}

@@ -157,0 +164,0 @@ }

@@ -9,3 +9,4 @@ /**

var doop = require("jsdoc/util/doop").doop;
var doop = require('jsdoc/util/doop');
var logger = require('jsdoc/util/logger');

@@ -35,3 +36,4 @@ var hasOwnProp = Object.prototype.hasOwnProperty;

if (!docs.index) {
throw 'Docs has not been indexed: docs.index must be defined here.';
logger.error('Unable to resolve borrowed symbols, because the docs have not been indexed.');
return;
}

@@ -38,0 +40,0 @@

@@ -58,4 +58,3 @@ /**

var Syntax = jsdoc.src.Syntax;
if (type === Syntax.FunctionDeclaration || type === Syntax.FunctionExpression ||
type === 'function') {
if (type === Syntax.FunctionDeclaration || type === Syntax.FunctionExpression) {
return 'function';

@@ -180,3 +179,2 @@ }

if (!this.kind && this.meta && this.meta.code) {
//console.log('adding kind to: %j', this.meta.code);
this.addTag( 'kind', codetypeToKind(this.meta.code.type) );

@@ -339,3 +337,3 @@ }

}
/**

@@ -342,0 +340,0 @@ * Information about the code symbol.

/**
Parse the command line arguments.
@module jsdoc/opts/argparser
@author Michael Mathews <micmath@gmail.com>
@license Apache License 2.0 - See file 'LICENSE.md' in this project.
* Parse the command line arguments.
* @module jsdoc/opts/argparser
* @author Michael Mathews <micmath@gmail.com>
* @license Apache License 2.0 - See file 'LICENSE.md' in this project.
*/

@@ -14,27 +14,43 @@ 'use strict';

/**
Create an instance of the parser.
@classdesc A parser to interpret the key-value pairs entered on the command
line.
@constructor
* Create an instance of the parser.
* @classdesc A parser to interpret the key-value pairs entered on the command line.
* @constructor
*/
var ArgParser = function() {
this._options = [];
this._shortNameIndex = {};
this._longNameIndex = {};
this._options = [];
this._shortNameIndex = {};
this._longNameIndex = {};
};
ArgParser.prototype._getOptionByShortName = function(name) {
if (hasOwnProp.call(this._shortNameIndex, name)) {
return this._options[this._shortNameIndex[name]];
}
return null;
if (hasOwnProp.call(this._shortNameIndex, name)) {
return this._options[this._shortNameIndex[name]];
}
return null;
};
ArgParser.prototype._getOptionByLongName = function(name) {
if (hasOwnProp.call(this._longNameIndex, name)) {
return this._options[this._longNameIndex[name]];
}
return null;
if (hasOwnProp.call(this._longNameIndex, name)) {
return this._options[this._longNameIndex[name]];
}
return null;
};
ArgParser.prototype._addOption = function(option) {
var currentIndex;
var longName = option.longName;
var shortName = option.shortName;
this._options.push(option);
currentIndex = this._options.length - 1;
if (shortName) {
this._shortNameIndex[shortName] = currentIndex;
}
if (longName) {
this._longNameIndex[longName] = currentIndex;
}
};
/**

@@ -53,130 +69,232 @@ * Provide information about a legal option.

ArgParser.prototype.addOption = function(shortName, longName, hasValue, helpText, canHaveMultiple, coercer) {
this._options.push({
shortName: shortName,
longName: longName,
hasValue: hasValue,
helpText: helpText,
canHaveMultiple: (canHaveMultiple || false),
coercer: coercer
});
if (shortName) {
this._shortNameIndex[shortName] = this._options.length - 1;
}
if (longName) {
this._longNameIndex[longName] = this._options.length - 1;
}
var option = {
shortName: shortName,
longName: longName,
hasValue: hasValue,
helpText: helpText,
canHaveMultiple: (canHaveMultiple || false),
coercer: coercer
};
this._addOption(option);
};
// TODO: refactor addOption to accept objects, then get rid of this method
/**
Generate a summary of all the options with corresponding help text.
@returns {string}
* Provide information about an option that should not cause an error if present, but that is always
* ignored (for example, an option that was used in previous versions but is no longer supported).
*
* @private
* @param {string} shortName - The short name of the option with a leading hyphen (for example,
* `-v`).
* @param {string} longName - The long name of the option with two leading hyphens (for example,
* `--version`).
*/
ArgParser.prototype.addIgnoredOption = function(shortName, longName) {
var option = {
shortName: shortName,
longName: longName,
ignore: true
};
this._addOption(option);
};
function padding(length) {
return new Array(length + 1).join(' ');
}
function padLeft(str, length) {
return padding(length) + str;
}
function padRight(str, length) {
return str + padding(length);
}
function findMaxLength(arr) {
var max = 0;
arr.forEach(function(item) {
if (item.length > max) {
max = item.length;
}
});
return max;
}
function concatWithMaxLength(items, maxLength) {
var result = '';
// to prevent endless loops, always use the first item, regardless of length
result += items.shift();
while ( items.length && (result.length + items[0].length < maxLength) ) {
result += ' ' + items.shift();
}
return result;
}
// we want to format names and descriptions like this:
// | -f, --foo Very long description very long description very long |
// | description very long description. |
function formatHelpInfo(options) {
var MARGIN_LENGTH = 4;
var results = [];
var maxLength = process.stdout.columns;
var maxNameLength = findMaxLength(options.names);
var maxDescriptionLength = findMaxLength(options.descriptions);
var wrapDescriptionAt = maxLength - (MARGIN_LENGTH * 3) - maxNameLength;
// build the string for each option
options.names.forEach(function(name, i) {
var result;
var partialDescription;
var words;
// add a left margin to the name
result = padLeft(options.names[i], MARGIN_LENGTH);
// and a right margin, with extra padding so the descriptions line up with one another
result = padRight(result, maxNameLength - options.names[i].length + MARGIN_LENGTH);
// split the description on spaces
words = options.descriptions[i].split(' ');
// add as much of the description as we can fit on the first line
result += concatWithMaxLength(words, wrapDescriptionAt);
// if there's anything left, keep going until we've consumed the description
while (words.length) {
partialDescription = padding( maxNameLength + (MARGIN_LENGTH * 2) );
partialDescription += concatWithMaxLength(words, wrapDescriptionAt);
result += '\n' + partialDescription;
}
results.push(result);
});
return results;
}
/**
* Generate a summary of all the options with corresponding help text.
* @returns {string}
*/
ArgParser.prototype.help = function() {
var helpArr = ['OPTIONS:'],
option, optionHelp;
var options = {
names: [],
descriptions: []
};
for (var i = 0, leni = this._options.length; i < leni; i++) {
option = this._options[i];
optionHelp = '\t';
this._options.forEach(function(option) {
var name = '';
if (option.shortName) {
optionHelp += '-' + option.shortName + (option.longName ? ', ' : '');
}
// don't show ignored options
if (option.ignore) {
return;
}
if (option.longName) {
optionHelp += '--' + option.longName;
}
if (option.shortName) {
name += '-' + option.shortName + (option.longName ? ', ' : '');
}
if (option.hasValue) {
optionHelp += ' <value>';
}
if (option.longName) {
name += '--' + option.longName;
}
optionHelp += '\t\t' + option.helpText;
helpArr.push(optionHelp);
}
if (option.hasValue) {
name += ' <value>';
}
return helpArr.join('\n');
options.names.push(name);
options.descriptions.push(option.helpText);
});
return 'Options:\n' + formatHelpInfo(options).join('\n');
};
/**
Get the options.
@param {Array.<string>} args An array, like ['-x', 'hello']
@param {Object} [defaults={}] An optional collection of default values.
@returns {Object} The keys will be the longNames, or the shortName if
no longName is defined for that option. The values will be the values
provided, or `true` if the option accepts no value.
* Get the options.
* @param {Array.<string>} args An array, like ['-x', 'hello']
* @param {Object} [defaults={}] An optional collection of default values.
* @returns {Object} The keys will be the longNames, or the shortName if no longName is defined for
* that option. The values will be the values provided, or `true` if the option accepts no value.
*/
ArgParser.prototype.parse = function(args, defaults) {
var result = defaults && _.defaults({}, defaults) || {};
var result = defaults && _.defaults({}, defaults) || {};
result._ = [];
for (var i = 0, leni = args.length; i < leni; i++) {
var arg = '' + args[i],
next = (i < leni-1)? '' + args[i+1] : null,
option,
shortName = null,
longName,
name,
value = null;
result._ = [];
for (var i = 0, leni = args.length; i < leni; i++) {
var arg = '' + args[i],
next = (i < leni-1)? '' + args[i+1] : null,
option,
shortName = null,
longName,
name,
value = null;
// like -t
if (arg.charAt(0) === '-') {
// like -t
if (arg.charAt(0) === '-') {
// like --template
if (arg.charAt(1) === '-') {
name = longName = arg.slice(2);
option = this._getOptionByLongName(longName);
}
else {
name = shortName = arg.slice(1);
option = this._getOptionByShortName(shortName);
}
// like --template
if (arg.charAt(1) === '-') {
name = longName = arg.slice(2);
option = this._getOptionByLongName(longName);
}
else {
name = shortName = arg.slice(1);
option = this._getOptionByShortName(shortName);
}
if (option === null) {
throw new Error( 'Unknown command line option found: ' + name );
}
if (option === null) {
throw new Error( 'Unknown command line option found: ' + name );
}
if (option.hasValue) {
value = next;
i++;
if (option.hasValue) {
value = next;
i++;
if (value === null || value.charAt(0) === '-') {
throw new Error( 'Command line option requires a value: ' + name );
}
}
else {
value = true;
}
if (value === null || value.charAt(0) === '-') {
throw new Error( 'Command line option requires a value: ' + name );
}
}
else {
value = true;
}
if (option.longName && shortName) {
name = option.longName;
}
// skip ignored options now that we've consumed the option text
if (option.ignore) {
continue;
}
if (typeof option.coercer === 'function') {
value = option.coercer(value);
}
// Allow for multiple options of the same type to be present
if (option.canHaveMultiple && hasOwnProp.call(result, name)) {
var val = result[name];
if (val instanceof Array) {
val.push(value);
} else {
result[name] = [val, value];
}
}
else {
result[name] = value;
}
}
else {
result._.push(arg);
}
}
if (option.longName && shortName) {
name = option.longName;
}
return result;
if (typeof option.coercer === 'function') {
value = option.coercer(value);
}
// Allow for multiple options of the same type to be present
if (option.canHaveMultiple && hasOwnProp.call(result, name)) {
var val = result[name];
if (val instanceof Array) {
val.push(value);
} else {
result[name] = [val, value];
}
}
else {
result[name] = value;
}
}
else {
result._.push(arg);
}
}
return result;
};
module.exports = ArgParser;
/**
@module jsdoc/opts/args
@requires jsdoc/opts/argparser
@author Michael Mathews <micmath@gmail.com>
@license Apache License 2.0 - See file 'LICENSE.md' in this project.
* @module jsdoc/opts/args
* @requires jsdoc/opts/argparser
* @author Michael Mathews <micmath@gmail.com>
* @license Apache License 2.0 - See file 'LICENSE.md' in this project.
*/
'use strict';
var ArgParser = require('jsdoc/opts/argparser'),
argParser = new ArgParser(),
hasOwnProp = Object.prototype.hasOwnProperty,
ourOptions,
querystring = require('querystring'),
util = require('util');
var ArgParser = require('jsdoc/opts/argparser');
var querystring = require('querystring');
var util = require('util');
var ourOptions;
var argParser = new ArgParser();
var hasOwnProp = Object.prototype.hasOwnProperty;
// cast strings to booleans or integers where appropriate
function castTypes(item) {
var result = item;
var integer;
switch (result) {
case 'true':
return true;
case 'false':
return false;
default:
// might be an integer
var integer = parseInt(result, 10);
if (String(integer) === result && integer !== 'NaN') {
return integer;
} else {
return result;
}
}
var result = item;
switch (result) {
case 'true':
result = true;
break;
case 'false':
result = false;
break;
default:
// might be an integer
integer = parseInt(result, 10);
if (String(integer) === result && integer !== 'NaN') {
result = integer;
}
}
return result;
}

@@ -39,28 +46,30 @@

function fixTypes(item) {
var result = item;
var result = item;
// recursively process arrays and objects
if ( util.isArray(result) ) {
for (var i = 0, l = result.length; i < l; i++) {
result[i] = fixTypes(result[i]);
}
} else if (typeof result === 'object') {
Object.keys(result).forEach(function(prop) {
result[prop] = fixTypes(result[prop]);
});
} else {
result = castTypes(result);
}
// recursively process arrays and objects
if ( util.isArray(result) ) {
for (var i = 0, l = result.length; i < l; i++) {
result[i] = fixTypes(result[i]);
}
}
else if (typeof result === 'object') {
Object.keys(result).forEach(function(prop) {
result[prop] = fixTypes(result[prop]);
});
}
else {
result = castTypes(result);
}
return result;
return result;
}
function parseQuery(str) {
var result = querystring.parse(str);
var result = querystring.parse(str);
Object.keys(result).forEach(function(prop) {
result[prop] = fixTypes(result[prop]);
});
Object.keys(result).forEach(function(prop) {
result[prop] = fixTypes(result[prop]);
});
return result;
return result;
}

@@ -75,3 +84,2 @@

argParser.addOption('r', 'recurse', false, 'Recurse into subdirectories when scanning for source code files.');
argParser.addOption('l', 'lenient', false, 'Continue to generate output if a doclet is incomplete or contains errors. Default: false');
argParser.addOption('h', 'help', false, 'Print this message and quit.');

@@ -82,30 +90,32 @@ argParser.addOption('X', 'explain', false, 'Dump all found doclet internals to console and quit.');

argParser.addOption('v', 'version', false, 'Display the version number and quit.');
argParser.addOption('', 'debug', false, 'Log information for debugging JSDoc. On Rhino, launches the debugger when passed as the first option.');
argParser.addOption('', 'verbose', false, 'Log detailed information to the console as JSDoc runs.');
argParser.addOption('', 'pedantic', false, 'Treat errors as fatal errors, and treat warnings as errors. Default: false');
//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?
// Options specific to tests
argParser.addOption(null, 'match', true, 'Only run tests containing <value>.', true);
argParser.addOption(null, 'nocolor', false, 'Do not use color in console output from tests.');
//Here are options specific to tests
argParser.addOption(null, 'verbose', false, 'Display verbose output for tests');
argParser.addOption(null, 'match', true, 'Only run tests containing <value>', true);
argParser.addOption(null, 'nocolor', false, 'Do not use color in console output from tests');
// Options that are no longer supported and should be ignored
argParser.addIgnoredOption('l', 'lenient'); // removed in JSDoc 3.3.0
/**
Set the options for this app.
@throws {Error} Illegal arguments will throw errors.
@param {string|String[]} args The command line arguments for this app.
* 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 || [];
args = args || [];
if (typeof args === 'string' || args.constructor === String) {
args = (''+args).split(/\s+/g);
}
if (typeof args === 'string' || args.constructor === String) {
args = (''+args).split(/\s+/g);
}
ourOptions = argParser.parse(args);
ourOptions = argParser.parse(args);
return ourOptions;
return ourOptions;
};
/**
Display help message for options.
* Retrieve help message for options.
*/

@@ -117,16 +127,16 @@ exports.help = function() {

/**
Get a named option.
@param {string} name The name of the option.
@return {string} The value associated with the given 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.
* 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];
}
if (typeof name === 'undefined') {
return ourOptions;
}
else if ( hasOwnProp.call(ourOptions, name) ) {
return ourOptions[name];
}
};

@@ -21,4 +21,3 @@ /*global env: true */

// TODO: should probably replace process.cwd() with the CWD before launching JSDoc
currentPath = path.resolve( process.cwd(), path.dirname(current) ).split(path.sep) || [];
currentPath = path.resolve(global.env.pwd, current).split(path.sep) || [];

@@ -72,29 +71,8 @@ if (previousPath && currentPath.length) {

// TODO: can we get rid of this?
/**
* If required by the current VM, convert a path to a URI that meets the operating system's
* requirements. Otherwise, return the original path.
* @function
* @private
* @param {string} path The path to convert.
* @return {string} A URI that meets the operating system's requirements, or the original path.
*/
var pathToUri = require( runtime.getModulePath('path') ).pathToUri;
// TODO: can we get rid of this, or at least stop exporting it?
/**
* If required by the current VM, convert a URI to a path that meets the operating system's
* requirements. Otherwise, assume the "URI" is really a path, and return the original path.
* @function
* @private
* @param {string} uri The URI to convert.
* @return {string} A path that meets the operating system's requirements.
*/
exports._uriToPath = require( runtime.getModulePath('path') ).uriToPath;
/**
* Retrieve the fully qualified path to the requested resource.
*
* If the resource path is specified as a relative path, JSDoc searches for the path in the current
* working directory, then in the JSDoc directory.
* If the resource path is specified as a relative path, JSDoc searches for the path in the
* directory where the JSDoc configuration file is located, then in the current working directory,
* and finally in the JSDoc directory.
*

@@ -110,3 +88,3 @@ * If the resource path is specified as a fully qualified path, JSDoc uses the path as-is.

exports.getResourcePath = function(filepath, filename) {
var result;
var result = null;

@@ -124,16 +102,14 @@ function pathExists(_path) {

// first, try resolving it relative to the working directory (or just normalize it if it's an
// absolute path)
result = path.resolve(env.pwd, filepath);
if ( !pathExists(result) ) {
// next, try resolving it relative to the JSDoc directory
result = path.resolve(env.dirname, filepath);
if ( !pathExists(result) ) {
result = null;
// absolute paths are normalized by path.resolve on the first pass
[path.dirname(global.env.opts.configure || ''), env.pwd, env.dirname].forEach(function(_path) {
if (!result && _path) {
_path = path.resolve(_path, filepath);
if ( pathExists(_path) ) {
result = _path;
}
}
}
});
if (result) {
result = filename ? path.join(result, filename) : result;
result = pathToUri(result);
}

@@ -140,0 +116,0 @@

@@ -8,3 +8,3 @@ /*global app: true */

var error = require('jsdoc/util/error');
var logger = require('jsdoc/util/logger');
var path = require('jsdoc/path');

@@ -17,14 +17,6 @@

var plugin;
var pluginPath;
for (var i = 0, l = plugins.length; i < l; i++) {
pluginPath = path.getResourcePath(path.dirname(plugins[i]), path.basename(plugins[i]));
plugin = require(plugins[i]);
if (!pluginPath) {
error.handle(new Error('Unable to find the plugin "' + plugins[i] + '"'));
continue;
}
plugin = require(pluginPath);
// allow user-defined plugins to...

@@ -46,4 +38,4 @@ //...register event handlers

if ( !parser.addNodeVisitor ) {
error.handle( new Error('Unable to add the Rhino node visitor from ' + plugins[i] +
', because JSDoc is not using the Rhino JavaScript parser.') );
logger.error('Unable to add the Rhino node visitor from %s, because JSDoc ' +
'is not using the Rhino JavaScript parser.', plugins[i]);
}

@@ -50,0 +42,0 @@ else {

/**
@overview Schema for validating JSON produced by JSDoc Toolkit.
@author Michael Mathews <micmath@gmail.com>
@license Apache License 2.0 - See file 'LICENSE.md' in this project.
@see <http://tools.ietf.org/html/draft-zyp-json-schema-02>
* @overview Schema for validating JSDoc doclets.
*
* @author Michael Mathews <micmath@gmail.com>
* @author Jeff Williams <jeffrey.l.williams@gmail.com>
* @license Apache License 2.0 - See file 'LICENSE.md' in this project.
* @see <http://tools.ietf.org/html/draft-zyp-json-schema-03>
*/
'use strict';
exports.jsdocSchema = {
"properties": {
"doc": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"author": {
"type": ["string", "array"],
"optional": true,
"items": {
"type": "string"
}
// JSON schema types
var ARRAY = 'array';
var BOOLEAN = 'boolean';
var INTEGER = 'integer';
var NULL = 'null';
var NUMBER = 'number';
var OBJECT = 'object';
var STRING = 'string';
var UNDEFINED = 'undefined';
var EVENT_REGEXP = /event\:[\S]+/;
var PACKAGE_REGEXP = /package\:[\S]+/;
// information about the code associated with a doclet
var META_SCHEMA = exports.META_SCHEMA = {
type: OBJECT,
optional: true,
additionalProperties: false,
properties: {
code: {
type: OBJECT,
additionalProperties: false,
properties: {
funcscope: {
type: STRING,
optional: true
},
id: {
type: STRING,
optional: true
},
name: {
type: STRING,
optional: true
},
node: {
type: OBJECT,
optional: true
},
paramnames: {
type: ARRAY,
optional: true,
uniqueItems: true,
items: {
type: STRING
}
},
type: {
type: STRING,
optional: true
},
value: {
optional: true
}
}
},
filename: {
title: 'The name of the file that contains the code associated with this doclet.',
type: STRING,
optional: true
},
lineno: {
title: 'The line number of the code associated with this doclet.',
type: NUMBER,
optional: true
},
path: {
title: 'The path in which the code associated with this doclet is located.',
type: STRING,
optional: true
},
range: {
title: 'The positions of the first and last characters of the code associated with ' +
'this doclet.',
type: ARRAY,
optional: true,
minItems: 2,
maxItems: 2,
items: {
type: NUMBER
}
},
vars: {
type: OBJECT
}
}
};
// type property containing type names
var TYPE_PROPERTY_SCHEMA = exports.TYPE_PROPERTY_SCHEMA = {
type: OBJECT,
additionalProperties: false,
properties: {
names: {
type: ARRAY,
minItems: 1,
items: {
type: STRING
}
}
}
};
// enumeration properties
var ENUM_PROPERTY_SCHEMA = exports.ENUM_PROPERTY_SCHEMA = {
type: OBJECT,
additionalProperties: false,
properties: {
comment: {
type: STRING
},
defaultvalue: {
// TODO: stop adding property if it's empty
type: [STRING, NULL, UNDEFINED],
optional: true
},
description: {
// TODO: stop adding property if it's empty
type: [STRING, NULL, UNDEFINED],
optional: true
},
kind: {
type: STRING,
// TODO: get this from a real enum somewhere
enum: ['member']
},
longname: {
type: STRING
},
memberof: {
type: STRING,
optional: true
},
meta: META_SCHEMA,
name: {
type: STRING
},
scope: {
type: STRING,
// TODO: get this from a real enum somewhere
enum: ['static']
},
type: TYPE_PROPERTY_SCHEMA
}
};
// function parameter, or object property defined with @property tag
var PARAM_SCHEMA = exports.PARAM_SCHEMA = {
type: OBJECT,
additionalProperties: false,
properties: {
// what is the default value for this parameter?
defaultvalue: {
// TODO: stop adding property if it's empty
type: [STRING, NULL, UNDEFINED],
optional: true
},
// a description of the parameter
description: {
// TODO: stop adding property if it's empty
type: [STRING, NULL, UNDEFINED],
optional: true
},
// what name does this parameter have within the function?
name: {
type: STRING
},
// can the value for this parameter be null?
nullable: {
// TODO: stop adding property if it's empty
type: [BOOLEAN, NULL, UNDEFINED],
optional: true
},
// is a value for this parameter optional?
optional: {
// TODO: stop adding property if it's empty
type: [BOOLEAN, NULL, UNDEFINED],
optional: true
},
// what are the types of value expected for this parameter?
type: TYPE_PROPERTY_SCHEMA,
// can this parameter be repeated?
variable: {
// TODO: stop adding property if it's empty
type: [BOOLEAN, NULL, UNDEFINED],
optional: true
}
}
};
var DOCLET_SCHEMA = exports.DOCLET_SCHEMA = {
type: OBJECT,
additionalProperties: false,
properties: {
// what access privileges are allowed
access: {
type: STRING,
optional: true,
// TODO: define this as an enumeration elsewhere
enum: [
'private',
'protected'
]
},
alias: {
type: STRING,
optional: true
},
augments: {
type: ARRAY,
optional: true,
uniqueItems: true,
items: {
type: STRING
}
},
author: {
type: ARRAY,
optional: true,
items: {
type: STRING
}
},
borrowed: {
type: ARRAY,
optional: true,
uniqueItems: true,
items: {
type: OBJECT,
additionalProperties: false,
properties: {
// name of the target
as: {
type: STRING,
optional: true
},
"path": { // unique identifier for each doc
"type": "string",
"maxItems": 1
// name of the source
from: {
type: STRING
}
}
}
},
// a description of the class that this constructor belongs to
classdesc: {
type: STRING,
optional: true
},
comment: {
type: STRING
},
copyright: {
type: STRING,
optional: true
},
defaultvalue: {
optional: true
},
defaultvaluetype: {
type: STRING,
optional: true,
enum: [OBJECT]
},
// is usage of this symbol deprecated?
deprecated: {
type: [STRING, BOOLEAN],
optional: true
},
// a description
description: {
// TODO: stop adding property if it's empty
type: [STRING, NULL, UNDEFINED],
optional: true
},
// something else to consider
examples: {
type: ARRAY,
optional: true,
items: {
type: STRING
}
},
exceptions: {
type: ARRAY,
optional: true,
items: PARAM_SCHEMA
},
// the path to another constructor
extends: {
type: ARRAY,
optional: true,
uniqueItems: true,
items: {
type: STRING
}
},
// the path to another doc object
fires: {
type: ARRAY,
optional: true,
uniqueItems: true,
items: {
type: STRING,
pattern: EVENT_REGEXP
}
},
forceMemberof: {
// TODO: stop adding property if it's empty
type: [BOOLEAN, NULL, UNDEFINED],
optional: true
},
ignore: {
type: BOOLEAN,
optional: true
},
implements: {
type: ARRAY,
optional: true,
uniqueItems: true,
items: {
type: STRING
}
},
inherited: {
type: BOOLEAN,
optional: true
},
inherits: {
type: STRING,
optional: true,
dependency: {
inherited: true
}
},
isEnum: {
type: BOOLEAN,
optional: true
},
// what kind of symbol is this?
kind: {
type: STRING,
// TODO: define this as an enumeration elsewhere
enum: [
'class',
'constant',
'event',
'external',
'file',
'function',
'member',
'mixin',
'module',
'namespace',
'package',
'typedef'
]
},
license: {
type: STRING,
optional: true
},
listens: {
type: ARRAY,
optional: true,
uniqueItems: true,
items: {
type: STRING,
pattern: EVENT_REGEXP
}
},
longname: {
type: STRING
},
// probably a leading substring of the path
memberof: {
type: STRING,
optional: true
},
// information about this doc
meta: META_SCHEMA,
mixes: {
type: ARRAY,
optional: true,
uniqueItems: true,
items: {
type: STRING
}
},
// probably a trailing substring of the path
name: {
type: STRING
},
// are there function parameters associated with this doc?
params: {
type: ARRAY,
optional: true,
uniqueItems: true,
items: PARAM_SCHEMA
},
preserveName: {
type: BOOLEAN,
optional: true
},
properties: {
type: ARRAY,
optional: true,
uniqueItems: true,
minItems: 1,
items: {
anyOf: [ENUM_PROPERTY_SCHEMA, PARAM_SCHEMA]
}
},
readonly: {
type: BOOLEAN,
optional: true
},
// the symbol being documented requires another symbol
requires: {
type: ARRAY,
optional: true,
uniqueItems: true,
minItems: 1,
items: {
type: STRING
}
},
returns: {
type: ARRAY,
optional: true,
minItems: 1,
items: PARAM_SCHEMA
},
// what sort of parent scope does this symbol have?
scope: {
type: STRING,
enum: [
// TODO: make these an enumeration
'global',
'inner',
'instance',
'static'
]
},
// something else to consider
see: {
type: ARRAY,
optional: true,
minItems: 1,
items: {
type: STRING
}
},
// at what previous version was this doc added?
since: {
type: STRING,
optional: true
},
summary: {
type: STRING,
optional: true
},
// arbitrary tags associated with this doc
tags: {
type: ARRAY,
optional: true,
minItems: 1,
items: {
type: OBJECT,
additionalProperties: false,
properties: {
originalTitle: {
type: STRING
},
"description": { // a description
"type": "string",
"optional": true,
"maxItems": 1
text: {
type: STRING,
optional: true
},
"classdesc": { // a description of the class that this constructor belongs to
"type": "string",
"optional": true,
"maxItems": 1
title: {
type: STRING
},
"name": { // probably a trailing substring of the path
"type": "string",
"maxItems": 1
},
"version": { // what is the version of this doc
"type": "string",
"optional": true,
"maxItems": 1
},
"since": { // at what previous version was this doc added?
"type": "string",
"optional": true,
"maxItems": 1
},
"see": { // some thing else to consider
"type": ["string", "array"],
"optional": true,
"items": {
"type": "string"
}
},
"tutorials": { // extended tutorials
"type": ["string", "array"],
"optional": true,
"items": {
"type": "string"
}
},
"deprecated": { // is usage of this symbol deprecated?
"type": ["string", "boolean"],
"optional": true
},
"scope": { // how is this symbol attached to it's enclosing scope?
"type": "string",
"maxItems": 1,
"enum": ["global", "static", "instance", "inner"]
},
"memberof": { // probably a leading substring of the path
"type": "string",
"optional": true,
"maxItems": 1
},
"extends": { // the path to another constructor
"type": ["string", "array"],
"optional": true,
"items": {
"type": "string"
}
},
"fires": { // the path to another doc object
"type": ["string", "array"],
"optional": true,
"items": {
"type": "string"
}
},
"requires": { // the symbol being documented requires another symbol
"type": ["string", "array"],
"optional": true,
"items": {
"type": "string"
}
},
"implements": {
"type": ["string", "array"],
"optional": true,
"items": {
"type": "string"
}
},
"kind": { // what kind of symbol is this?
"type": "string",
"maxItems": 1,
"enum": ["constructor", "module", "event", "namespace", "method", "member", "enum", "class", "interface", "constant", "mixin", "file", "version"]
},
"refersto": { // the path to another doc: this doc is simply a renamed alias to that
"type": "string",
"optional": true,
"maxItems": 1
},
"access": { // what access priviledges are allowed
"type": "string",
"optional": true,
"maxItems": 1,
"enum": ["private", "protected", "public"]
},
"virtual": { // is a member left to be implemented during inheritance?
"type": "boolean",
"optional": true,
"default": false
},
"attrib": { // other attributes, like "readonly"
"type": "string",
"optional": true
},
"type": { // what type is the value that this doc is associated with, like "number"
"type": ["string", "array"],
"optional": true,
"items": {
"type": "string"
}
},
"exception" : {
"optional": true,
"type": "object",
"properties": {
"type": { // what is the type of the value thrown?
"type": "array",
"optional": true,
"items": {
"type": "string"
}
},
"description": { // a description of the thrown value
"type": "string",
"optional": true
}
},
"additionalProperties": false
},
"returns" : {
"optional": true,
"type": "object",
"properties": {
"type": { // what is the type of the value returned?
"type": ["string", "array"],
"optional": true,
"items": {
"type": "string"
}
},
"description": { // a description of the returned value
"type": "string",
"optional": true
}
},
"additionalProperties": false
},
"param" : { // are there function parameters associated with this doc?
"type": "array",
"optional": true,
"items": {
"type": "object",
"properties": {
"type": { // what are the types of value expected for this parameter?
"type": ["string", "array"],
"optional": true,
"items": {
"type": "string"
}
},
"optional": { // is a value for this parameter optional?
"type": "boolean",
"optional": true,
"default": true
},
"nullable": { // can the value for this parameter be null?
"type": "boolean",
"optional": true,
"default": true
},
"defaultvalue": { // what is the default value for this parameter?
"type": "string",
"optional": true
},
"name": { // what name does this parameter have within the function?
"type": "string"
},
"description": { // a description of the parameter
"type": "string",
"optional": true
}
},
"additionalProperties": false
}
},
"thisobj": {
"type": ["string", "array"],
"optional": true,
"items": {
"type": "string"
}
},
"example": { // some thing else to consider
"type": ["string", "array"],
"optional": true,
"items": {
"type": "string"
}
},
"tags": { // arbitrary tags associated with this doc
"type": "array",
"optional": true,
"additionalProperties": false,
"items": {
"type": "string"
}
},
"meta": { // information about this doc
"type": "object",
"optional": true,
"maxItems": 1,
"properties": {
"file": { // what is the name of the file this doc appears in?
"type": "string",
"optional": true,
"maxItems": 1
},
"line": { // on what line of the file does this doc appear?
"type": "number",
"optional": true,
"maxItems": 1
}
},
"additionalProperties": false
value: {
type: [STRING, OBJECT],
optional: true,
properties: PARAM_SCHEMA
}

@@ -257,54 +499,108 @@ }

},
"meta": { // information about the generation for all the docs
"type": "object",
"optional": true,
"maxItems": 1,
"properties": {
"project": { // to what project does this doc belong?
"type": "object",
"optional": true,
"maxItems": 1,
"properties": {
"name": { // the name of the project
"type": "string",
"maxItems": 1
},
"uri": { // the URI of the project
"type": "string",
"maxItems": 1,
"format": "uri"
},
"version": { // the version of the project
"type": "string",
"maxItems": 1
},
"lang": { // the programming language used in the project
"type": "string",
"maxItems": 1
}
'this': {
type: STRING,
optional: true
},
todo: {
type: ARRAY,
optional: true,
minItems: 1,
items: {
type: STRING
}
},
// extended tutorials
tutorials: {
type: ARRAY,
optional: true,
minItems: 1,
items: {
type: STRING
}
},
// what type is the value that this doc is associated with, like `number`
type: TYPE_PROPERTY_SCHEMA,
undocumented: {
type: BOOLEAN,
optional: true
},
variation: {
type: STRING,
optional: true
},
// what is the version of this doc
version: {
type: STRING,
optional: true
},
// is a member left to be implemented during inheritance?
virtual: {
type: BOOLEAN,
optional: true
}
}
};
var PACKAGE_SCHEMA = exports.PACKAGE_SCHEMA = {
type: OBJECT,
additionalProperties: false,
properties: {
description: {
type: STRING,
optional: true
},
files: {
type: ARRAY,
uniqueItems: true,
minItems: 1,
items: {
type: STRING
}
},
kind: {
type: STRING,
enum: ['package']
},
licenses: {
type: ARRAY,
optional: true,
minItems: 1,
items: {
type: OBJECT,
additionalProperties: false,
properties: {
type: {
type: STRING,
optional: true
},
"additionalProperties": false
},
"generated": { // some information about the running of the doc generator
"type": "object",
"optional": true,
"maxItems": 1,
"properties": {
"date": { // on what date and time was the doc generated?
"type": "string",
"maxItems": 1,
"optional": true,
"format": "date-time"
},
"parser": { // what tool was used to generate the doc?
"type": "string",
"maxItems": 1,
"optional": true
}
},
"additionalProperties": false
url: {
type: STRING,
optional: true,
format: 'uri'
}
}
}
},
longname: {
type: STRING,
optional: true,
pattern: PACKAGE_REGEXP
},
name: {
type: STRING,
optional: true
},
version: {
type: STRING,
optional: true
}
}
};
};
var DOCLETS_SCHEMA = exports.DOCLETS_SCHEMA = {
type: ARRAY,
uniqueItems: true,
items: {
anyOf: [DOCLET_SCHEMA, PACKAGE_SCHEMA]
}
};

@@ -9,5 +9,2 @@ 'use strict';

// Counter for generating unique node IDs.
var uid = 100000000;
// TODO: docs

@@ -356,2 +353,3 @@ var acceptsLeadingComments = exports.acceptsLeadingComments = (function() {

AstBuilder.prototype._postProcess = function(filename, ast) {
var astnode = require('jsdoc/src/astnode');
var Walker = require('jsdoc/src/walker').Walker;

@@ -366,8 +364,2 @@

}
if (!node.nodeId) {
Object.defineProperty(node, 'nodeId', {
value: 'astnode' + uid++
});
}
}

@@ -374,0 +366,0 @@ };

@@ -21,3 +21,3 @@ /**

comment.replace(/[\r\n]/g, ''), error.message) );
require('jsdoc/util/error').handle(err);
require('jsdoc/util/logger').error(err);
doclet = new Doclet('', e);

@@ -24,0 +24,0 @@ }

@@ -7,8 +7,15 @@ /*global env: true, Packages: true */

var Doclet = require('jsdoc/doclet');
var name = require('jsdoc/name');
var Syntax = require('jsdoc/src/syntax').Syntax;
var jsdoc = {
doclet: require('jsdoc/doclet'),
name: require('jsdoc/name'),
src: {
astnode: require('jsdoc/src/astnode'),
syntax: require('jsdoc/src/syntax')
}
};
var logger = require('jsdoc/util/logger');
var util = require('util');
var hasOwnProp = Object.prototype.hasOwnProperty;
var Syntax = jsdoc.src.syntax.Syntax;

@@ -24,2 +31,18 @@ // Prefix for JavaScript strings that were provided in lieu of a filename.

// TODO: docs
// TODO: not currently used
function makeGlobalDoclet(globalScope) {
var doclet = new jsdoc.doclet.Doclet('/** Auto-generated doclet for global scope */', {});
if (globalScope) {
// TODO: handle global aliases
Object.keys(globalScope.ownedVariables).forEach(function(variable) {
doclet.meta.vars = doclet.meta.vars || {};
doclet.meta.vars[variable] = null;
});
}
return doclet;
}
// TODO: docs
exports.createParser = function(type) {

@@ -46,3 +69,3 @@ var path = require('jsdoc/path');

catch (e) {
throw new Error('Unable to create the parser type "' + type + '": ' + e);
logger.fatal('Unable to create the parser type "' + type + '": ' + e);
}

@@ -90,7 +113,5 @@ };

this._resultBuffer = [];
this.refs = {
__global__: {
meta: {}
}
};
this.refs = {};
this.refs[jsdoc.src.astnode.GLOBAL_NODE_ID] = {};
this.refs[jsdoc.src.astnode.GLOBAL_NODE_ID].meta = {};
};

@@ -129,2 +150,3 @@

e.sourcefiles = sourceFiles;
logger.debug('Parsing source files: %j', sourceFiles);

@@ -146,6 +168,3 @@ this.emit('parseBegin', e);

catch(e) {
// TODO: shouldn't this be fatal if we're not in lenient mode?
console.error('FILE READ ERROR: in module:jsdoc/src/parser.Parser#parse: "' +
filename + '" ' + e);
continue;
logger.error('Unable to read and parse the source file %s: %s', filename, e);
}

@@ -164,2 +183,3 @@ }

});
logger.debug('Finished parsing source files.');

@@ -218,2 +238,3 @@ return this._resultBuffer;

var ast;
var globalScope;

@@ -225,2 +246,3 @@ var e = {

this.emit('fileBegin', e);
logger.printInfo('Parsing %s ...', sourceName);

@@ -243,2 +265,3 @@ if (!e.defaultPrevented) {

this.emit('fileComplete', e);
logger.info('complete.');
};

@@ -261,3 +284,3 @@

this.refs[node.nodeId] = {
longname: Doclet.ANONYMOUS_LONGNAME,
longname: jsdoc.doclet.ANONYMOUS_LONGNAME,
meta: {

@@ -282,176 +305,2 @@ code: e.code

/**
* @private
* @memberof module:src/parser.Parser
*/
function nodeToString(node) {
var str;
if (!node || !node.type) {
return;
}
switch (node.type) {
case Syntax.AssignmentExpression:
str = nodeToString(node.left);
break;
case Syntax.FunctionDeclaration:
// falls through
case Syntax.FunctionExpression:
str = 'function';
break;
case Syntax.Identifier:
str = node.name;
break;
case Syntax.Literal:
str = String(node.value);
break;
case Syntax.MemberExpression:
// could be computed (like foo['bar']) or not (like foo.bar)
str = nodeToString(node.object);
if (node.computed) {
str += util.format( '[%s]', node.property.raw || nodeToString(node.property) );
}
else {
str += '.' + nodeToString(node.property);
}
break;
case Syntax.ThisExpression:
str = 'this';
break;
case Syntax.UnaryExpression:
// like -1; operator can be prefix or postfix
str = nodeToString(node.argument);
if (node.prefix) {
str = node.operator + str;
}
else {
str = str + node.operator;
}
break;
case Syntax.VariableDeclarator:
str = nodeToString(node.id);
break;
default:
str = Syntax[node.type] || 'UnknownType';
}
return str;
}
// TODO: docs
function getParamNames(node) {
if (!node.params) {
return [];
}
return node.params.map(function(param) {
return nodeToString(param);
});
}
// TODO: docs
function isAccessor(node) {
return node.kind === 'get' || node.kind === 'set';
}
// TODO: docs
function isAssignment(node) {
return node && (node.type === Syntax.AssignmentExpression ||
node.type === Syntax.VariableDeclarator);
}
// TODO: docs
/**
* Retrieve information about the node, including its name and type.
* @memberof module:jsdoc/src/parser.Parser
*/
Parser.prototype.getNodeInfo = function(node) {
var string;
var about = {};
var accessor = false;
switch (node.type) {
// like: "foo = 'bar'" (after foo has been declared)
case Syntax.AssignmentExpression:
about.node = node.right;
about.name = nodeToString(node.left);
about.type = about.node.type;
about.value = nodeToString(about.node);
break;
// like: "function foo() {}"
case Syntax.FunctionDeclaration:
about.node = node;
about.name = nodeToString(node.id);
about.type = nodeToString(node);
about.value = nodeToString(about.node);
about.paramnames = getParamNames(node);
break;
// like the function in: "var foo = function() {}"
case Syntax.FunctionExpression:
about.node = node;
about.name = '';
about.type = nodeToString(node);
about.value = nodeToString(about.node);
about.paramnames = getParamNames(node);
break;
// like "a.b.c"
case Syntax.MemberExpression:
about.node = node;
about.name = nodeToString(about.node);
about.type = about.node.type;
break;
// like "a: 0" in "var foo = {a: 0}"
case Syntax.Property:
accessor = isAccessor(node);
about.node = node.value;
about.name = nodeToString(node.key);
about.value = nodeToString(about.node);
if (accessor) {
about.type = nodeToString(node);
about.paramnames = getParamNames(node);
}
else {
about.type = about.node.type;
}
break;
// like: "var i = 0" (has init property)
// like: "var i" (no init property)
case Syntax.VariableDeclarator:
about.node = node.init || node.id;
about.name = node.id.name;
about.type = about.node.type || 'undefined';
about.value = nodeToString(about.node);
break;
default:
string = nodeToString(node);
if (string) {
about.name = string;
}
}
return about;
};
// TODO: docs
/**
* @param {string} name - The symbol's longname.

@@ -468,3 +317,3 @@ * @return {string} The symbol's basename.

function definedInScope(doclet, basename) {
return !!doclet && !!doclet.meta && !!doclet.meta.vars &&
return !!doclet && !!doclet.meta && !!doclet.meta.vars && !!basename &&
hasOwnProp.call(doclet.meta.vars, basename);

@@ -476,3 +325,3 @@ }

* Given a node, determine what the node is a member of.
* @param {astnode} node
* @param {node} node
* @returns {string} The long name of the node that this is a member of.

@@ -493,6 +342,6 @@ */

if (!doclet) {
result = Doclet.ANONYMOUS_LONGNAME + name.INNER;
result = jsdoc.doclet.ANONYMOUS_LONGNAME + jsdoc.name.INNER;
}
else {
result = (doclet.longname || doclet.name) + name.INNER;
result = (doclet.longname || doclet.name) + jsdoc.name.INNER;
}

@@ -503,3 +352,3 @@ }

scope = node;
basename = this.getBasename( nodeToString(node) );
basename = this.getBasename( jsdoc.src.astnode.nodeToString(node) );

@@ -520,3 +369,3 @@ // walk up the scope chain until we find the scope in which the node is defined

// do we know that it's a global?
doclet = this.refs.__global__;
doclet = this.refs[jsdoc.src.astnode.GLOBAL_NODE_ID];
if ( doclet && definedInScope(doclet, basename) ) {

@@ -545,3 +394,3 @@ result = [doclet.meta.vars[basename], basename];

* Resolve what "this" refers to relative to a node.
* @param {astnode} node - The "this" node
* @param {node} node - The "this" node
* @returns {string} The longname of the enclosing node.

@@ -557,3 +406,3 @@ */

if (!doclet) {
result = Doclet.ANONYMOUS_LONGNAME; // TODO handle global this?
result = jsdoc.doclet.ANONYMOUS_LONGNAME; // TODO handle global this?
}

@@ -568,3 +417,3 @@ else if (doclet['this']) {

// like: var foo = function(n) { /** blah */ this.bar = n; }
else if ( doclet.kind === 'member' && isAssignment(node) ) {
else if ( doclet.kind === 'member' && jsdoc.src.astnode.isAssignment(node) ) {
result = doclet.longname || doclet.name;

@@ -571,0 +420,0 @@ }

@@ -12,2 +12,3 @@ /*global env: true */

var fs = require('jsdoc/fs');
var logger = require('jsdoc/util/logger');
var path = require('jsdoc/path');

@@ -29,2 +30,3 @@

exports.Scanner.prototype.scan = function(searchPaths, depth, filter) {
var currentFile;
var isFile;

@@ -43,9 +45,10 @@

try {
isFile = fs.statSync(filepath).isFile();
currentFile = fs.statSync(filepath);
}
catch(e) {
isFile = false;
catch (e) {
logger.error('Unable to find the source file or directory %s', filepath);
return;
}
if (isFile) {
if ( currentFile.isFile() ) {
filePaths.push(filepath);

@@ -52,0 +55,0 @@ }

@@ -8,7 +8,13 @@ /**

var doclet = require('jsdoc/doclet');
var Syntax = require('jsdoc/src/syntax').Syntax;
var jsdoc = {
doclet: require('jsdoc/doclet'),
src: {
astnode: require('jsdoc/src/astnode'),
syntax: require('jsdoc/src/syntax')
}
};
var util = require('util');
var hasOwnProp = Object.prototype.hasOwnProperty;
var Syntax = jsdoc.src.syntax.Syntax;

@@ -28,7 +34,7 @@ // TODO: docs

// TODO: docs
function makeVarsFinisher(scopeDoc) {
function makeVarsFinisher(scopeDoclet) {
return function(e) {
// no need to evaluate all things related to scopeDoc again, just use it
if (scopeDoc && e.doclet && e.doclet.alias) {
scopeDoc.meta.vars[e.code.name] = e.doclet.longname;
// no need to evaluate all things related to scopeDoclet again, just use it
if (scopeDoclet && e.doclet && e.doclet.alias) {
scopeDoclet.meta.vars[e.code.name] = e.doclet.longname;
}

@@ -38,3 +44,2 @@ };

// TODO: docs

@@ -46,3 +51,3 @@ function SymbolFound(node, filename, extras) {

this.id = extras.id || node.nodeId;
this.comment = extras.comment || getLeadingComment(node) || doclet.UNDOCUMENTED_TAG;
this.comment = extras.comment || getLeadingComment(node) || jsdoc.doclet.UNDOCUMENTED_TAG;
this.lineno = extras.lineno || node.loc.start.line;

@@ -232,16 +237,12 @@ this.range = extras.range || node.range;

// TODO: docs
// TODO: may be able to get rid of this using knownAliases
function trackVars(parser, node, e) {
// keep track of vars within a given scope
var scope = '__global__';
var doclet = null;
var enclosingScopeId = node.enclosingScope ? node.enclosingScope.nodeId :
jsdoc.src.astnode.GLOBAL_NODE_ID;
var doclet = parser.refs[enclosingScopeId];
if (node.enclosingScope) {
scope = node.enclosingScope.nodeId;
}
doclet = parser.refs[scope];
if (doclet) {
doclet.meta.vars = doclet.meta.vars || {};
doclet.meta.vars[e.code.name] = false;
e.finishers.push(makeVarsFinisher(doclet));
doclet.meta.vars[e.code.name] = null;
e.finishers.push( makeVarsFinisher(doclet) );
}

@@ -258,3 +259,3 @@ }

var extras = {
code: parser.getNodeInfo(node)
code: jsdoc.src.astnode.getInfo(node)
};

@@ -265,3 +266,2 @@

case Syntax.AssignmentExpression:
// TODO: ignore unless operator is '=' (for example, ignore '+=')
// falls through

@@ -268,0 +268,0 @@

@@ -10,2 +10,4 @@ /**

var astnode = require('jsdoc/src/astnode');
var doclet = require('jsdoc/doclet');
var Syntax = require('jsdoc/src/syntax').Syntax;

@@ -45,3 +47,3 @@

walkers[Syntax.ArrayExpression] = function(node, parent, state, cb) {
walkers[Syntax.ArrayExpression] = function arrayExpression(node, parent, state, cb) {
for (var i = 0, l = node.elements.length; i < l; i++) {

@@ -56,3 +58,3 @@ var e = node.elements[i];

// TODO: verify correctness
walkers[Syntax.ArrayPattern] = function(node, parent, state, cb) {
walkers[Syntax.ArrayPattern] = function arrayPattern(node, parent, state, cb) {
for (var i = 0, l = node.elements.length; i < l; i++) {

@@ -67,3 +69,3 @@ var e = node.elements[i];

walkers[Syntax.AssignmentExpression] = function(node, parent, state, cb) {
walkers[Syntax.AssignmentExpression] = function assignmentExpression(node, parent, state, cb) {
cb(node.left, node, state);

@@ -73,5 +75,8 @@ cb(node.right, node, state);

walkers[Syntax.BinaryExpression] = walkers[Syntax.AssignmentExpression];
walkers[Syntax.BinaryExpression] = function binaryExpression(node, parent, state, cb) {
cb(node.left, node, state);
cb(node.right, node, state);
};
walkers[Syntax.BlockStatement] = function(node, parent, state, cb) {
walkers[Syntax.BlockStatement] = function blockStatement(node, parent, state, cb) {
for (var i = 0, l = node.body.length; i < l; i++) {

@@ -84,3 +89,3 @@ cb(node.body[i], node, state);

walkers[Syntax.CallExpression] = function(node, parent, state, cb) {
walkers[Syntax.CallExpression] = function callExpression(node, parent, state, cb) {
var i;

@@ -103,3 +108,4 @@ var l;

// TODO: verify correctness
walkers[Syntax.ComprehensionExpression] = function(node, parent, state, cb) {
walkers[Syntax.ComprehensionExpression] =
function comprehensionExpression(node, parent, state, cb) {
cb(node.body, node, state);

@@ -116,3 +122,3 @@

walkers[Syntax.ConditionalExpression] = function(node, parent, state, cb) {
walkers[Syntax.ConditionalExpression] = function conditionalExpression(node, parent, state, cb) {
cb(node.test, node, state);

@@ -127,3 +133,3 @@ cb(node.consequent, node, state);

walkers[Syntax.DoWhileStatement] = function(node, parent, state, cb) {
walkers[Syntax.DoWhileStatement] = function doWhileStatement(node, parent, state, cb) {
cb(node.test, node, state);

@@ -135,7 +141,7 @@ cb(node.body, node, state);

walkers[Syntax.ExpressionStatement] = function(node, parent, state, cb) {
walkers[Syntax.ExpressionStatement] = function expressionStatement(node, parent, state, cb) {
cb(node.expression, node, state);
};
walkers[Syntax.ForInStatement] = function(node, parent, state, cb) {
walkers[Syntax.ForInStatement] = function forInStatement(node, parent, state, cb) {
cb(node.left, node, state);

@@ -148,3 +154,3 @@ cb(node.right, node, state);

walkers[Syntax.ForStatement] = function(node, parent, state, cb) {
walkers[Syntax.ForStatement] = function forStatement(node, parent, state, cb) {
if (node.init) {

@@ -165,3 +171,3 @@ cb(node.init, node, state);

walkers[Syntax.FunctionDeclaration] = function(node, parent, state, cb) {
walkers[Syntax.FunctionDeclaration] = function functionDeclaration(node, parent, state, cb) {
var i;

@@ -190,3 +196,3 @@ var l;

walkers[Syntax.IfStatement] = function(node, parent, state, cb) {
walkers[Syntax.IfStatement] = function ifStatement(node, parent, state, cb) {
cb(node.test, node, state);

@@ -199,3 +205,3 @@ cb(node.consequent, node, state);

walkers[Syntax.LabeledStatement] = function(node, parent, state, cb) {
walkers[Syntax.LabeledStatement] = function labeledStatement(node, parent, state, cb) {
cb(node.body, node, state);

@@ -205,3 +211,3 @@ };

// TODO: add scope info??
walkers[Syntax.LetStatement] = function(node, parent, state, cb) {
walkers[Syntax.LetStatement] = function letStatement(node, parent, state, cb) {
for (var i = 0, l = node.head.length; i < l; i++) {

@@ -220,5 +226,5 @@ var head = node.head[i];

walkers[Syntax.LogicalExpression] = walkers[Syntax.AssignmentExpression];
walkers[Syntax.LogicalExpression] = walkers[Syntax.BinaryExpression];
walkers[Syntax.MemberExpression] = function(node, parent, state, cb) {
walkers[Syntax.MemberExpression] = function memberExpression(node, parent, state, cb) {
if (node.property) {

@@ -232,3 +238,3 @@ cb(node.property, node, state);

walkers[Syntax.ObjectExpression] = function(node, parent, state, cb) {
walkers[Syntax.ObjectExpression] = function objectExpression(node, parent, state, cb) {
for (var i = 0, l = node.properties.length; i < l; i++) {

@@ -243,3 +249,3 @@ cb(node.properties[i], node, state);

walkers[Syntax.Property] = function(node, parent, state, cb) {
walkers[Syntax.Property] = function property(node, parent, state, cb) {
// move leading comments from key to property node

@@ -251,3 +257,3 @@ moveComments(node.key, node);

walkers[Syntax.ReturnStatement] = function(node, parent, state, cb) {
walkers[Syntax.ReturnStatement] = function returnStatement(node, parent, state, cb) {
if (node.argument) {

@@ -258,3 +264,3 @@ cb(node.argument, node, state);

walkers[Syntax.SequenceExpression] = function(node, parent, state, cb) {
walkers[Syntax.SequenceExpression] = function sequenceExpression(node, parent, state, cb) {
for (var i = 0, l = node.expressions.length; i < l; i++) {

@@ -265,3 +271,3 @@ cb(node.expressions[i], node, state);

walkers[Syntax.SwitchCase] = function(node, parent, state, cb) {
walkers[Syntax.SwitchCase] = function switchCase(node, parent, state, cb) {
if (node.test) {

@@ -276,3 +282,3 @@ cb(node.test, node, state);

walkers[Syntax.SwitchStatement] = function(node, parent, state, cb) {
walkers[Syntax.SwitchStatement] = function switchStatement(node, parent, state, cb) {
cb(node.discriminant, node, state);

@@ -287,7 +293,7 @@

walkers[Syntax.ThrowStatement] = function(node, parent, state, cb) {
walkers[Syntax.ThrowStatement] = function throwStatement(node, parent, state, cb) {
cb(node.argument, node, state);
};
walkers[Syntax.TryStatement] = function(node, parent, state, cb) {
walkers[Syntax.TryStatement] = function tryStatement(node, parent, state, cb) {
var i;

@@ -317,3 +323,3 @@ var l;

walkers[Syntax.UnaryExpression] = function(node, parent, state, cb) {
walkers[Syntax.UnaryExpression] = function unaryExpression(node, parent, state, cb) {
cb(node.argument, node, state);

@@ -324,3 +330,3 @@ };

walkers[Syntax.VariableDeclaration] = function(node, parent, state, cb) {
walkers[Syntax.VariableDeclaration] = function variableDeclaration(node, parent, state, cb) {
// move leading comments to first declarator

@@ -334,3 +340,3 @@ moveComments(node, node.declarations[0]);

walkers[Syntax.VariableDeclarator] = function(node, parent, state, cb) {
walkers[Syntax.VariableDeclarator] = function variableDeclarator(node, parent, state, cb) {
cb(node.id, node, state);

@@ -345,3 +351,3 @@

walkers[Syntax.WithStatement] = function(node, parent, state, cb) {
walkers[Syntax.WithStatement] = function withStatement(node, parent, state, cb) {
cb(node.object, node, state);

@@ -370,3 +376,3 @@ cb(node.body, node, state);

Walker.prototype._recurse = function(ast) {
// TODO: look for other state that we can track/attach during the walk
// TODO: track variables/aliases during the walk
var state = {

@@ -379,14 +385,17 @@ nodes: [],

function cb(node, parent, state) {
var isScope = isScopeNode(node);
var currentScope;
if (node.parent === undefined) {
Object.defineProperty(node, 'parent', {
value: parent || null
});
var isScope = astnode.isScope(node);
// for efficiency, if the node has a knownVariables property, assume that we've already
// added the required properties
if (!node.knownVariables) {
astnode.addNodeProperties(node);
}
if (node.enclosingScope === undefined) {
Object.defineProperty(node, 'enclosingScope', {
value: getCurrentScope(state.scopes)
});
node.parent = parent || null;
currentScope = getCurrentScope(state.scopes);
if (currentScope) {
node.enclosingScope = currentScope;
}

@@ -393,0 +402,0 @@

@@ -22,10 +22,27 @@ /*global env: true */

type: require('jsdoc/tag/type')
},
util: {
logger: require('jsdoc/util/logger')
}
};
var path = require('jsdoc/path');
function trim(text, newlines) {
function trim(text, opts) {
var indentMatcher;
var match;
opts = opts || {};
if (!text) { return ''; }
if (newlines) {
return text.replace(/^[\n\r\f]+|[\n\r\f]+$/g, '');
if (opts.keepsWhitespace) {
text = text.replace(/^[\n\r\f]+|[\n\r\f]+$/g, '');
if (opts.removesIndent) {
match = text.match(/^([ \t]+)/);
if (match && match[1]) {
indentMatcher = new RegExp('^' + match[1], 'gm');
text = text.replace(indentMatcher, '');
}
}
return text;
}

@@ -88,2 +105,5 @@ else {

var Tag = exports.Tag = function(tagTitle, tagBody, meta) {
var tagDef;
var trimOpts;
meta = meta || {};

@@ -96,12 +116,27 @@

var tagDef = jsdoc.tag.dictionary.lookUp(this.title);
tagDef = jsdoc.tag.dictionary.lookUp(this.title);
trimOpts = {
keepsWhitespace: tagDef.keepsWhitespace,
removesIndent: tagDef.removesIndent
};
/** The text part of the tag: @title text */
this.text = trim(tagBody, tagDef.keepsWhitespace);
this.text = trim(tagBody, trimOpts);
if (this.text) {
processTagText(this, tagDef);
try {
processTagText(this, tagDef);
jsdoc.tag.validator.validate(this, tagDef, meta);
}
catch (e) {
// probably a type-parsing error
jsdoc.util.logger.error(
'Unable to create a Tag object%s with title "%s" and body "%s": %s',
meta.filename ? ( ' for source file ' + path.join(meta.path, meta.filename) ) : '',
tagTitle,
tagBody,
e.message
);
}
}
jsdoc.tag.validator.validate(this, tagDef, meta);
};

@@ -17,3 +17,5 @@ /*global app: true, env: true */

var commonPrefix = path.commonPrefix( sourceFiles.concat(env.opts._ || []) );
var result = (filepath + '/').replace(commonPrefix, '');
// always use forward slashes
var result = (filepath + path.sep).replace(commonPrefix, '')
.replace(/\\/g, '/');

@@ -45,2 +47,8 @@ if (result.length > 0 && result[result.length - 1] !== '/') {

function setDocletNameToValueName(doclet, tag) {
if (tag.value && tag.value.name) {
doclet.addTag('name', tag.value.name);
}
}
function setDocletDescriptionToValue(doclet, tag) {

@@ -52,2 +60,8 @@ if (tag.value) {

function setDocletTypeToValueType(doclet, tag) {
if (tag.value && tag.value.type) {
doclet.type = tag.value.type;
}
}
function setNameToFile(doclet, tag) {

@@ -214,8 +228,7 @@ var name;

canHaveType: true,
canHaveName: true,
onTagged: function(doclet, tag) {
setDocletKindToTitle(doclet, tag);
setDocletNameToValue(doclet, tag);
if (tag.value && tag.value.type) {
doclet.type = tag.value.type;
}
setDocletNameToValueName(doclet, tag);
setDocletTypeToValueType(doclet, tag);
}

@@ -290,3 +303,3 @@ })

doclet.isEnum = true;
if (tag.value && tag.value.type) { doclet.type = tag.value.type; }
setDocletTypeToValueType(doclet, tag);
}

@@ -305,2 +318,3 @@ });

keepsWhitespace: true,
removesIndent: true,
mustHaveValue: true,

@@ -319,5 +333,3 @@ onTagged: function(doclet, tag) {

doclet.exceptions.push(tag.value);
if (tag.value && tag.value.type) {
doclet.type = tag.value.type;
}
setDocletTypeToValueType(doclet, tag);
}

@@ -332,5 +344,5 @@ })

setDocletKindToTitle(doclet, tag);
setDocletNameToValue(doclet, tag);
if (tag.value && tag.value.type) {
doclet.type = tag.value.type;
setDocletTypeToValueType(doclet, tag);
doclet.addTag('name', doclet.type.names[0]);
}

@@ -441,8 +453,7 @@ }

canHaveType: true,
canHaveName: true,
onTagged: function(doclet, tag) {
setDocletKindToTitle(doclet, tag);
setDocletNameToValue(doclet, tag);
if (tag.value && tag.value.type) {
doclet.type = tag.value.type;
}
setDocletNameToValueName(doclet, tag);
setDocletTypeToValueType(doclet, tag);
}

@@ -485,5 +496,3 @@ })

}
if (tag.value && tag.value.type) {
doclet.type = tag.value.type;
}
setDocletTypeToValueType(doclet, tag);
}

@@ -501,5 +510,3 @@ });

setDocletNameToValue(doclet, tag);
if (tag.value && tag.value.type) {
doclet.type = tag.value.type;
}
setDocletTypeToValueType(doclet, tag);
}

@@ -625,3 +632,2 @@ });

onTagged: function(doclet, tag) {
if (!doclet.see) { doclet.see = []; }
doclet['this'] = firstWordOf(tag.value);

@@ -661,3 +667,3 @@ }

if (tag.value && tag.value.type) {
doclet.type = tag.value.type;
setDocletTypeToValueType(doclet, tag);

@@ -679,5 +685,3 @@ // for backwards compatibility, we allow @type for functions to imply return type

if (tag.value) {
if (tag.value.name) {
doclet.addTag('name', tag.value.name);
}
setDocletNameToValueName(doclet, tag);

@@ -692,4 +696,4 @@ // callbacks are always type {function}

}
else if (tag.value.type) {
doclet.type = tag.value.type;
else {
setDocletTypeToValueType(doclet, tag);
}

@@ -696,0 +700,0 @@ }

@@ -242,4 +242,4 @@ /**

// always re-throw so the caller has a chance to report which file was bad
throw new Error( util.format('unable to parse the type expression "%s": %s',
tagInfo.typeExpression, e.message) );
throw new Error( util.format('Invalid type expression "%s": %s', tagInfo.typeExpression,
e.message) );
}

@@ -246,0 +246,0 @@

@@ -13,2 +13,3 @@ /*global env: true */

var format = require('util').format;
var logger = require('jsdoc/util/logger');

@@ -24,23 +25,2 @@ function buildMessage(tagName, meta, desc) {

function UnknownTagError(tagName, meta) {
this.name = 'UnknownTagError';
this.message = buildMessage(tagName, meta, 'is not a known tag');
}
UnknownTagError.prototype = new Error();
UnknownTagError.prototype.constructor = UnknownTagError;
function TagValueRequiredError(tagName, meta) {
this.name = 'TagValueRequiredError';
this.message = buildMessage(tagName, meta, 'requires a value');
}
TagValueRequiredError.prototype = new Error();
TagValueRequiredError.prototype.constructor = TagValueRequiredError;
function TagValueNotPermittedError(tagName, meta) {
this.name = 'TagValueNotPermittedError';
this.message = buildMessage(tagName, meta, 'does not permit a value');
}
TagValueNotPermittedError.prototype = new Error();
TagValueNotPermittedError.prototype.constructor = TagValueNotPermittedError;
/**

@@ -51,8 +31,7 @@ * Validate the given tag.

if (!tagDef && !env.conf.tags.allowUnknownTags) {
require('jsdoc/util/error').handle( new UnknownTagError(tag.title, meta) );
logger.error( buildMessage(tag.title, meta, 'is not a known tag') );
}
if (!tag.text) {
else if (!tag.text) {
if (tagDef.mustHaveValue) {
require('jsdoc/util/error').handle( new TagValueRequiredError(tag.title, meta) );
logger.error( buildMessage(tag.title, meta, 'requires a value') );
}

@@ -62,5 +41,5 @@ }

if (tagDef.mustNotHaveValue) {
require('jsdoc/util/error').handle( new TagValueNotPermittedError(tag.title, meta) );
logger.error( buildMessage(tag.title, meta, 'does not permit a value') );
}
}
};

@@ -41,4 +41,3 @@ /**

exports.Template.prototype.load = function(file) {
var _path = path.join(this.path, file);
return _.template(fs.readFileSync(_path, 'utf8'), null, this.settings);
return _.template(fs.readFileSync(file, 'utf8'), null, this.settings);
};

@@ -57,2 +56,4 @@

exports.Template.prototype.partial = function(file, data) {
file = path.resolve(this.path, file);
// load template into cache

@@ -59,0 +60,0 @@ if (!(file in this.cache)) {

@@ -15,3 +15,3 @@ /*global env: true */

fs = require('jsdoc/fs'),
error = require('jsdoc/util/error'),
logger = require('jsdoc/util/logger'),
path = require('path'),

@@ -65,3 +65,3 @@ hasOwnProp = Object.prototype.hasOwnProperty,

if (hasOwnProp.call(conf, name)) {
error.handle(new Error("Tutorial " + name + "'s metadata is defined multiple times, only the first will be used."));
logger.warn('Metadata for the tutorial %s is defined more than once. Only the first definition will be used.', name );
} else {

@@ -84,3 +84,3 @@ conf[name] = meta;

if (hasOwnProp.call(tutorials, current.name)) {
error.handle(new Error("Tutorial with name " + current.name + " exists more than once, not adding (same name, different file extensions?)"));
logger.warn('The tutorial %s is defined more than once. Only the first definition will be used.', current.name);
} else {

@@ -185,3 +185,3 @@ tutorials[current.name] = current;

if (!hasOwnProp.call(tutorials, child)) {
error.handle( new Error("Missing child tutorial: " + child) );
logger.error('Missing child tutorial: %s', child);
}

@@ -188,0 +188,0 @@ else {

@@ -21,3 +21,3 @@ /**

else {
clone = Object.create(o);
clone = Object.create( Object.getPrototypeOf(o) );
props = Object.getOwnPropertyNames(o);

@@ -24,0 +24,0 @@ for (i = 0, l = props.length; i < l; i++) {

@@ -11,5 +11,8 @@ /**

var seenItems = [];
function seen(object) {
if (seenItems.indexOf(object) !== -1) {
function ObjectWalker() {
this.seenItems = [];
}
ObjectWalker.prototype.seen = function(object) {
if (this.seenItems.indexOf(object) !== -1) {
return true;

@@ -19,42 +22,44 @@ }

return false;
}
};
// some objects are unwalkable, like Java native objects
function isUnwalkable(o) {
ObjectWalker.prototype.isUnwalkable = function(o) {
return (o && typeof o === 'object' && typeof o.constructor === 'undefined');
}
};
function isFunction(o) {
ObjectWalker.prototype.isFunction = function(o) {
return (o && typeof o === 'function' || o instanceof Function);
}
};
function isObject(o) {
ObjectWalker.prototype.isObject = function(o) {
return o && o instanceof Object ||
(o && typeof o.constructor !== 'undefined' && o.constructor.name === 'Object');
}
};
function checkCircularRefs(o, func) {
if ( seen(o) ) {
ObjectWalker.prototype.checkCircularRefs = function(o, func) {
if ( this.seen(o) ) {
return '<CircularRef>';
}
else {
seenItems.push(o);
this.seenItems.push(o);
return func(o);
}
}
};
function walk(o) {
ObjectWalker.prototype.walk = function(o) {
var result;
if ( isUnwalkable(o) ) {
var self = this;
if ( this.isUnwalkable(o) ) {
result = '<Object>';
}
else if ( o === undefined ) {
result = 'undefined';
result = null;
}
else if ( Array.isArray(o) ) {
result = checkCircularRefs(o, function(arr) {
result = this.checkCircularRefs(o, function(arr) {
var newArray = [];
arr.forEach(function(item) {
newArray.push( walk(item) );
newArray.push( self.walk(item) );
});

@@ -74,10 +79,10 @@

}
else if ( isFunction(o) ) {
else if ( this.isFunction(o) ) {
result = '<Function' + (o.name ? ' ' + o.name : '') + '>';
}
else if ( isObject(o) && o !== null ) {
result = checkCircularRefs(o, function(obj) {
else if ( this.isObject(o) && o !== null ) {
result = this.checkCircularRefs(o, function(obj) {
var newObj = {};
Object.keys(obj).forEach(function(key) {
newObj[key] = walk(obj[key]);
newObj[key] = self.walk(obj[key]);
});

@@ -94,3 +99,3 @@

return result;
}
};

@@ -101,3 +106,3 @@ /**

exports.dump = function(object) {
return JSON.stringify(walk(object), null, 4);
return JSON.stringify(new ObjectWalker().walk(object), null, 4);
};
/*global env: true */
/**
Helper functions for handling errors.
@module jsdoc/util/error
* Helper functions for handling errors.
*
* @deprecated As of JSDoc 3.3.0. This module may be removed in a future release. Use the module
* {@link module:jsdoc/util/logger} to log warnings and errors.
* @module jsdoc/util/error
*/

@@ -9,26 +12,25 @@ 'use strict';

/**
Handle an exception appropriately based on whether lenient mode is enabled:
+ If lenient mode is enabled, log the exception to the console.
+ If lenient mode is not enabled, re-throw the exception.
@param {Error} e - The exception to handle.
@exception {Error} Re-throws the original exception unless lenient mode is enabled.
@memberof module:jsdoc/util/error
* Log an exception as an error.
*
* Prior to JSDoc 3.3.0, this method would either log the exception (if lenient mode was enabled) or
* re-throw the exception (default).
*
* In JSDoc 3.3.0 and later, lenient mode has been replaced with strict mode, which is disabled by
* default. If strict mode is enabled, calling the `handle` method causes JSDoc to exit immediately,
* just as if the exception had been re-thrown.
*
* @deprecated As of JSDoc 3.3.0. This module may be removed in a future release.
* @param {Error} e - The exception to log.
* @memberof module:jsdoc/util/error
*/
exports.handle = function(e) {
var msg;
var logger = require('jsdoc/util/logger');
var msg = e ? ( e.message || JSON.stringify(e) ) : '';
if (env.opts.lenient) {
msg = e.message || JSON.stringify(e);
// include the error type if it's an Error object
if (e instanceof Error) {
msg = e.name + ': ' + msg;
}
// include the error type if it's an Error object
if (e instanceof Error) {
msg = e.name + ': ' + msg;
}
console.log(msg);
}
else {
throw e;
}
logger.error(msg);
};

@@ -76,5 +76,5 @@ /*global env: true */

* returns the resulting HTML.
* @throws {Error} If the name does not correspond to a known parser.
*/
function getParseFunction(parserName, conf) {
var logger = require('jsdoc/util/logger');
var marked = require('marked');

@@ -103,3 +103,4 @@ var parserFunction;

else {
throw new Error("unknown Markdown parser: '" + parserName + "'");
logger.error('Unrecognized Markdown parser "%s". Markdown support is disabled.',
parserName);
}

@@ -113,5 +114,5 @@ }

* HTML, then returns the HTML as a string.
* @returns {Function} A function that accepts Markdown source, feeds it to the selected parser, and
*
* @returns {function} A function that accepts Markdown source, feeds it to the selected parser, and
* returns the resulting HTML.
* @throws {Error} If the value of `env.conf.markdown.parser` does not correspond to a known parser.
*/

@@ -118,0 +119,0 @@ exports.getParser = function() {

@@ -22,3 +22,3 @@ /*global env: true */

* + `module:jsdoc/util/runtime~RHINO`: Mozilla Rhino.
* + `module:jsdoc/util/runtime~NODE`: Node.js (not currently supported).
* + `module:jsdoc/util/runtime~NODE`: Node.js.
*

@@ -48,3 +48,3 @@ * @private

/**
* Check whether Node.js is running JSDoc. (Node.js is not currently supported.)
* Check whether Node.js is running JSDoc.
* @return {boolean} Set to `true` if the current runtime is Node.js.

@@ -57,25 +57,7 @@ */

function initializeRhino(args) {
// note: mutates args
function getDirname() {
var dirname;
// the JSDoc dirname is the main module URI, minus the filename, converted to a path
var uriParts = require.main.uri.split('/');
uriParts.pop();
// Rhino has no native way to get the base dirname of the current script,
// so this information must be manually passed in from the command line.
for (var i = 0, l = args.length; i < l; i++) {
if ( /^--dirname(?:=(.+?)(\/|\/\.)?)?$/i.test(args[i]) ) {
if (RegExp.$1) {
dirname = RegExp.$1; // last wins
args.splice(i--, 1); // remove --dirname opt from arguments
}
else {
dirname = args[i + 1];
args.splice(i--, 2);
}
}
}
return dirname;
}
env.dirname = getDirname();
env.dirname = String( new java.io.File(new java.net.URI(uriParts.join('/'))) );
env.pwd = String( java.lang.System.getenv().get('PWD') );

@@ -92,3 +74,3 @@ env.args = args;

var jsdocPath = args[0];
var pwd = process.env.PWD || args[1];
var pwd = args[1];

@@ -114,3 +96,3 @@ // resolve the path if it's a symlink

default:
throw new Error('Unable to initialize the JavaScript runtime!');
throw new Error('Cannot initialize the unknown JavaScript runtime "' + runtime + '"!');
}

@@ -117,0 +99,0 @@ };

@@ -127,3 +127,3 @@ /*global env: true */

err = new Error('unable to parse ' + longname + ': ' + e.message);
require('jsdoc/util/error').handle(err);
require('jsdoc/util/logger').error(err);
return longname;

@@ -289,3 +289,3 @@ }

if (!node) {
require('jsdoc/util/error').handle( new Error('No such tutorial: '+tutorial) );
require('jsdoc/util/logger').error( new Error('No such tutorial: ' + tutorial) );
return;

@@ -322,3 +322,3 @@ }

if (!tutorial) {
require('jsdoc/util/error').handle( new Error('Missing required parameter: tutorial') );
require('jsdoc/util/logger').error( new Error('Missing required parameter: tutorial') );
return;

@@ -325,0 +325,0 @@ }

@@ -264,2 +264,17 @@ # License #

## node-browser-builtins ##
Portions of the node-browser-builtins source code are incorporated into the
following files:
- `rhino/assert.js`
- `rhino/rhino-shim.js`
node-browser-builtins is distributed under the MIT license, which is reproduced
above.
The source code for node-browser-builtins is available at:
https://github.com/alexgorbatchev/node-browser-builtins
## node-browserify ##

@@ -360,2 +375,11 @@

## tv4 ##
tv4 is in the public domain. It is also distributed under the MIT license, which
is reproduced above.
The source code for tv4 is available at:
https://github.com/geraintluff/tv4
## Underscore.js ##

@@ -362,0 +386,0 @@

@@ -12,25 +12,58 @@ #!/usr/bin/env node

fs.symlink(symlinkSrc, symlinkDest, 'dir', function(err) {
if (err) {
// On Windows, try to create a junction instead
if (process.platform.indexOf('win') === 0) {
fs.symlink(symlinkSrc, symlinkDest, 'junction', function(junctionErr) {
if (junctionErr) {
console.error('Unable to create a symbolic link or junction from %s to %s.\n' +
'Symbolic link result: %s\nJunction result: %s\n' +
'Make sure you have write privileges in the target directory. ' +
'You may need to run the Windows shell as an administrator.',
symlinkSrc, symlinkDest, err, junctionErr);
process.exit(1);
}
else {
process.exit(0);
}
});
function createJunction(err) {
fs.symlink(symlinkSrc, symlinkDest, 'junction', function(junctionErr) {
if (junctionErr) {
console.error('Unable to create a symbolic link or junction from %s to %s.\n' +
'Symbolic link result: %s\nJunction result: %s\n' +
'Make sure you have write privileges in the target directory. ' +
'You may need to run the Windows shell as an administrator.',
symlinkSrc, symlinkDest, err, junctionErr);
process.exit(1);
}
else {
console.error('Unable to create a symbolic link from %s to %s. %s\n',
symlinkSrc, symlinkDest, err);
process.exit(0);
}
});
}
function checkLink() {
fs.readlink(symlinkDest, function(readlinkErr, linkString) {
if (!readlinkErr) {
linkString = path.resolve(path.dirname(symlinkDest), linkString);
if (linkString === symlinkSrc) {
// the existing symlink points to the right place
process.exit(0);
}
else {
console.error('The symlink at %s points to %s, but it should point to %s. ' +
'Please remove the symlink and try again.', symlinkDest, linkString,
symlinkSrc);
process.exit(1);
}
}
else {
console.error('Unable to read the symlink at %s. Please remove the symlink and try ' +
'again', symlinkDest);
process.exit(1);
}
});
}
fs.symlink(symlinkSrc, symlinkDest, 'dir', function(err) {
if (err) {
// Does the symlink already exist? If so, does it point to the right place?
fs.lstat(symlinkDest, function(lstatErr, stats) {
if ( stats && stats.isSymbolicLink() ) {
checkLink();
}
// On Windows, try to create a junction instead
else if (process.platform.indexOf('win') === 0) {
createJunction();
}
else {
console.error('Unable to create a symbolic link from %s to %s. %s\n', symlinkSrc,
symlinkDest, err);
process.exit(1);
}
});
}

@@ -37,0 +70,0 @@ else {

{
"name": "jsdoc",
"version": "3.3.0-alpha2",
"revision": "1384269864915",
"version": "3.3.0-alpha3",
"revision": "1387991255485",
"description": "An API documentation generator for JavaScript.",
"keywords": [ "documentation", "javascript" ],
"keywords": [
"documentation",
"javascript"
],
"licenses": [
{
"type": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0"
"url": "http://www.apache.org/licenses/LICENSE-2.0"
}

@@ -15,16 +18,19 @@ ],

"type": "git",
"url": "https://github.com/jsdoc3/jsdoc"
"url": "https://github.com/jsdoc3/jsdoc"
},
"dependencies": {
"async": "0.1.22",
"catharsis": "0.7.0",
"esprima": "1.0.4",
"js2xmlparser": "0.1.0",
"marked": "0.2.8",
"taffydb": "git+https://github.com/hegemonic/taffydb.git",
"underscore": "1.4.2",
"wrench": "1.3.9"
"async": "~0.1.22",
"catharsis": "~0.7.0",
"esprima": "~1.0.4",
"js2xmlparser": "~0.1.0",
"marked": "~0.2.8",
"taffydb": "git+https://github.com/hegemonic/taffydb.git",
"underscore": "~1.4.2",
"wrench": "~1.3.9"
},
"devDependencies": {
"jshint": "2.3.0"
"grunt": "~0.4.2",
"grunt-bumpup": "~0.4.2",
"jshint": "~2.3.0",
"tv4": "git+https://github.com/hegemonic/tv4.git#own-properties"
},

@@ -42,3 +48,3 @@ "engines": {

"author": {
"name": "Michael Mathews",
"name": "Michael Mathews",
"email": "micmath@gmail.com"

@@ -45,0 +51,0 @@ },

@@ -7,2 +7,4 @@ /**

var logger = require('jsdoc/util/logger');
exports.handlers = {

@@ -36,3 +38,4 @@ /**

catch(e) {
throw new Error('@source tag expects a valid JSON value, like { "filename": "myfile.js", "lineno": 123 }.');
logger.error('@source tag expects a valid JSON value, like { "filename": "myfile.js", "lineno": 123 }.');
return;
}

@@ -46,2 +49,2 @@

}
};
};

@@ -38,5 +38,5 @@ JSDoc 3

./node_modules/bin/jsdoc yourJavaScriptFile.js
./node_modules/.bin/jsdoc yourJavaScriptFile.js
Or if you installed JSDoc globally:
Or if you installed JSDoc globally, simply run the `jsdoc` command:

@@ -43,0 +43,0 @@ jsdoc yourJavaScriptFile.js

@@ -8,3 +8,3 @@ /*global env: true */

taffy = require('taffydb').taffy,
handle = require('jsdoc/util/error').handle,
logger = require('jsdoc/util/logger'),
helper = require('jsdoc/util/templateHelper'),

@@ -93,8 +93,6 @@ htmlsafe = helper.htmlsafe,

function shortenPaths(files, commonPrefix) {
// always use forward slashes
var regexp = new RegExp('\\\\', 'g');
Object.keys(files).forEach(function(file) {
files[file].shortened = files[file].resolved.replace(commonPrefix, '')
.replace(regexp, '/');
// always use forward slashes
.replace(/\\/g, '/');
});

@@ -111,3 +109,3 @@

return doclet.meta.path && doclet.meta.path !== 'null' ?
doclet.meta.path + '/' + doclet.meta.filename :
path.join(doclet.meta.path, doclet.meta.filename) :
doclet.meta.filename;

@@ -149,3 +147,3 @@ }

catch(e) {
handle(e);
logger.error('Error while generating source file %s: %s', file, e.message);
}

@@ -333,3 +331,6 @@

// set up templating
view.layout = 'layout.tmpl';
view.layout = conf['default'].layoutFile ?
path.getResourcePath(path.dirname(conf['default'].layoutFile),
path.basename(conf['default'].layoutFile) ) :
'layout.tmpl';

@@ -377,3 +378,5 @@ // set up tutorials for helper

};
sourceFilePaths.push(sourcePath);
if (sourceFilePaths.indexOf(sourcePath) === -1) {
sourceFilePaths.push(sourcePath);
}
}

@@ -380,0 +383,0 @@ });

(function() {
var counter = 0;
var numbered;
var source = document.getElementsByClassName('prettyprint source');
var source = document.getElementsByClassName('prettyprint source linenums');
var i = 0;
var lineNumber = 0;
var lineId;
var lines;
var totalLines;
var anchorHash;
if (source && source[0]) {
source = source[0].getElementsByTagName('code')[0];
anchorHash = document.location.hash.substring(1);
lines = source[0].getElementsByTagName('li');
totalLines = lines.length;
numbered = source.innerHTML.split('\n');
numbered = numbered.map(function(item) {
counter++;
return '<span id="line' + counter + '" class="line"></span>' + item;
});
source.innerHTML = numbered.join('\n');
for (; i < totalLines; i++) {
lineNumber++;
lineId = 'line' + lineNumber;
lines[i].id = lineId;
if (lineId === anchorHash) {
lines[i].className += ' selected';
}
}
}
})();

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc