mirror of
https://github.com/jsdoc/jsdoc.git
synced 2025-12-08 19:46:11 +00:00
overhaul logging and error handling (#416)
This commit is contained in:
parent
2babc5b1c3
commit
c9b0237c12
15
LICENSE.md
15
LICENSE.md
@ -261,6 +261,21 @@ The source code for Node.js is available at:
|
||||
https://github.com/joyent/node
|
||||
|
||||
|
||||
## 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 ##
|
||||
|
||||
Portions of the node-browserify source code are incorporated into the following
|
||||
|
||||
195
cli.js
195
cli.js
@ -3,32 +3,39 @@
|
||||
*
|
||||
* A few critical notes for anyone who works on this module:
|
||||
*
|
||||
* + 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.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
module.exports = (function() {
|
||||
'use strict';
|
||||
|
||||
var logger = require('jsdoc/util/logger');
|
||||
|
||||
var props = {
|
||||
docs: [],
|
||||
shouldExitWithError: false,
|
||||
packageJson: null
|
||||
};
|
||||
|
||||
var app = global.app;
|
||||
var env = global.env;
|
||||
|
||||
var JSDoc = {};
|
||||
var fatalErrorMessage = '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') );
|
||||
|
||||
env.version = {
|
||||
@ -36,11 +43,11 @@ JSDoc.setVersionInfo = function() {
|
||||
revision: new Date( parseInt(info.revision, 10) ).toUTCString()
|
||||
};
|
||||
|
||||
return JSDoc;
|
||||
return cli;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
JSDoc.loadConfig = function() {
|
||||
cli.loadConfig = function() {
|
||||
var _ = require('underscore');
|
||||
var args = require('jsdoc/opts/args');
|
||||
var Config = require('jsdoc/config');
|
||||
@ -55,7 +62,12 @@ JSDoc.loadConfig = function() {
|
||||
encoding: 'utf8'
|
||||
};
|
||||
|
||||
env.opts = args.parse(env.args);
|
||||
try {
|
||||
env.opts = args.parse(env.args);
|
||||
}
|
||||
catch (e) {
|
||||
cli.exit(1, e.message + '\n' + fatalErrorMessage);
|
||||
}
|
||||
|
||||
confPath = env.opts.configure || path.join(env.dirname, 'conf.json');
|
||||
try {
|
||||
@ -74,48 +86,109 @@ JSDoc.loadConfig = function() {
|
||||
.get();
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error('Cannot parse the config file ' + confPath + ': ' + e);
|
||||
cli.exit(1, 'Cannot parse the config file ' + confPath + ': ' + e + '\n' +
|
||||
fatalErrorMessage);
|
||||
}
|
||||
|
||||
// look for options on the command line, in the config file, and in the defaults, in that order
|
||||
env.opts = _.defaults(env.opts, env.conf.opts, defaultOpts);
|
||||
|
||||
return JSDoc;
|
||||
return cli;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
JSDoc.runCommand = function(cb) {
|
||||
cli.configureLogger = function() {
|
||||
function recoverableError() {
|
||||
props.shouldExitWithError = true;
|
||||
}
|
||||
|
||||
function fatalError() {
|
||||
cli.exit(1, fatalErrorMessage);
|
||||
}
|
||||
|
||||
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: {"env":{"conf":%j,"opts":%j}}', env.conf, 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;
|
||||
|
||||
var opts = env.opts;
|
||||
|
||||
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) {
|
||||
JSDoc.printVersion(function() {
|
||||
console.log( '\n' + require('jsdoc/opts/args').help() );
|
||||
console.log('\n' + 'Visit http://usejsdoc.org for more information.');
|
||||
cb(0);
|
||||
});
|
||||
cli.printHelp = function(cb) {
|
||||
console.log( '\n' + require('jsdoc/opts/args').help() + '\n' );
|
||||
console.log('Visit http://usejsdoc.org for more information.');
|
||||
cb(0);
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
JSDoc.runTests = function(cb) {
|
||||
cli.runTests = function(cb) {
|
||||
var path = require('jsdoc/path');
|
||||
|
||||
var runner = require( path.join(env.dirname, 'test/runner') );
|
||||
@ -127,17 +200,26 @@ JSDoc.runTests = function(cb) {
|
||||
};
|
||||
|
||||
// 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()
|
||||
.processParseResults();
|
||||
}
|
||||
@ -146,7 +228,8 @@ JSDoc.main = function(cb) {
|
||||
cb(0);
|
||||
};
|
||||
|
||||
JSDoc.scanFiles = function() {
|
||||
// TODO: docs
|
||||
cli.scanFiles = function() {
|
||||
var Filter = require('jsdoc/src/filter').Filter;
|
||||
var fs = require('jsdoc/fs');
|
||||
var Readme = require('jsdoc/readme');
|
||||
@ -181,10 +264,10 @@ JSDoc.scanFiles = function() {
|
||||
filter);
|
||||
}
|
||||
|
||||
return JSDoc;
|
||||
return cli;
|
||||
};
|
||||
|
||||
JSDoc.createParser = function() {
|
||||
cli.createParser = function() {
|
||||
var handlers = require('jsdoc/src/handlers');
|
||||
var parser = require('jsdoc/src/parser');
|
||||
var plugins = require('jsdoc/plugins');
|
||||
@ -197,10 +280,10 @@ JSDoc.createParser = function() {
|
||||
|
||||
handlers.attachTo(app.jsdoc.parser);
|
||||
|
||||
return JSDoc;
|
||||
return cli;
|
||||
};
|
||||
|
||||
JSDoc.parseFiles = function() {
|
||||
cli.parseFiles = function() {
|
||||
var augment = require('jsdoc/augment');
|
||||
var borrow = require('jsdoc/borrow');
|
||||
var Package = require('jsdoc/package').Package;
|
||||
@ -216,40 +299,46 @@ JSDoc.parseFiles = function() {
|
||||
packageDocs.files = env.sourceFiles || [];
|
||||
docs.push(packageDocs);
|
||||
|
||||
logger.debug('Adding inherited symbols...');
|
||||
borrow.indexAll(docs);
|
||||
|
||||
augment.addInherited(docs);
|
||||
borrow.resolveBorrows(docs);
|
||||
|
||||
app.jsdoc.parser.fireProcessingComplete(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');
|
||||
|
||||
if (env.opts.tutorials) {
|
||||
resolver.load(env.opts.tutorials);
|
||||
resolver.resolve();
|
||||
}
|
||||
|
||||
return cli;
|
||||
};
|
||||
|
||||
JSDoc.generateDocs = function() {
|
||||
cli.generateDocs = function() {
|
||||
var path = require('jsdoc/path');
|
||||
var resolver = require('jsdoc/tutorial/resolver');
|
||||
var taffy = require('taffydb').taffy;
|
||||
@ -266,26 +355,38 @@ JSDoc.generateDocs = function() {
|
||||
template = require(env.opts.template + '/publish');
|
||||
}
|
||||
catch(e) {
|
||||
throw new Error('Unable to load template: ' + e.message || e);
|
||||
logger.fatal('Unable to load template: ' + e.message || e);
|
||||
}
|
||||
|
||||
// templates should include a publish.js file that exports a "publish" function
|
||||
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(
|
||||
taffy(props.docs),
|
||||
env.opts,
|
||||
resolver.root
|
||||
);
|
||||
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, errorMessage) {
|
||||
if (errorMessage) {
|
||||
logger.fatal(errorMessage);
|
||||
}
|
||||
|
||||
process.exit(exitCode || 0);
|
||||
};
|
||||
|
||||
return cli;
|
||||
|
||||
})();
|
||||
|
||||
3
jsdoc
3
jsdoc
@ -28,10 +28,7 @@ ENCODEDBASEPATH=`echo "$BASEPATH" | sed -e 's/ /%20/g'`
|
||||
|
||||
if test "$1" = "--debug"
|
||||
then
|
||||
echo "Running Debug"
|
||||
CMD="org.mozilla.javascript.tools.debugger.Main -debug -opt -1"
|
||||
# strip --debug argument
|
||||
shift
|
||||
else
|
||||
CMD="org.mozilla.javascript.tools.shell.Main"
|
||||
fi
|
||||
|
||||
10
jsdoc.cmd
10
jsdoc.cmd
@ -25,18 +25,10 @@ IF NOT "%_URLPATH%"=="%_URLPATH: =%" GOTO ESCAPE_SPACE
|
||||
IF [%1]==[--debug] (
|
||||
ECHO Running Debug
|
||||
SET CMD=org.mozilla.javascript.tools.debugger.Main -debug -opt -1
|
||||
|
||||
REM `SHIFT` doesn't affect %*
|
||||
:COLLECT_ARGS
|
||||
IF [%2]==[] GOTO LAST_ARG
|
||||
SET ARGS=%ARGS% %2
|
||||
SHIFT
|
||||
GOTO COLLECT_ARGS
|
||||
) ELSE (
|
||||
SET CMD=org.mozilla.javascript.tools.shell.Main
|
||||
SET ARGS=%*
|
||||
)
|
||||
:LAST_ARG
|
||||
SET ARGS=%*
|
||||
|
||||
IF [%1]==[-T] (
|
||||
java -classpath "%_BASEPATH%/rhino/js.jar" %CMD% -opt -1 -modules "%_URLPATH%/lib" -modules "%_URLPATH%/node_modules" -modules "%_URLPATH%/rhino" -modules "%_URLPATH%" "%_BASEPATH%/jsdoc.js" %ARGS% --nocolor --dirname="%_BASEPATH%/
|
||||
|
||||
21
jsdoc.js
21
jsdoc.js
@ -126,10 +126,7 @@ global.dump = function() {
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
function cb(errorCode) {
|
||||
process.exit(errorCode || 0);
|
||||
}
|
||||
|
||||
var logger = require('jsdoc/util/logger');
|
||||
var path = require('jsdoc/path');
|
||||
var runtime = require('jsdoc/util/runtime');
|
||||
|
||||
@ -138,6 +135,17 @@ global.dump = function() {
|
||||
cli.setVersionInfo()
|
||||
.loadConfig();
|
||||
|
||||
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)
|
||||
if ( runtime.isRhino() ) {
|
||||
try {
|
||||
@ -145,11 +153,10 @@ global.dump = function() {
|
||||
}
|
||||
catch(e) {
|
||||
if (e.rhinoException) {
|
||||
e.rhinoException.printStackTrace();
|
||||
process.exit(1);
|
||||
logger.fatal( e.rhinoException.printStackTrace() );
|
||||
} else {
|
||||
console.trace(e);
|
||||
process.exit(1);
|
||||
cli.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,8 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var doop = require("jsdoc/util/doop").doop;
|
||||
var doop = require('jsdoc/util/doop');
|
||||
var logger = require('jsdoc/util/logger');
|
||||
|
||||
var hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
|
||||
@ -31,7 +32,8 @@ exports.indexAll = function(docs) {
|
||||
*/
|
||||
exports.resolveBorrows = function(docs) {
|
||||
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;
|
||||
}
|
||||
|
||||
docs.forEach(function(doc) {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
@ -11,29 +11,45 @@ var _ = require('underscore');
|
||||
var hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
|
||||
/**
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -49,209 +65,234 @@ ArgParser.prototype._getOptionByLongName = function(name) {
|
||||
* myParser.addOption('h', 'help', false, 'Show the help message.');
|
||||
*/
|
||||
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
|
||||
/**
|
||||
* 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(' ');
|
||||
return new Array(length + 1).join(' ');
|
||||
}
|
||||
|
||||
function padLeft(str, length) {
|
||||
return padding(length) + str;
|
||||
return padding(length) + str;
|
||||
}
|
||||
|
||||
function padRight(str, length) {
|
||||
return str + padding(length);
|
||||
return str + padding(length);
|
||||
}
|
||||
|
||||
function findMaxLength(arr) {
|
||||
var max = 0;
|
||||
var max = 0;
|
||||
|
||||
arr.forEach(function(item) {
|
||||
if (item.length > max) {
|
||||
max = item.length;
|
||||
}
|
||||
});
|
||||
arr.forEach(function(item) {
|
||||
if (item.length > max) {
|
||||
max = item.length;
|
||||
}
|
||||
});
|
||||
|
||||
return max;
|
||||
return max;
|
||||
}
|
||||
|
||||
function concatWithMaxLength(items, maxLength) {
|
||||
var result = '';
|
||||
// to prevent endless loops, always use the first item, regardless of length
|
||||
result += items.shift();
|
||||
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();
|
||||
}
|
||||
while ( items.length && (result.length + items[0].length < maxLength) ) {
|
||||
result += ' ' + items.shift();
|
||||
}
|
||||
|
||||
return result;
|
||||
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 MARGIN_LENGTH = 4;
|
||||
var results = [];
|
||||
|
||||
var maxLength = process.stdout.columns;
|
||||
var maxNameLength = findMaxLength(options.names);
|
||||
var maxDescriptionLength = findMaxLength(options.descriptions);
|
||||
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;
|
||||
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);
|
||||
// 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;
|
||||
}
|
||||
// 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);
|
||||
});
|
||||
results.push(result);
|
||||
});
|
||||
|
||||
return results;
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
Generate a summary of all the options with corresponding help text.
|
||||
@returns {string}
|
||||
* Generate a summary of all the options with corresponding help text.
|
||||
* @returns {string}
|
||||
*/
|
||||
ArgParser.prototype.help = function() {
|
||||
var options = {
|
||||
names: [],
|
||||
descriptions: []
|
||||
};
|
||||
var options = {
|
||||
names: [],
|
||||
descriptions: []
|
||||
};
|
||||
|
||||
this._options.forEach(function(option) {
|
||||
var name = '';
|
||||
this._options.forEach(function(option) {
|
||||
var name = '';
|
||||
|
||||
if (option.shortName) {
|
||||
name += '-' + option.shortName + (option.longName ? ', ' : '');
|
||||
}
|
||||
// don't show ignored options
|
||||
if (option.ignore) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (option.longName) {
|
||||
name += '--' + option.longName;
|
||||
}
|
||||
if (option.shortName) {
|
||||
name += '-' + option.shortName + (option.longName ? ', ' : '');
|
||||
}
|
||||
|
||||
if (option.hasValue) {
|
||||
name += ' <value>';
|
||||
}
|
||||
if (option.longName) {
|
||||
name += '--' + option.longName;
|
||||
}
|
||||
|
||||
options.names.push(name);
|
||||
options.descriptions.push(option.helpText);
|
||||
});
|
||||
if (option.hasValue) {
|
||||
name += ' <value>';
|
||||
}
|
||||
|
||||
return 'Options:\n' + formatHelpInfo(options).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;
|
||||
|
||||
@ -1,67 +1,76 @@
|
||||
/**
|
||||
@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;
|
||||
}
|
||||
|
||||
// check for strings that we need to cast to other types
|
||||
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;
|
||||
}
|
||||
|
||||
argParser.addOption('t', 'template', true, 'The path to the template to use. Default: path/to/jsdoc/templates/default');
|
||||
@ -71,58 +80,59 @@ 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: ./out/');
|
||||
argParser.addOption('p', 'private', false, 'Display symbols marked with the @private tag. Default: false');
|
||||
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.');
|
||||
argParser.addOption('X', 'explain', false, 'Dump all found doclet internals to console and quit.');
|
||||
argParser.addOption('q', 'query', true, 'A query string to parse and store in env.opts.query. Example: foo=bar&baz=true', false, parseQuery);
|
||||
argParser.addOption('u', 'tutorials', true, 'Directory in which JSDoc should search for tutorials.');
|
||||
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.
|
||||
*/
|
||||
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 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];
|
||||
}
|
||||
};
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var error = require('jsdoc/util/error');
|
||||
var logger = require('jsdoc/util/logger');
|
||||
var path = require('jsdoc/path');
|
||||
|
||||
exports.installPlugins = function(plugins, parser) {
|
||||
@ -19,8 +19,7 @@ exports.installPlugins = function(plugins, parser) {
|
||||
pluginPath = path.getResourcePath(path.dirname(plugins[i]), path.basename(plugins[i]));
|
||||
|
||||
if (!pluginPath) {
|
||||
error.handle(new Error('Unable to find the plugin "' + plugins[i] + '"'));
|
||||
continue;
|
||||
logger.error('Unable to find the plugin "%s"', plugins[i]);
|
||||
}
|
||||
|
||||
plugin = require(pluginPath);
|
||||
@ -41,8 +40,8 @@ exports.installPlugins = function(plugins, parser) {
|
||||
//...add a Rhino node visitor (deprecated in JSDoc 3.3)
|
||||
if (plugin.nodeVisitor) {
|
||||
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]);
|
||||
}
|
||||
else {
|
||||
parser.addNodeVisitor(plugin.nodeVisitor);
|
||||
|
||||
@ -143,6 +143,7 @@ var nodeToString = exports.nodeToString = function(node) {
|
||||
str = node.operator + str;
|
||||
}
|
||||
else {
|
||||
// this shouldn't happen
|
||||
throw new Error('Found a UnaryExpression with a postfix operator: %j', node);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -18,7 +18,7 @@ function getNewDoclet(comment, e) {
|
||||
catch (error) {
|
||||
err = new Error( util.format('cannot create a doclet for the comment "%s": %s',
|
||||
comment.replace(/[\r\n]/g, ''), error.message) );
|
||||
require('jsdoc/util/error').handle(err);
|
||||
require('jsdoc/util/logger').error(err);
|
||||
doclet = new Doclet('', e);
|
||||
}
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ var jsdoc = {
|
||||
syntax: require('jsdoc/src/syntax')
|
||||
}
|
||||
};
|
||||
var logger = require('jsdoc/util/logger');
|
||||
var util = require('util');
|
||||
|
||||
var hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
@ -63,7 +64,7 @@ exports.createParser = function(type) {
|
||||
return new ( require(modulePath) ).Parser();
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error('Unable to create the parser type "' + type + '": ' + e);
|
||||
logger.fatal('Unable to create the parser type "' + type + '": ' + e);
|
||||
}
|
||||
};
|
||||
|
||||
@ -142,6 +143,7 @@ Parser.prototype.parse = function(sourceFiles, encoding) {
|
||||
}
|
||||
|
||||
e.sourcefiles = sourceFiles;
|
||||
logger.debug('Parsing source files: %j', sourceFiles);
|
||||
|
||||
this.emit('parseBegin', e);
|
||||
|
||||
@ -158,10 +160,7 @@ Parser.prototype.parse = function(sourceFiles, encoding) {
|
||||
sourceCode = require('jsdoc/fs').readFileSync(filename, encoding);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,6 +174,7 @@ Parser.prototype.parse = function(sourceFiles, encoding) {
|
||||
sourcefiles: parsedFiles,
|
||||
doclets: this._resultBuffer
|
||||
});
|
||||
logger.debug('Finished parsing source files.');
|
||||
|
||||
return this._resultBuffer;
|
||||
};
|
||||
@ -235,6 +235,7 @@ Parser.prototype._parseSourceCode = function(sourceCode, sourceName) {
|
||||
};
|
||||
|
||||
this.emit('fileBegin', e);
|
||||
logger.printInfo('Parsing %s ...', sourceName);
|
||||
|
||||
if (!e.defaultPrevented) {
|
||||
e = {
|
||||
@ -252,6 +253,7 @@ Parser.prototype._parseSourceCode = function(sourceCode, sourceName) {
|
||||
}
|
||||
|
||||
this.emit('fileComplete', e);
|
||||
logger.info('complete.');
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
'use strict';
|
||||
|
||||
var fs = require('jsdoc/fs');
|
||||
var logger = require('jsdoc/util/logger');
|
||||
var path = require('jsdoc/path');
|
||||
|
||||
/**
|
||||
@ -25,6 +26,7 @@ exports.Scanner.prototype = Object.create( require('events').EventEmitter.protot
|
||||
@fires sourceFileFound
|
||||
*/
|
||||
exports.Scanner.prototype.scan = function(searchPaths, depth, filter) {
|
||||
var currentFile;
|
||||
var isFile;
|
||||
|
||||
var filePaths = [];
|
||||
@ -38,13 +40,14 @@ exports.Scanner.prototype.scan = function(searchPaths, depth, filter) {
|
||||
var filepath = path.resolve( pwd, decodeURIComponent($) );
|
||||
|
||||
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);
|
||||
}
|
||||
else {
|
||||
|
||||
@ -19,8 +19,12 @@ var jsdoc = {
|
||||
dictionary: require('jsdoc/tag/dictionary'),
|
||||
validator: require('jsdoc/tag/validator'),
|
||||
type: require('jsdoc/tag/type')
|
||||
},
|
||||
util: {
|
||||
logger: require('jsdoc/util/logger')
|
||||
}
|
||||
};
|
||||
var path = require('jsdoc/path');
|
||||
|
||||
function trim(text, opts) {
|
||||
var indentMatcher;
|
||||
@ -117,8 +121,19 @@ var Tag = exports.Tag = function(tagTitle, tagBody, meta) {
|
||||
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);
|
||||
};
|
||||
|
||||
@ -239,8 +239,8 @@ function parseTypeExpression(tagInfo) {
|
||||
}
|
||||
catch (e) {
|
||||
// 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) );
|
||||
}
|
||||
|
||||
if (parsedType) {
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
|
||||
var dictionary = require('jsdoc/tag/dictionary');
|
||||
var format = require('util').format;
|
||||
var logger = require('jsdoc/util/logger');
|
||||
|
||||
function buildMessage(tagName, meta, desc) {
|
||||
var result = format('The @%s tag %s. File: %s, line: %s', tagName, desc, meta.filename,
|
||||
@ -20,43 +21,21 @@ function buildMessage(tagName, meta, desc) {
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Validate the given tag.
|
||||
*/
|
||||
exports.validate = function(tag, tagDef, meta) {
|
||||
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') );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (tagDef.mustNotHaveValue) {
|
||||
require('jsdoc/util/error').handle( new TagValueNotPermittedError(tag.title, meta) );
|
||||
logger.error( buildMessage(tag.title, meta, 'does not permit a value') );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
var tutorial = require('jsdoc/tutorial'),
|
||||
fs = require('jsdoc/fs'),
|
||||
error = require('jsdoc/util/error'),
|
||||
logger = require('jsdoc/util/logger'),
|
||||
path = require('path'),
|
||||
hasOwnProp = Object.prototype.hasOwnProperty,
|
||||
conf = {},
|
||||
@ -61,7 +61,7 @@ function addTutorialConf(name, meta) {
|
||||
}
|
||||
// check if the tutorial has already been defined...
|
||||
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 {
|
||||
conf[name] = meta;
|
||||
}
|
||||
@ -79,7 +79,7 @@ function addTutorialConf(name, meta) {
|
||||
*/
|
||||
exports.addTutorial = function(current) {
|
||||
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 {
|
||||
tutorials[current.name] = current;
|
||||
|
||||
@ -179,7 +179,7 @@ exports.resolve = function() {
|
||||
if (item.children) {
|
||||
item.children.forEach(function(child) {
|
||||
if (!hasOwnProp.call(tutorials, child)) {
|
||||
error.handle( new Error("Missing child tutorial: " + child) );
|
||||
logger.error('Missing child tutorial: %s', child);
|
||||
}
|
||||
else {
|
||||
tutorials[child].setParent(current);
|
||||
|
||||
@ -1,33 +1,35 @@
|
||||
/*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
|
||||
*/
|
||||
'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);
|
||||
};
|
||||
|
||||
232
lib/jsdoc/util/logger.js
Normal file
232
lib/jsdoc/util/logger.js
Normal file
@ -0,0 +1,232 @@
|
||||
/**
|
||||
* Logging tools for JSDoc.
|
||||
*
|
||||
* Log messages are printed to the console based on the current logging level. By default, messages
|
||||
* at level `{@link module:jsdoc/util/logger.LEVELS.ERROR}` or above are logged; all other messages
|
||||
* are ignored.
|
||||
*
|
||||
* In addition, the module object emits an event whenever a logger method is called, regardless of
|
||||
* the current logging level. The event's name is the string `logger:` followed by the logger's name
|
||||
* (for example, `logger:error`). The event handler receives an array of arguments that were passed
|
||||
* to the logger method.
|
||||
*
|
||||
* Each logger method accepts a `message` parameter that may contain zero or more placeholders. Each
|
||||
* placeholder is replaced by the corresponding argument following the message. If the placeholder
|
||||
* does not have a corresponding argument, the placeholder is not replaced.
|
||||
*
|
||||
* The following placeholders are supported:
|
||||
*
|
||||
* + `%s`: String.
|
||||
* + `%d`: Number.
|
||||
* + `%j`: JSON.
|
||||
*
|
||||
* @module jsdoc/util/logger
|
||||
* @extends module:events.EventEmitter
|
||||
* @example
|
||||
* var logger = require('jsdoc/util/logger');
|
||||
*
|
||||
* var data = {
|
||||
* foo: 'bar'
|
||||
* };
|
||||
* var name = 'baz';
|
||||
*
|
||||
* logger.warn('%j %s', data, name); // prints '{"foo":"bar"} baz'
|
||||
* @see http://nodejs.org/api/util.html#util_util_format_format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var runtime = require('jsdoc/util/runtime');
|
||||
var util = require('util');
|
||||
|
||||
function Logger() {}
|
||||
util.inherits(Logger, require('events').EventEmitter);
|
||||
|
||||
var logger = module.exports = new Logger();
|
||||
|
||||
/**
|
||||
* Logging levels for the JSDoc logger. The default logging level is
|
||||
* {@link module:jsdoc/util/logger.LEVELS.ERROR}.
|
||||
*
|
||||
* @enum
|
||||
* @type {number}
|
||||
*/
|
||||
var LEVELS = logger.LEVELS = {
|
||||
/** Do not log any messages. */
|
||||
SILENT: 0,
|
||||
/** Log fatal errors that prevent JSDoc from running. */
|
||||
FATAL: 10,
|
||||
/** Log all errors, including errors from which JSDoc can recover. */
|
||||
ERROR: 20,
|
||||
/**
|
||||
* Log the following messages:
|
||||
*
|
||||
* + Warnings
|
||||
* + Errors
|
||||
*/
|
||||
WARN: 30,
|
||||
/**
|
||||
* Log the following messages:
|
||||
*
|
||||
* + Informational messages
|
||||
* + Warnings
|
||||
* + Errors
|
||||
*/
|
||||
INFO: 40,
|
||||
/**
|
||||
* Log the following messages:
|
||||
*
|
||||
* + Debugging messages
|
||||
* + Informational messages
|
||||
* + Warnings
|
||||
* + Errors
|
||||
*/
|
||||
DEBUG: 50,
|
||||
/** Log all messages. */
|
||||
VERBOSE: 1000
|
||||
};
|
||||
|
||||
var DEFAULT_LEVEL = LEVELS.ERROR;
|
||||
var logLevel = DEFAULT_LEVEL;
|
||||
|
||||
var PREFIXES = {
|
||||
DEBUG: 'DEBUG: ',
|
||||
ERROR: 'ERROR: ',
|
||||
FATAL: 'FATAL: ',
|
||||
WARN: 'WARNING: '
|
||||
};
|
||||
|
||||
// Add a prefix to a log message if necessary.
|
||||
function addPrefix(args, prefix) {
|
||||
var updatedArgs;
|
||||
|
||||
if (prefix && typeof args[0] === 'string') {
|
||||
updatedArgs = args.slice(0);
|
||||
updatedArgs[0] = prefix + updatedArgs[0];
|
||||
}
|
||||
|
||||
return updatedArgs || args;
|
||||
}
|
||||
|
||||
// TODO: document events
|
||||
function wrapLogFunction(name, func) {
|
||||
var eventName = 'logger:' + name;
|
||||
var upperCaseName = name.toUpperCase();
|
||||
var level = LEVELS[upperCaseName];
|
||||
var prefix = PREFIXES[upperCaseName];
|
||||
|
||||
return function() {
|
||||
var loggerArgs;
|
||||
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
|
||||
if (logLevel >= level) {
|
||||
loggerArgs = addPrefix(args, prefix);
|
||||
func.apply(null, loggerArgs);
|
||||
}
|
||||
|
||||
args.unshift(eventName);
|
||||
logger.emit.apply(logger, args);
|
||||
};
|
||||
}
|
||||
|
||||
// Print a message to STDOUT without a terminating newline.
|
||||
function printToStdout() {
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
|
||||
util.print( util.format.apply(util, args) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a message at log level {@link module:jsdoc/util/logger.LEVELS.DEBUG}.
|
||||
*
|
||||
* @param {string} message - The message to log.
|
||||
* @param {...*=} values - The values that will replace the message's placeholders.
|
||||
*/
|
||||
logger.debug = wrapLogFunction('debug', console.info);
|
||||
/**
|
||||
* Print a string at log level {@link module:jsdoc/util/logger.LEVELS.DEBUG}. The string is not
|
||||
* terminated by a newline.
|
||||
*
|
||||
* @param {string} message - The message to log.
|
||||
* @param {...*=} values - The values that will replace the message's placeholders.
|
||||
*/
|
||||
logger.printDebug = wrapLogFunction('debug', printToStdout);
|
||||
/**
|
||||
* Log a message at log level {@link module:jsdoc/util/logger.LEVELS.ERROR}.
|
||||
*
|
||||
* @name module:jsdoc/util/logger.error
|
||||
* @function
|
||||
* @param {string} message - The message to log.
|
||||
* @param {...*=} values - The values that will replace the message's placeholders.
|
||||
*/
|
||||
logger.error = wrapLogFunction('error', console.error);
|
||||
/**
|
||||
* Log a message at log level {@link module:jsdoc/util/logger.LEVELS.FATAL}.
|
||||
*
|
||||
* @name module:jsdoc/util/logger.error
|
||||
* @function
|
||||
* @param {string} message - The message to log.
|
||||
* @param {...*=} values - The values that will replace the message's placeholders.
|
||||
*/
|
||||
logger.fatal = wrapLogFunction('fatal', console.error);
|
||||
/**
|
||||
* Log a message at log level {@link module:jsdoc/util/logger.LEVELS.INFO}.
|
||||
*
|
||||
* @name module:jsdoc/util/logger.info
|
||||
* @function
|
||||
* @param {string} message - The message to log.
|
||||
* @param {...*=} values - The values that will replace the message's placeholders.
|
||||
*/
|
||||
logger.info = wrapLogFunction('info', console.info);
|
||||
/**
|
||||
* Print a string at log level {@link module:jsdoc/util/logger.LEVELS.INFO}. The string is not
|
||||
* terminated by a newline.
|
||||
*
|
||||
* @param {string} message - The message to log.
|
||||
* @param {...*=} values - The values that will replace the message's placeholders.
|
||||
*/
|
||||
logger.printInfo = wrapLogFunction('info', printToStdout);
|
||||
/**
|
||||
* Log a message at log level {@link module:jsdoc/util/logger.LEVELS.VERBOSE}.
|
||||
*
|
||||
* @name module:jsdoc/util/logger.verbose
|
||||
* @function
|
||||
* @param {string} message - The message to log.
|
||||
* @param {...*=} values - The values that will replace the message's placeholders.
|
||||
*/
|
||||
logger.verbose = wrapLogFunction('verbose', console.info);
|
||||
/**
|
||||
* Print a string at log level {@link module:jsdoc/util/logger.LEVELS.VERBOSE}. The string is not
|
||||
* terminated by a newline.
|
||||
*
|
||||
* @param {string} message - The message to log.
|
||||
* @param {...*=} values - The values that will replace the message's placeholders.
|
||||
*/
|
||||
logger.printVerbose = wrapLogFunction('verbose', printToStdout);
|
||||
/**
|
||||
* Log a message at log level {@link module:jsdoc/util/logger.LEVELS.WARN}.
|
||||
*
|
||||
* @name module:jsdoc/util/logger.warn
|
||||
* @function
|
||||
* @param {string} message - The message to log.
|
||||
* @param {...*=} values - The values that will replace the message's placeholders.
|
||||
*/
|
||||
logger.warn = wrapLogFunction('warn', console.warn);
|
||||
|
||||
/**
|
||||
* Set the log level.
|
||||
*
|
||||
* @param {module:jsdoc/util/logger.LEVELS} level - The log level to use.
|
||||
*/
|
||||
logger.setLevel = function setLevel(level) {
|
||||
logLevel = (level !== undefined) ? level : DEFAULT_LEVEL;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current log level.
|
||||
*
|
||||
* @return {module:jsdoc/util/logger.LEVELS} The current log level.
|
||||
*/
|
||||
logger.getLevel = function getLevel() {
|
||||
return logLevel;
|
||||
};
|
||||
@ -73,9 +73,9 @@ function unescapeUrls(source) {
|
||||
* @param {Object} [conf] Configuration for the selected parser, if any.
|
||||
* @returns {Function} A function that accepts Markdown source, feeds it to the selected parser, and
|
||||
* returns the resulting HTML.
|
||||
* @throws {Error} If the name does not correspond to a known parser.
|
||||
*/
|
||||
function getParseFunction(parserName, conf) {
|
||||
var logger = require('jsdoc/util/logger');
|
||||
var marked = require('marked');
|
||||
var parserFunction;
|
||||
|
||||
@ -99,7 +99,8 @@ function getParseFunction(parserName, conf) {
|
||||
return parserFunction;
|
||||
}
|
||||
else {
|
||||
throw new Error("unknown Markdown parser: '" + parserName + "'");
|
||||
logger.error('Unrecognized Markdown parser "%s". Markdown support is disabled.',
|
||||
parserName);
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,9 +109,9 @@ function getParseFunction(parserName, conf) {
|
||||
* `env.conf.markdown` property. The parsing function accepts a single parameter containing Markdown
|
||||
* source. The function uses the parser specified in `conf.json` to transform the Markdown source to
|
||||
* HTML, then returns the HTML as a string.
|
||||
* @returns {Function} A function that accepts Markdown source, feeds it to the selected parser, and
|
||||
*
|
||||
* @returns {function} A function that accepts Markdown source, feeds it to the selected parser, and
|
||||
* returns the resulting HTML.
|
||||
* @throws {Error} If the value of `env.conf.markdown.parser` does not correspond to a known parser.
|
||||
*/
|
||||
exports.getParser = function() {
|
||||
var conf = env.conf.markdown;
|
||||
|
||||
@ -107,7 +107,7 @@ exports.initialize = function(args) {
|
||||
initializeNode(args);
|
||||
break;
|
||||
default:
|
||||
throw new Error('Unable to initialize the JavaScript runtime!');
|
||||
throw new Error('Cannot initialize the unknown JavaScript runtime "' + runtime + '"!');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -124,7 +124,7 @@ function parseType(longname) {
|
||||
}
|
||||
catch (e) {
|
||||
err = new Error('unable to parse ' + longname + ': ' + e.message);
|
||||
require('jsdoc/util/error').handle(err);
|
||||
require('jsdoc/util/logger').error(err);
|
||||
return longname;
|
||||
}
|
||||
}
|
||||
@ -285,7 +285,7 @@ var tutorialToUrl = exports.tutorialToUrl = function(tutorial) {
|
||||
var node = tutorials.getByName(tutorial);
|
||||
// no such tutorial
|
||||
if (!node) {
|
||||
require('jsdoc/util/error').handle( new Error('No such tutorial: '+tutorial) );
|
||||
require('jsdoc/util/logger').error( new Error('No such tutorial: ' + tutorial) );
|
||||
return;
|
||||
}
|
||||
|
||||
@ -317,7 +317,7 @@ var tutorialToUrl = exports.tutorialToUrl = function(tutorial) {
|
||||
*/
|
||||
var toTutorial = exports.toTutorial = function(tutorial, content, missingOpts) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jsdoc",
|
||||
"version": "3.3.0-dev",
|
||||
"revision": "1386539957698",
|
||||
"revision": "1387841089759",
|
||||
"description": "An API documentation generator for JavaScript.",
|
||||
"keywords": [ "documentation", "javascript" ],
|
||||
"licenses": [
|
||||
|
||||
@ -1,389 +0,0 @@
|
||||
Creating and Enabling a Plugin
|
||||
----
|
||||
|
||||
There are two steps required to create and enable a new JSDoc plugin:
|
||||
|
||||
1. Create a JavaScript module to contain your plugin code.
|
||||
2. Include that module in the "plugins" array of `conf.json`. You can specify
|
||||
an absolute or relative path. If you use a relative path, JSDoc searches for
|
||||
the plugin in the current working directory and the JSDoc directory, in that
|
||||
order.
|
||||
|
||||
For example, if your plugin source code was saved in the "plugins/shout.js"
|
||||
file in the current working directory, you would include it by adding a
|
||||
reference to it in conf.json like so:
|
||||
|
||||
...
|
||||
"plugins": [
|
||||
"plugins/shout"
|
||||
]
|
||||
...
|
||||
|
||||
Authoring JSDoc 3 Plugins
|
||||
----
|
||||
|
||||
The plugin system for JSDoc 3 is pretty powerful and provides plugin authors
|
||||
multiple methods, from high-level to low-level, of affecting document generation:
|
||||
|
||||
- Defining event handlers
|
||||
- Defining tags
|
||||
- Defining a parse tree node processor
|
||||
|
||||
### Event Handlers
|
||||
|
||||
At the highest level, a plugin may register handlers for specific named-events
|
||||
that occur in the documentation generation process. JSDoc will pass the handler
|
||||
an event object containing pertinent information. Your plugin module should
|
||||
export a _handlers_ object that contains your handler, like so:
|
||||
|
||||
exports.handlers = {
|
||||
newDoclet: function(e) {
|
||||
//Do something when we see a new doclet
|
||||
}
|
||||
}
|
||||
|
||||
#### Event: fileBegin
|
||||
|
||||
This is triggered when the parser has started on a new file. You might use this
|
||||
to do any per-file initialization your plugin needs to do.
|
||||
|
||||
The event object will contain the following properties:
|
||||
|
||||
- filename: the name of the file
|
||||
|
||||
#### Event: beforeParse
|
||||
|
||||
This is triggered before parsing has begun. You can use this method to modify
|
||||
the source code that will be parsed. For instance, you might add some virtual
|
||||
doclets so they get added to the documentation.
|
||||
|
||||
The event object will contain the following properties:
|
||||
|
||||
- filename: the name of the file
|
||||
- source: the contents of the file
|
||||
|
||||
Below is an example that adds a virtual doclet for a function to the source so
|
||||
that it will get parsed and added to the documentation. This might be done to
|
||||
document methods that will be present for end-user use, but might not be in the
|
||||
source code being documented, like methods provided by a third-party superclass:
|
||||
|
||||
exports.handlers = {
|
||||
beforeParse: function(e) {
|
||||
var extraDoc = ["",
|
||||
"/**",
|
||||
"Here's a description of this function",
|
||||
"@name superFunc",
|
||||
"@memberof ui.mywidget",
|
||||
"@function",
|
||||
"*/", ""];
|
||||
e.source += extraDoc.join("\n");
|
||||
}
|
||||
}
|
||||
|
||||
#### Event: jsdocCommentFound
|
||||
|
||||
This is fired whenever a jsdoc comment is found. It may or may not be associated
|
||||
with any code. You might use this to modify the contents of a comment before it
|
||||
is processed.
|
||||
|
||||
The event object will contain the following properties:
|
||||
|
||||
- filename: the name of the file
|
||||
- comment: the text of the comment
|
||||
- lineno: the line number the comment was found on
|
||||
|
||||
#### Event: symbolFound
|
||||
|
||||
This is fired when the parser comes across a symbol in the code it thinks is
|
||||
important. This usually means things that one might want to document --
|
||||
variables, functions, object literals, object property definitions,
|
||||
assignments, etc., but the symbols the parser finds can be modified by a plugin
|
||||
(see "Node Visitors" below).
|
||||
|
||||
The event object will contain the following properties:
|
||||
|
||||
- filename: the name of the file
|
||||
- comment: the comment associated with the symbol, if any
|
||||
- id: the unique id of the symbol
|
||||
- lineno: the line number the symbols was found on
|
||||
- range: an array containing the first and last characters of the code
|
||||
associated with the symbol
|
||||
- astnode: the node of the parse tree
|
||||
- code: information about the code. This usually contains "name", "type", and
|
||||
"node" properties and might also have "value", "paramnames", or "funcscope"
|
||||
properties depending on the symbol.
|
||||
|
||||
#### Event: newDoclet
|
||||
|
||||
This is the highest level event and is fired when a new doclet has been created.
|
||||
This means that a jsdoc or a symbol has been processed and the actual doclet
|
||||
that will be passed to the template has been created.
|
||||
|
||||
The event object will contain the following properties:
|
||||
|
||||
- doclet: the new doclet that was created
|
||||
|
||||
The properties of the doclet can vary depending on the comment or symbol used to
|
||||
create it. Additionally, tag definitions (See "Tag Definitions" below) can
|
||||
modify the doclet. Some common properties you're likely to see include:
|
||||
|
||||
- comment: the text of the comment (may be empty if symbol is undocumented)
|
||||
- meta: some information about the doclet, like filename, line number, etc.
|
||||
- description
|
||||
- kind
|
||||
- name
|
||||
- longname: the fully qualified name, including memberof info
|
||||
- memberof: the function/class/namespace that this is a member of
|
||||
- scope: (global|static|instance|inner)
|
||||
- undocumented: true if the symbol didn't have a jsdoc comment
|
||||
- defaultvalue: the specified default value for a property/variable
|
||||
- type: the specified type of parameter/property/function return (e.g. Boolean)
|
||||
- params: an object containing the list of parameters to a function
|
||||
- tags: an object containing the set of tags not handled by the parser (note:
|
||||
this is only available if ```allowUnknownTags``` is set to true in the conf.json
|
||||
file for JSDoc3)
|
||||
|
||||
Below is an example of a newDoclet handler that shouts the descriptions:
|
||||
|
||||
exports.handlers = {
|
||||
newDoclet: function(e) {
|
||||
// e.doclet will refer to the newly created doclet
|
||||
// you can read and modify properties of that doclet if you wish
|
||||
if (typeof e.doclet.description === 'string') {
|
||||
e.doclet.description = e.doclet.description.toUpperCase();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#### Event: fileComplete
|
||||
|
||||
This is fired when the parser is done with a file. You might use this to
|
||||
perform some cleanup for your plugin.
|
||||
|
||||
The event object will contain the following properties:
|
||||
|
||||
- filename: the name of the file
|
||||
- source: the contents of the file
|
||||
|
||||
### Tag Definitions
|
||||
|
||||
Adding tags to the tag dictionary is a mid-level way to affect documentation
|
||||
generation. Before a newDoclet event is triggered, jsdoc comment blocks are
|
||||
parsed to determine the description and any jsdoc tags that may be present. When
|
||||
a tag is found, if it has been defined in the tag dictionary, it is given a
|
||||
chance to modify the doclet.
|
||||
|
||||
Plugins can define tags by exporting a _defineTags_ function. That function will
|
||||
be passed a dictionary that can be used to define tags, like so:
|
||||
|
||||
exports.defineTags = function(dictionary) {
|
||||
//define tags here
|
||||
}
|
||||
|
||||
#### The Dictionary
|
||||
|
||||
The dictionary provides the following methods:
|
||||
|
||||
1. defineTag(title, opts)
|
||||
Used to define tags.
|
||||
The first parameter is the name of the tag (e.g. "param" or "overview"). the
|
||||
second is an object containing options for the tag. The options can be the
|
||||
following:
|
||||
- mustHaveValue (Boolean): whether or not the tag must have a value
|
||||
(e.g "@name TheName")
|
||||
- mustNotHaveValue (Boolean): whether or not the tag must not have a value
|
||||
- canHaveType (Boolean): Whether or not the tag can have a type
|
||||
(e.g. "@param **{String}** name the description of name")
|
||||
- canHaveName (Boolean): Whether or not the tag can have a name
|
||||
(e.g. "@param {String} **name** the description of name")
|
||||
- isNamespace (Boolean): Whether or not the tag marks a doclet as representing
|
||||
a namespace. The "@module" tag, for instance, sets this to true.
|
||||
- onTagged (Function): A callback function executed when the tag is found. The
|
||||
function is passed two parameters: the doclet and the tag. Here's an example:
|
||||
|
||||
dictionary.defineTag('instance', {
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.scope = "instance";
|
||||
}
|
||||
});
|
||||
The defineTag method returns a Tag. The Tag object has a method "synonym"
|
||||
that can be used to declare synonyms to the tag. For example:
|
||||
|
||||
dictionary.defineTag('exception', {
|
||||
<options for exception tag>
|
||||
})
|
||||
.synonym('throws');
|
||||
2. lookUp(title)
|
||||
Used to lookup a tag. Returns either the tag or false if it's not defined
|
||||
3. isNamespace(kind)
|
||||
Used to determine if a particular doclet type represents a namespace
|
||||
4. normalise(title)
|
||||
Used to find the canonical name of a tag. The name passed in might be that
|
||||
name or a synonym
|
||||
|
||||
### Node Visitors
|
||||
|
||||
At the lowest level, plugin authors can process each node in the parse tree by
|
||||
defining a node visitor that will visit each node, creating an opportunity to
|
||||
do things like modify comments and trigger parser events for any arbitrary piece
|
||||
of code.
|
||||
|
||||
Plugins can define a node visitor by exporting a ```nodeVisitor``` object that
|
||||
contains a ```visitNode``` function, like so:
|
||||
|
||||
exports.nodeVisitor = {
|
||||
visitNode: function(node, e, parser, currentSourceName) {
|
||||
//do all sorts of crazy things here
|
||||
}
|
||||
}
|
||||
|
||||
The function is called on each node with the following parameters:
|
||||
|
||||
- node: the node of the parse tree
|
||||
- e: the event. If the node is one that the parser handles, this will already
|
||||
be populated with the same things described in the _symbolFound_ event above.
|
||||
Otherwise, it will be an empty object on which to set various properties.
|
||||
- parser: the parser
|
||||
- currentSourceName: the name of the file being parsed
|
||||
|
||||
#### Making things happen
|
||||
|
||||
The primary reasons to implement a node visitor are to be able to document
|
||||
things that aren't normally documented (like function calls that create classes)
|
||||
or to auto generate documentation for code that isn't documented. For instance,
|
||||
a plugin might look for calls to a "_trigger" method since it knows that means
|
||||
an event is fired and then generate documentation for the event.
|
||||
|
||||
To make things happen, the ```visitNode``` function should modify properties
|
||||
of the event parameter. In general the goal is to construct a comment and then
|
||||
get an event to fire. After the parser lets all of the node visitors have a
|
||||
look at the node, it looks to see if the event object has a ```comment```
|
||||
property and an ```event``` property. If it has both, the event named in the event
|
||||
property is fired. The event is usually "symbolFound" or "jsdocCommentFound",
|
||||
but theoretically, a plugin could define its own events and handle them.
|
||||
|
||||
#### Example
|
||||
|
||||
Below is an example of what a plugin for documenting jQuery UI widgets might do.
|
||||
jQuery UI uses a factory function call to create widget classes. The plugin
|
||||
looks for that function call and creates a symbol with documentation. It also
|
||||
looks for any "this._trigger" function calls and automatically creates
|
||||
documentation for the events that are triggered:
|
||||
|
||||
exports.nodeVisitor = {
|
||||
visitNode: function(node, e, parser, currentSourceName) {
|
||||
if (node.type === Token.OBJECTLIT && node.parent && node.parent.type === Token.CALL && isInWidgetFactory(node, 1)) {
|
||||
var widgetName = node.parent.arguments.get(0).toSource();
|
||||
e.id = 'astnode' + node.hashCode(); // the id of the object literal node
|
||||
e.comment = String(node.parent.jsDoc||'');
|
||||
e.lineno = node.parent.getLineno();
|
||||
e.filename = currentSourceName;
|
||||
e.astnode = node;
|
||||
e.code = {
|
||||
name: "" + widgetName.substring(1, widgetName.length() - 1),
|
||||
type: "class",
|
||||
node: node
|
||||
};
|
||||
e.event = "symbolFound";
|
||||
e.finishers = [parser.addDocletRef];
|
||||
|
||||
addCommentTag(e, "param", "{Object=} options A set of configuration options");
|
||||
}
|
||||
else if(isTriggerCall(node)) {
|
||||
var nameNode = node.arguments.get(0);
|
||||
eventName = String((nameNode.type == Token.STRING) ? nameNode.value : nameNode.toSource()),
|
||||
func = {},
|
||||
comment = "@event\n",
|
||||
eventKey = "";
|
||||
|
||||
if (node.enclosingFunction) {
|
||||
func.id = 'astnode'+node.enclosingFunction.hashCode();
|
||||
func.doclet = parser.refs[func.id];
|
||||
}
|
||||
if(func.doclet) {
|
||||
func.doclet.addTag("fires", eventName);
|
||||
if (func.doclet.memberof) {
|
||||
eventKey = func.doclet.memberof + "#event:" + eventName;
|
||||
comment += "@name " + func.doclet.memberof + "#" + eventName;
|
||||
}
|
||||
}
|
||||
e.comment = comment;
|
||||
e.lineno = node.getLineno();
|
||||
e.filename = currentSourceName;
|
||||
e.event = "jsdocCommentFound";
|
||||
}
|
||||
}
|
||||
};
|
||||
function isTriggerCall(node) {
|
||||
if(node.type != Token.CALL) { return false; }
|
||||
var target = node.getTarget(),
|
||||
left = target && target.left && String(target.left.toSource()),
|
||||
right = target && target.right && String(target.right.toSource());
|
||||
return (left === "this" && right === "_trigger");
|
||||
}
|
||||
|
||||
function isInWidgetFactory(node, depth) {
|
||||
var parent = node.parent,
|
||||
d = 0;
|
||||
while(parent && (!depth || d < depth)) {
|
||||
if (parent.type === Token.CALL) {
|
||||
var target = parent.getTarget(),
|
||||
left = target && target.left && String(target.left.toSource()),
|
||||
right = target && target.right && String(target.right.toSource());
|
||||
return ((left === "$" || left === "jQuery") && right === "widget");
|
||||
} else {
|
||||
parent = parent.parent;
|
||||
d++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
You'll notice a "finishers" property set. The finishers property should contain
|
||||
an array of functions to be called after the event is fired and all the handlers
|
||||
have processed it. The parser provides an ```addDocletRef``` function that adds the
|
||||
doclet to the map (keyed off of the id property) of doclets it knows about.
|
||||
|
||||
Lastly, the visitors are executed in the order the plugins are listed in the
|
||||
conf.json file. A plugin can stop later plugins from visiting a node by
|
||||
setting a ```stopPropagation``` property on the event object (e.stopPropagation = true).
|
||||
A plugin can stop the event from firing setting a ```preventDefault``` property.
|
||||
|
||||
### Throwing Errors
|
||||
|
||||
If you wish your plugin to throw an error, do it using the `handle` function in
|
||||
the `jsdoc/util/error` module:
|
||||
|
||||
require('jsdoc/util/error').handle( new Error('I do not like green eggs and ham!') );
|
||||
|
||||
By default, this will throw the error, halting the execution of JSDoc. However,
|
||||
if the user enabled JSDoc's `--lenient` switch, JSDoc will simply log the error
|
||||
to the console and continue.
|
||||
|
||||
Packaging JSDoc 3 Plugins
|
||||
----
|
||||
|
||||
The JSDoc 3 Jakefile has an ```install``` task that can be used to install a
|
||||
plugin into the JSDoc directory. So running the following will install the
|
||||
plugin:
|
||||
|
||||
$>jake install[path/to/YourPluginFolder]
|
||||
|
||||
**Note**: On some operating systems, including OS X, you may need to quote the
|
||||
target name and parameters:
|
||||
|
||||
$>jake 'install[path/to/YourPluginFolder]'
|
||||
|
||||
The task is passed a directory that should look something like the following:
|
||||
|
||||
YourPluginFolder
|
||||
|- plugins
|
||||
| |- YourPlugin.js
|
||||
| \- test
|
||||
| |- fixtures
|
||||
| | \- YourFixtures.js
|
||||
| \- specs
|
||||
| \- YourTests.js
|
||||
\- templates
|
||||
\- YourTemplate
|
||||
\- publish.js
|
||||
@ -4,6 +4,8 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var logger = require('jsdoc/util/logger');
|
||||
|
||||
exports.handlers = {
|
||||
/**
|
||||
Support @source tag. Expected value like:
|
||||
@ -32,7 +34,8 @@ exports.handlers = {
|
||||
value = JSON.parse(tag.value);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
e.doclet.meta = e.doclet.meta || {};
|
||||
@ -41,4 +44,4 @@ exports.handlers = {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
/*global describe: true, env: true, expect: true, it: true, jasmine: true, xit: true */
|
||||
/**
|
||||
* @author Rob Taylor [manix84@gmail.com]
|
||||
*/
|
||||
|
||||
var path = require('jsdoc/path');
|
||||
|
||||
describe("verbose output plugin", function () {
|
||||
var parser = jasmine.createParser();
|
||||
var path = require('jsdoc/path');
|
||||
|
||||
var docSet;
|
||||
var pluginPath = 'plugins/verboseOutput';
|
||||
var plugin = require( path.resolve(env.dirname, pluginPath) );
|
||||
|
||||
//require('jsdoc/plugins').installPlugins(['plugins/verboseOutput'], parser);
|
||||
docSet = jasmine.getDocSetFromFile(pluginPath + '.js', parser);
|
||||
|
||||
xit("should log file names to console", function() {
|
||||
// TODO: this doesn't actually test the plugin...
|
||||
var fileBegin = docSet.getByLongname("module:plugins/verboseOutput.handlers.fileBegin");
|
||||
expect(fileBegin[0].description).toEqual("Logging the file name to the console.");
|
||||
});
|
||||
});
|
||||
@ -1,16 +0,0 @@
|
||||
/**
|
||||
* Adds a verbose output to the console, so that you can see what's happening in your process.
|
||||
* @module plugins/verboseOutput
|
||||
* @author Rob Taylor <manix84@gmail.com> - The basic idea
|
||||
* @author Michael Mathews <micmath@gmail.com> - Wrote the first itteration with me :)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
exports.handlers = {
|
||||
/**
|
||||
* Logging the file name to the console.
|
||||
*/
|
||||
fileBegin: function (data) {
|
||||
console.log(data.filename);
|
||||
}
|
||||
};
|
||||
315
rhino/assert.js
Normal file
315
rhino/assert.js
Normal file
@ -0,0 +1,315 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// UTILITY
|
||||
var util = require('util');
|
||||
var pSlice = Array.prototype.slice;
|
||||
|
||||
// 1. The assert module provides functions that throw
|
||||
// AssertionError's when particular conditions are not met. The
|
||||
// assert module must conform to the following interface.
|
||||
|
||||
var assert = module.exports = ok;
|
||||
|
||||
// 2. The AssertionError is defined in assert.
|
||||
// new assert.AssertionError({ message: message,
|
||||
// actual: actual,
|
||||
// expected: expected })
|
||||
|
||||
assert.AssertionError = function AssertionError(options) {
|
||||
this.name = 'AssertionError';
|
||||
this.actual = options.actual;
|
||||
this.expected = options.expected;
|
||||
this.operator = options.operator;
|
||||
this.message = options.message || getMessage(this);
|
||||
};
|
||||
|
||||
// assert.AssertionError instanceof Error
|
||||
util.inherits(assert.AssertionError, Error);
|
||||
|
||||
function replacer(key, value) {
|
||||
if (util.isUndefined(value)) {
|
||||
return '' + value;
|
||||
}
|
||||
if (util.isNumber(value) && (isNaN(value) || !isFinite(value))) {
|
||||
return value.toString();
|
||||
}
|
||||
if (util.isFunction(value) || util.isRegExp(value)) {
|
||||
return value.toString();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function truncate(s, n) {
|
||||
if (util.isString(s)) {
|
||||
return s.length < n ? s : s.slice(0, n);
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
function getMessage(self) {
|
||||
return truncate(JSON.stringify(self.actual, replacer), 128) + ' ' +
|
||||
self.operator + ' ' +
|
||||
truncate(JSON.stringify(self.expected, replacer), 128);
|
||||
}
|
||||
|
||||
// At present only the three keys mentioned above are used and
|
||||
// understood by the spec. Implementations or sub modules can pass
|
||||
// other keys to the AssertionError's constructor - they will be
|
||||
// ignored.
|
||||
|
||||
// 3. All of the following functions must throw an AssertionError
|
||||
// when a corresponding condition is not met, with a message that
|
||||
// may be undefined if not provided. All assertion methods provide
|
||||
// both the actual and expected values to the assertion error for
|
||||
// display purposes.
|
||||
|
||||
function fail(actual, expected, message, operator, stackStartFunction) {
|
||||
throw new assert.AssertionError({
|
||||
message: message,
|
||||
actual: actual,
|
||||
expected: expected,
|
||||
operator: operator,
|
||||
stackStartFunction: stackStartFunction
|
||||
});
|
||||
}
|
||||
|
||||
// EXTENSION! allows for well behaved errors defined elsewhere.
|
||||
assert.fail = fail;
|
||||
|
||||
// 4. Pure assertion tests whether a value is truthy, as determined
|
||||
// by !!guard.
|
||||
// assert.ok(guard, message_opt);
|
||||
// This statement is equivalent to assert.equal(true, !!guard,
|
||||
// message_opt);. To test strictly for the value true, use
|
||||
// assert.strictEqual(true, guard, message_opt);.
|
||||
|
||||
function ok(value, message) {
|
||||
if (!value) fail(value, true, message, '==', assert.ok);
|
||||
}
|
||||
assert.ok = ok;
|
||||
|
||||
// 5. The equality assertion tests shallow, coercive equality with
|
||||
// ==.
|
||||
// assert.equal(actual, expected, message_opt);
|
||||
|
||||
assert.equal = function equal(actual, expected, message) {
|
||||
if (actual != expected) fail(actual, expected, message, '==', assert.equal);
|
||||
};
|
||||
|
||||
// 6. The non-equality assertion tests for whether two objects are not equal
|
||||
// with != assert.notEqual(actual, expected, message_opt);
|
||||
|
||||
assert.notEqual = function notEqual(actual, expected, message) {
|
||||
if (actual == expected) {
|
||||
fail(actual, expected, message, '!=', assert.notEqual);
|
||||
}
|
||||
};
|
||||
|
||||
// 7. The equivalence assertion tests a deep equality relation.
|
||||
// assert.deepEqual(actual, expected, message_opt);
|
||||
|
||||
assert.deepEqual = function deepEqual(actual, expected, message) {
|
||||
if (!_deepEqual(actual, expected)) {
|
||||
fail(actual, expected, message, 'deepEqual', assert.deepEqual);
|
||||
}
|
||||
};
|
||||
|
||||
function _deepEqual(actual, expected) {
|
||||
// 7.1. All identical values are equivalent, as determined by ===.
|
||||
if (actual === expected) {
|
||||
return true;
|
||||
|
||||
} else if (util.isBuffer(actual) && util.isBuffer(expected)) {
|
||||
if (actual.length != expected.length) return false;
|
||||
|
||||
for (var i = 0; i < actual.length; i++) {
|
||||
if (actual[i] !== expected[i]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
// 7.2. If the expected value is a Date object, the actual value is
|
||||
// equivalent if it is also a Date object that refers to the same time.
|
||||
} else if (util.isDate(actual) && util.isDate(expected)) {
|
||||
return actual.getTime() === expected.getTime();
|
||||
|
||||
// 7.3 If the expected value is a RegExp object, the actual value is
|
||||
// equivalent if it is also a RegExp object with the same source and
|
||||
// properties (`global`, `multiline`, `lastIndex`, `ignoreCase`).
|
||||
} else if (util.isRegExp(actual) && util.isRegExp(expected)) {
|
||||
return actual.source === expected.source &&
|
||||
actual.global === expected.global &&
|
||||
actual.multiline === expected.multiline &&
|
||||
actual.lastIndex === expected.lastIndex &&
|
||||
actual.ignoreCase === expected.ignoreCase;
|
||||
|
||||
// 7.4. Other pairs that do not both pass typeof value == 'object',
|
||||
// equivalence is determined by ==.
|
||||
} else if (!util.isObject(actual) && !util.isObject(expected)) {
|
||||
return actual == expected;
|
||||
|
||||
// 7.5 For all other Object pairs, including Array objects, equivalence is
|
||||
// determined by having the same number of owned properties (as verified
|
||||
// with Object.prototype.hasOwnProperty.call), the same set of keys
|
||||
// (although not necessarily the same order), equivalent values for every
|
||||
// corresponding key, and an identical 'prototype' property. Note: this
|
||||
// accounts for both named and indexed properties on Arrays.
|
||||
} else {
|
||||
return objEquiv(actual, expected);
|
||||
}
|
||||
}
|
||||
|
||||
function isArguments(object) {
|
||||
return Object.prototype.toString.call(object) == '[object Arguments]';
|
||||
}
|
||||
|
||||
function objEquiv(a, b) {
|
||||
if (util.isNullOrUndefined(a) || util.isNullOrUndefined(b))
|
||||
return false;
|
||||
// an identical 'prototype' property.
|
||||
if (a.prototype !== b.prototype) return false;
|
||||
//~~~I've managed to break Object.keys through screwy arguments passing.
|
||||
// Converting to array solves the problem.
|
||||
if (isArguments(a)) {
|
||||
if (!isArguments(b)) {
|
||||
return false;
|
||||
}
|
||||
a = pSlice.call(a);
|
||||
b = pSlice.call(b);
|
||||
return _deepEqual(a, b);
|
||||
}
|
||||
try {
|
||||
var ka = Object.keys(a),
|
||||
kb = Object.keys(b),
|
||||
key, i;
|
||||
} catch (e) {//happens when one is a string literal and the other isn't
|
||||
return false;
|
||||
}
|
||||
// having the same number of owned properties (keys incorporates
|
||||
// hasOwnProperty)
|
||||
if (ka.length != kb.length)
|
||||
return false;
|
||||
//the same set of keys (although not necessarily the same order),
|
||||
ka.sort();
|
||||
kb.sort();
|
||||
//~~~cheap key test
|
||||
for (i = ka.length - 1; i >= 0; i--) {
|
||||
if (ka[i] != kb[i])
|
||||
return false;
|
||||
}
|
||||
//equivalent values for every corresponding key, and
|
||||
//~~~possibly expensive deep test
|
||||
for (i = ka.length - 1; i >= 0; i--) {
|
||||
key = ka[i];
|
||||
if (!_deepEqual(a[key], b[key])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 8. The non-equivalence assertion tests for any deep inequality.
|
||||
// assert.notDeepEqual(actual, expected, message_opt);
|
||||
|
||||
assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
|
||||
if (_deepEqual(actual, expected)) {
|
||||
fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);
|
||||
}
|
||||
};
|
||||
|
||||
// 9. The strict equality assertion tests strict equality, as determined by ===.
|
||||
// assert.strictEqual(actual, expected, message_opt);
|
||||
|
||||
assert.strictEqual = function strictEqual(actual, expected, message) {
|
||||
if (actual !== expected) {
|
||||
fail(actual, expected, message, '===', assert.strictEqual);
|
||||
}
|
||||
};
|
||||
|
||||
// 10. The strict non-equality assertion tests for strict inequality, as
|
||||
// determined by !==. assert.notStrictEqual(actual, expected, message_opt);
|
||||
|
||||
assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
|
||||
if (actual === expected) {
|
||||
fail(actual, expected, message, '!==', assert.notStrictEqual);
|
||||
}
|
||||
};
|
||||
|
||||
function expectedException(actual, expected) {
|
||||
if (!actual || !expected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Object.prototype.toString.call(expected) == '[object RegExp]') {
|
||||
return expected.test(actual);
|
||||
} else if (actual instanceof expected) {
|
||||
return true;
|
||||
} else if (expected.call({}, actual) === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function _throws(shouldThrow, block, expected, message) {
|
||||
var actual;
|
||||
|
||||
if (util.isString(expected)) {
|
||||
message = expected;
|
||||
expected = null;
|
||||
}
|
||||
|
||||
try {
|
||||
block();
|
||||
} catch (e) {
|
||||
actual = e;
|
||||
}
|
||||
|
||||
message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
|
||||
(message ? ' ' + message : '.');
|
||||
|
||||
if (shouldThrow && !actual) {
|
||||
fail(actual, expected, 'Missing expected exception' + message);
|
||||
}
|
||||
|
||||
if (!shouldThrow && expectedException(actual, expected)) {
|
||||
fail(actual, expected, 'Got unwanted exception' + message);
|
||||
}
|
||||
|
||||
if ((shouldThrow && actual && expected &&
|
||||
!expectedException(actual, expected)) || (!shouldThrow && actual)) {
|
||||
throw actual;
|
||||
}
|
||||
}
|
||||
|
||||
// 11. Expected to throw an error:
|
||||
// assert.throws(block, Error_opt, message_opt);
|
||||
|
||||
assert.throws = function(block, /*optional*/error, /*optional*/message) {
|
||||
_throws.apply(this, [true].concat(pSlice.call(arguments)));
|
||||
};
|
||||
|
||||
// EXTENSION! This is annoying to write outside this module.
|
||||
assert.doesNotThrow = function(block, /*optional*/message) {
|
||||
_throws.apply(this, [false].concat(pSlice.call(arguments)));
|
||||
};
|
||||
|
||||
assert.ifError = function(err) { if (err) {throw err;}};
|
||||
@ -16,15 +16,18 @@ global.setTimeout = null;
|
||||
global.clearTimeout = null;
|
||||
global.setInterval = null;
|
||||
global.clearInterval = null;
|
||||
global.setImmediate = null;
|
||||
global.clearImmediate = null;
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// TODO: tune number of threads if necessary
|
||||
var timerPool = new java.util.concurrent.ScheduledThreadPoolExecutor(10);
|
||||
var timerPool = new java.util.concurrent.ScheduledThreadPoolExecutor(1);
|
||||
var timers = {};
|
||||
var timerCount = 1;
|
||||
var timerUnits = java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
var queue = {};
|
||||
var queueActive = false;
|
||||
|
||||
function getCallback(fn) {
|
||||
return new java.lang.Runnable({
|
||||
@ -54,6 +57,41 @@ global.clearInterval = null;
|
||||
};
|
||||
|
||||
global.clearInterval = global.clearTimeout;
|
||||
|
||||
// adapted from https://github.com/alexgorbatchev/node-browser-builtins
|
||||
// MIT license
|
||||
global.setImmediate = (function() {
|
||||
function drain() {
|
||||
var key;
|
||||
|
||||
var keys = Object.keys(queue);
|
||||
|
||||
queueActive = false;
|
||||
|
||||
for (var i = 0, l = keys.length; i < l; i++) {
|
||||
key = keys[i];
|
||||
var fn = queue[key];
|
||||
delete queue[key];
|
||||
fn();
|
||||
}
|
||||
}
|
||||
|
||||
return function(fn) {
|
||||
var timerId = timerCount++;
|
||||
queue[timerId] = fn;
|
||||
|
||||
if (!queueActive) {
|
||||
queueActive = true;
|
||||
global.setTimeout(drain, 0);
|
||||
}
|
||||
|
||||
return timerId;
|
||||
};
|
||||
})();
|
||||
|
||||
global.clearImmediate = function(id) {
|
||||
delete queue[id];
|
||||
};
|
||||
})();
|
||||
|
||||
/**
|
||||
|
||||
@ -5,7 +5,7 @@ var template = require('jsdoc/template'),
|
||||
fs = require('jsdoc/fs'),
|
||||
path = require('jsdoc/path'),
|
||||
taffy = require('taffydb').taffy,
|
||||
handle = require('jsdoc/util/error').handle,
|
||||
logger = require('jsdoc/util/logger'),
|
||||
helper = require('jsdoc/util/templateHelper'),
|
||||
htmlsafe = helper.htmlsafe,
|
||||
linkto = helper.linkto,
|
||||
@ -141,7 +141,7 @@ function generateSourceFiles(sourceFiles, encoding) {
|
||||
};
|
||||
}
|
||||
catch(e) {
|
||||
handle(e);
|
||||
logger.error('Error while generating source file %s: %s', file, e.message);
|
||||
}
|
||||
|
||||
generate('Source: ' + sourceFiles[file].shortened, [source], sourceOutfile,
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
* 4. Run Jasmine on each directory
|
||||
*/
|
||||
var fs = require('jsdoc/fs');
|
||||
var logger = require('jsdoc/util/logger');
|
||||
var path = require('path');
|
||||
|
||||
fs.existsSync = fs.existsSync || path.existsSync;
|
||||
@ -47,6 +48,9 @@ function testedAllParsers() {
|
||||
var runNextFolder = module.exports = function(callback) {
|
||||
testsCompleteCallback = testsCompleteCallback || callback;
|
||||
|
||||
// silence the logger while we run the tests
|
||||
logger.setLevel(logger.LEVELS.SILENT);
|
||||
|
||||
if (index < specFolders.length) {
|
||||
// we need to run the test specs once for each parser
|
||||
// TODO: We currently support testing one parser per runtime
|
||||
|
||||
@ -1,184 +1,184 @@
|
||||
/*global describe: true, expect: true, it: true */
|
||||
describe("jsdoc/opts/args", function() {
|
||||
describe('jsdoc/opts/args', function() {
|
||||
var args = require('jsdoc/opts/args');
|
||||
var querystring = require('querystring');
|
||||
|
||||
it("should exist", function() {
|
||||
it('should exist', function() {
|
||||
expect(args).toBeDefined();
|
||||
expect(typeof args).toEqual("object");
|
||||
expect(typeof args).toBe('object');
|
||||
});
|
||||
|
||||
it("should export a 'parse' function", function() {
|
||||
it('should export a "parse" function', function() {
|
||||
expect(args.parse).toBeDefined();
|
||||
expect(typeof args.parse).toEqual("function");
|
||||
expect(typeof args.parse).toBe('function');
|
||||
});
|
||||
|
||||
it("should export a 'help' function", function() {
|
||||
it('should export a "help" function', function() {
|
||||
expect(args.help).toBeDefined();
|
||||
expect(typeof args.help).toEqual("function");
|
||||
expect(typeof args.help).toBe('function');
|
||||
});
|
||||
|
||||
it("should export a 'get' function", function() {
|
||||
it('should export a "get" function', function() {
|
||||
expect(args.get).toBeDefined();
|
||||
expect(typeof args.get).toEqual("function");
|
||||
expect(typeof args.get).toBe('function');
|
||||
});
|
||||
|
||||
describe("parse", function() {
|
||||
it("should accept a '-t' option and return an object with a 'template' property", function() {
|
||||
describe('parse', function() {
|
||||
it('should accept a "-t" option and return an object with a "template" property', function() {
|
||||
args.parse(['-t', 'mytemplate']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.template).toEqual('mytemplate');
|
||||
expect(r.template).toBe('mytemplate');
|
||||
});
|
||||
|
||||
it("should accept a '--template' option and return an object with a 'template' property", function() {
|
||||
it('should accept a "--template" option and return an object with a "template" property', function() {
|
||||
args.parse(['--template', 'mytemplate']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.template).toEqual('mytemplate');
|
||||
expect(r.template).toBe('mytemplate');
|
||||
});
|
||||
|
||||
it("should accept a '-c' option and return an object with a 'configure' property", function() {
|
||||
it('should accept a "-c" option and return an object with a "configure" property', function() {
|
||||
args.parse(['-c', 'myconf.json']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.configure).toEqual('myconf.json');
|
||||
expect(r.configure).toBe('myconf.json');
|
||||
});
|
||||
|
||||
it("should accept a '--configure' option and return an object with a 'configure' property", function() {
|
||||
it('should accept a "--configure" option and return an object with a "configure" property', function() {
|
||||
args.parse(['--configure', 'myconf.json']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.configure).toEqual('myconf.json');
|
||||
expect(r.configure).toBe('myconf.json');
|
||||
});
|
||||
|
||||
it("should accept a '-e' option and return an object with a 'encoding' property", function() {
|
||||
it('should accept an "-e" option and return an object with a "encoding" property', function() {
|
||||
args.parse(['-e', 'ascii']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.encoding).toEqual('ascii');
|
||||
expect(r.encoding).toBe('ascii');
|
||||
});
|
||||
|
||||
it("should accept a '--encoding' option and return an object with a 'encoding' property", function() {
|
||||
it('should accept an "--encoding" option and return an object with an "encoding" property', function() {
|
||||
args.parse(['--encoding', 'ascii']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.encoding).toEqual('ascii');
|
||||
expect(r.encoding).toBe('ascii');
|
||||
});
|
||||
|
||||
it("should accept a '-T' option and return an object with a 'test' property", function() {
|
||||
it('should accept a "-T" option and return an object with a "test" property', function() {
|
||||
args.parse(['-T']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.test).toEqual(true);
|
||||
expect(r.test).toBe(true);
|
||||
});
|
||||
|
||||
it("should accept a '--test' option and return an object with a 'test' property", function() {
|
||||
it('should accept a "--test" option and return an object with a "test" property', function() {
|
||||
args.parse(['--test']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.test).toEqual(true);
|
||||
expect(r.test).toBe(true);
|
||||
});
|
||||
|
||||
it("should accept a '-d' option and return an object with a 'destination' property", function() {
|
||||
it('should accept a "-d" option and return an object with a "destination" property', function() {
|
||||
args.parse(['-d', 'mydestination']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.destination).toEqual('mydestination');
|
||||
expect(r.destination).toBe('mydestination');
|
||||
});
|
||||
|
||||
it("should accept a '--destination' option and return an object with a 'destination' property", function() {
|
||||
it('should accept a "--destination" option and return an object with a "destination" property', function() {
|
||||
args.parse(['--destination', 'mydestination']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.destination).toEqual('mydestination');
|
||||
expect(r.destination).toBe('mydestination');
|
||||
});
|
||||
|
||||
it("should accept a '-p' option and return an object with a 'private' property", function() {
|
||||
it('should accept a "-p" option and return an object with a "private" property', function() {
|
||||
args.parse(['-p']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r['private']).toEqual(true);
|
||||
expect(r.private).toBe(true);
|
||||
});
|
||||
|
||||
it("should accept a '--private' option and return an object with a 'private' property", function() {
|
||||
it('should accept a "--private" option and return an object with a "private" property', function() {
|
||||
args.parse(['--private']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r['private']).toEqual(true);
|
||||
expect(r.private).toBe(true);
|
||||
});
|
||||
|
||||
it("should accept a '-r' option and return an object with a 'recurse' property", function() {
|
||||
it('should accept a "-r" option and return an object with a "recurse" property', function() {
|
||||
args.parse(['-r']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.recurse).toEqual(true);
|
||||
expect(r.recurse).toBe(true);
|
||||
});
|
||||
|
||||
it("should accept a '--recurse' option and return an object with a 'recurse' property", function() {
|
||||
it('should accept a "--recurse" option and return an object with a "recurse" property', function() {
|
||||
args.parse(['--recurse']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.recurse).toEqual(true);
|
||||
expect(r.recurse).toBe(true);
|
||||
});
|
||||
|
||||
it("should accept a '-l' option and return an object with a 'lenient' property", function() {
|
||||
it('should accept a "-l" option and ignore it', function() {
|
||||
args.parse(['-l']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.lenient).toEqual(true);
|
||||
expect(r.lenient).not.toBeDefined();
|
||||
});
|
||||
|
||||
it("should accept a '--lenient' option and return an object with a 'lenient' property", function() {
|
||||
it('should accept a "--lenient" option and ignore it', function() {
|
||||
args.parse(['--lenient']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.lenient).toEqual(true);
|
||||
expect(r.lenient).not.toBeDefined();
|
||||
});
|
||||
|
||||
it("should accept a '-h' option and return an object with a 'help' property", function() {
|
||||
it('should accept a "-h" option and return an object with a "help" property', function() {
|
||||
args.parse(['-h']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.help).toEqual(true);
|
||||
expect(r.help).toBe(true);
|
||||
});
|
||||
|
||||
it("should accept a '--help' option and return an object with a 'help' property", function() {
|
||||
it('should accept a "--help" option and return an object with a "help" property', function() {
|
||||
args.parse(['--help']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.help).toEqual(true);
|
||||
expect(r.help).toBe(true);
|
||||
});
|
||||
|
||||
it("should accept a '-X' option and return an object with a 'explain' property", function() {
|
||||
it('should accept an "-X" option and return an object with an "explain" property', function() {
|
||||
args.parse(['-X']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.explain).toEqual(true);
|
||||
expect(r.explain).toBe(true);
|
||||
});
|
||||
|
||||
it("should accept a '--explain' option and return an object with a 'explain' property", function() {
|
||||
it('should accept an "--explain" option and return an object with an "explain" property', function() {
|
||||
args.parse(['--explain']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.explain).toEqual(true);
|
||||
expect(r.explain).toBe(true);
|
||||
});
|
||||
|
||||
it("should accept a '-q' option and return an object with a 'query' property", function() {
|
||||
it('should accept a "-q" option and return an object with a "query" property', function() {
|
||||
args.parse(['-q', 'foo=bar&fab=baz']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.query).toEqual({ foo: 'bar', fab: 'baz' });
|
||||
});
|
||||
|
||||
it("should accept a '--query' option and return an object with a 'query' property", function() {
|
||||
it('should accept a "--query" option and return an object with a "query" property', function() {
|
||||
args.parse(['--query', 'foo=bar&fab=baz']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.query).toEqual({ foo: 'bar', fab: 'baz' });
|
||||
});
|
||||
|
||||
it("should use type coercion on the 'query' property so it has real booleans and numbers", function() {
|
||||
it('should use type coercion on the "query" property so it has real booleans and numbers', function() {
|
||||
var obj = {
|
||||
foo: 'fab',
|
||||
bar: true,
|
||||
@ -191,63 +191,77 @@ describe("jsdoc/opts/args", function() {
|
||||
expect(r.query).toEqual(obj);
|
||||
});
|
||||
|
||||
it("should accept a '-t' option and return an object with a 'tutorials' property", function() {
|
||||
args.parse(['-d', 'mytutorials']);
|
||||
it('should accept a "-u" option and return an object with a "tutorials" property', function() {
|
||||
args.parse(['-u', 'mytutorials']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.destination).toEqual('mytutorials');
|
||||
expect(r.tutorials).toBe('mytutorials');
|
||||
});
|
||||
|
||||
it("should accept a '--tutorials' option and return an object with a 'tutorials' property", function() {
|
||||
it('should accept a "--tutorials" option and return an object with a "tutorials" property', function() {
|
||||
args.parse(['--tutorials', 'mytutorials']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.tutorials).toEqual('mytutorials');
|
||||
expect(r.tutorials).toBe('mytutorials');
|
||||
});
|
||||
|
||||
it("should accept a '--verbose' option and return an object with a 'verbose' property", function() {
|
||||
it('should accept a "--debug" option and return an object with a "debug" property', function() {
|
||||
args.parse(['--debug']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.debug).toBe(true);
|
||||
});
|
||||
|
||||
it('should accept a "--verbose" option and return an object with a "verbose" property', function() {
|
||||
args.parse(['--verbose']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.verbose).toEqual(true);
|
||||
expect(r.verbose).toBe(true);
|
||||
});
|
||||
|
||||
it("should accept a '--match' option and return an object with a 'match' property", function() {
|
||||
it('should accept a "--pedantic" option and return an object with a "pedantic" property', function() {
|
||||
args.parse(['--pedantic']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.pedantic).toBe(true);
|
||||
});
|
||||
|
||||
it('should accept a "--match" option and return an object with a "match" property', function() {
|
||||
args.parse(['--match', '.*tag']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.match).toEqual('.*tag');
|
||||
expect(r.match).toBe('.*tag');
|
||||
});
|
||||
|
||||
it("should accept multiple '--match' options and return an object with a 'match' property", function() {
|
||||
it('should accept multiple "--match" options and return an object with a "match" property', function() {
|
||||
args.parse(['--match', '.*tag', '--match', 'parser']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.match).toEqual(['.*tag', 'parser']);
|
||||
});
|
||||
|
||||
it("should accept a '--nocolor' option and return an object with a 'nocolor' property", function() {
|
||||
it('should accept a "--nocolor" option and return an object with a "nocolor" property', function() {
|
||||
args.parse(['--nocolor']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.nocolor).toEqual(true);
|
||||
expect(r.nocolor).toBe(true);
|
||||
});
|
||||
|
||||
it("should accept a '-v' option and return an object with a 'version' property", function() {
|
||||
it('should accept a "-v" option and return an object with a "version" property', function() {
|
||||
args.parse(['-v']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.version).toEqual(true);
|
||||
expect(r.version).toBe(true);
|
||||
});
|
||||
|
||||
it("should accept a '--version' option and return an object with a 'version' property", function() {
|
||||
it('should accept a "--version" option and return an object with a "version" property', function() {
|
||||
args.parse(['--version']);
|
||||
var r = args.get();
|
||||
|
||||
expect(r.version).toEqual(true);
|
||||
expect(r.version).toBe(true);
|
||||
});
|
||||
|
||||
it("should accept a naked option (i.e. no '-') and return an object with a '_' property", function() {
|
||||
it('should accept a naked option (with no "-") and return an object with a "_" property', function() {
|
||||
args.parse(['myfile1', 'myfile2']);
|
||||
var r = args.get();
|
||||
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
/*global afterEach: true, describe: true, env: true, expect: true, it: true, spyOn: true */
|
||||
/*global afterEach, beforeEach, describe, env, expect, it, spyOn */
|
||||
describe("jsdoc/tag", function() {
|
||||
var jsdoc = {
|
||||
tag: require('jsdoc/tag'),
|
||||
dictionary: require('jsdoc/tag/dictionary'),
|
||||
type: require('jsdoc/tag/type')
|
||||
};
|
||||
var logger = require('jsdoc/util/logger');
|
||||
|
||||
it('should exist', function() {
|
||||
expect(jsdoc.tag).toBeDefined();
|
||||
@ -151,28 +152,12 @@ describe("jsdoc/tag", function() {
|
||||
|
||||
// further tests for this sort of thing are in jsdoc/tag/validator.js tests.
|
||||
describe("tag validating", function() {
|
||||
var lenient = !!env.opts.lenient;
|
||||
|
||||
function badTag() {
|
||||
var tag = new jsdoc.tag.Tag("name");
|
||||
return tag;
|
||||
}
|
||||
it("logs an error for bad tags", function() {
|
||||
spyOn(logger, 'error');
|
||||
|
||||
afterEach(function() {
|
||||
env.opts.lenient = lenient;
|
||||
});
|
||||
var tag = new jsdoc.tag.Tag('param', '{!*!*!*!} foo');
|
||||
|
||||
it("throws an exception for bad tags if the lenient option is not enabled", function() {
|
||||
env.opts.lenient = false;
|
||||
|
||||
expect(badTag).toThrow();
|
||||
});
|
||||
|
||||
it("doesn't throw an exception for bad tags if the lenient option is enabled", function() {
|
||||
spyOn(console, 'log');
|
||||
env.opts.lenient = true;
|
||||
|
||||
expect(badTag).not.toThrow();
|
||||
expect(logger.error).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
/*global afterEach: true, beforeEach: true, describe: true, env: true, expect: true, it: true, spyOn: true */
|
||||
/*global afterEach, beforeEach, describe, env, expect, it, spyOn */
|
||||
describe('jsdoc/tag/validator', function() {
|
||||
var validator = require('jsdoc/tag/validator'),
|
||||
doop = require('jsdoc/util/doop'),
|
||||
logger = require('jsdoc/util/logger'),
|
||||
tag = require('jsdoc/tag');
|
||||
|
||||
it('should exist', function() {
|
||||
@ -13,11 +15,8 @@ describe('jsdoc/tag/validator', function() {
|
||||
expect(typeof validator.validate).toBe('function');
|
||||
});
|
||||
|
||||
// Note: various Error classes are private so we just test whether *any*
|
||||
// error was thrown, not against particular types (e.g. UnknownTagError).
|
||||
describe('validate', function() {
|
||||
var dictionary = require('jsdoc/tag/dictionary'),
|
||||
lenient = !!env.opts.lenient,
|
||||
allowUnknown = !!env.conf.tags.allowUnknownTags,
|
||||
badTag = {title: 'lkjasdlkjfb'},
|
||||
meta = {filename: 'asdf.js', lineno: 1},
|
||||
@ -25,72 +24,53 @@ describe('jsdoc/tag/validator', function() {
|
||||
goodTag2 = new tag.Tag('ignore', '', meta); // mustNotHaveValue
|
||||
|
||||
function validateTag(tag) {
|
||||
return function() { validator.validate(tag, dictionary.lookUp(tag.title), meta); };
|
||||
}
|
||||
validator.validate(tag, dictionary.lookUp(tag.title), meta);
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
spyOn(console, 'log');
|
||||
spyOn(logger, 'error');
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
env.opts.lenient = lenient;
|
||||
env.conf.tags.allowUnknownTags = allowUnknown;
|
||||
});
|
||||
|
||||
it("throws an error if the tag is not in the dictionary, conf.tags.allowUnknownTags is false and lenient is false", function() {
|
||||
env.opts.lenient = false;
|
||||
it("logs an error if the tag is not in the dictionary and conf.tags.allowUnknownTags is false", function() {
|
||||
env.conf.tags.allowUnknownTags = false;
|
||||
expect(validateTag(badTag)).toThrow();
|
||||
validateTag(badTag);
|
||||
|
||||
expect(logger.error).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("throws NO error if the tag is not in the dictionary, conf.tags.allowUnknownTags is false and lenient is true", function() {
|
||||
env.opts.lenient = true;
|
||||
env.conf.tags.allowUnknownTags = false;
|
||||
expect(validateTag(badTag)).not.toThrow();
|
||||
});
|
||||
|
||||
it("doesn't throw an error if the tag is not in the dictionary and conf.tags.allowUnknownTags is true, regardless of lenience", function() {
|
||||
// if it doesn't throw an error with lenient false, then it won't throw it with lenient true (we have
|
||||
// tested lenient already in util/error.js)
|
||||
env.opts.lenient = false;
|
||||
it("doesn't log an error if the tag is not in the dictionary and conf.tags.allowUnknownTags is true", function() {
|
||||
env.conf.tags.allowUnknownTags = true;
|
||||
expect(validateTag(badTag)).not.toThrow();
|
||||
validateTag(badTag);
|
||||
|
||||
expect(logger.error).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("throws no error for valid tags", function() {
|
||||
env.opts.lenient = false;
|
||||
expect(validateTag(goodTag)).not.toThrow();
|
||||
expect(validateTag(goodTag2)).not.toThrow();
|
||||
it("logs no error for valid tags", function() {
|
||||
validateTag(goodTag);
|
||||
validateTag(goodTag2);
|
||||
|
||||
expect(logger.error).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("throws an error if the tag has no text but .mustHaveValue is true and lenient is false, or none if it's true", function() {
|
||||
// the name tag has .mustHaveValue.
|
||||
var oldText = goodTag.text;
|
||||
delete goodTag.text;
|
||||
it("logs an error if the tag has no text but .mustHaveValue is true", function() {
|
||||
var missingName = doop(goodTag);
|
||||
missingName.text = null;
|
||||
validateTag(missingName);
|
||||
|
||||
env.opts.lenient = false;
|
||||
expect(validateTag(goodTag)).toThrow();
|
||||
|
||||
env.opts.lenient = true;
|
||||
expect(validateTag(goodTag)).not.toThrow();
|
||||
|
||||
goodTag.text = oldText;
|
||||
expect(logger.error).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("throws an error if the tag has text but .mustNotHaveValue is true and lenient is false, or none if it's true", function() {
|
||||
var oldVal = goodTag2.mustNotHaveValue,
|
||||
text = goodTag2.text;
|
||||
goodTag2.mustNotHaveValue = true;
|
||||
goodTag2.text = goodTag2.text || 'asdf';
|
||||
it("logs an error if the tag has text but .mustNotHaveValue is true", function() {
|
||||
var missingText = doop(goodTag2);
|
||||
missingText.mustNotHaveValue = true;
|
||||
missingText.text = missingText.text || 'asdf';
|
||||
validateTag(missingText);
|
||||
|
||||
env.opts.lenient = false;
|
||||
expect(validateTag(goodTag2)).toThrow();
|
||||
|
||||
env.opts.lenient = true;
|
||||
expect(validateTag(goodTag2)).not.toThrow();
|
||||
|
||||
goodTag2.mustNotHaveValue = oldVal;
|
||||
goodTag2.text = oldVal;
|
||||
expect(logger.error).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
/*global afterEach: true, beforeEach: true, describe: true, env: true, expect: true, it: true,
|
||||
spyOn: true */
|
||||
/*global beforeEach, describe, env, expect, it, spyOn */
|
||||
describe("jsdoc/tutorial/resolver", function() {
|
||||
var logger = require('jsdoc/util/logger');
|
||||
var resolver = require('jsdoc/tutorial/resolver');
|
||||
var tutorial = require('jsdoc/tutorial');
|
||||
var lenient = !!env.opts.lenient;
|
||||
|
||||
it("should exist", function() {
|
||||
expect(resolver).toBeDefined();
|
||||
@ -171,59 +170,30 @@ describe("jsdoc/tutorial/resolver", function() {
|
||||
|
||||
// error reporting.
|
||||
describe("Error reporting", function() {
|
||||
// Tests for error reporting.
|
||||
function missingTutorial() {
|
||||
beforeEach(function() {
|
||||
spyOn(logger, 'error');
|
||||
spyOn(logger, 'warn');
|
||||
});
|
||||
|
||||
it("logs an error for missing tutorials", function() {
|
||||
resolver.load(env.dirname + "/test/tutorials/incomplete");
|
||||
resolver.resolve();
|
||||
}
|
||||
function duplicateNamedTutorials() {
|
||||
// can't add a tutorial if another with its name has already been added
|
||||
|
||||
expect(logger.error).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("logs a warning for duplicate-named tutorials (e.g. test.md, test.html)", function() {
|
||||
resolver.addTutorial(tute);
|
||||
}
|
||||
function duplicateDefinedTutorials() {
|
||||
|
||||
expect(logger.warn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("logs an error for tutorials defined twice in .json files", function() {
|
||||
// can't have a tutorial's metadata defined twice in .json files
|
||||
resolver.load(env.dirname + "/test/tutorials/duplicateDefined");
|
||||
resolver.resolve();
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
spyOn(console, 'log');
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
env.opts.lenient = lenient;
|
||||
});
|
||||
|
||||
it("throws an exception for missing tutorials if the lenient option is not enabled", function() {
|
||||
env.opts.lenient = false;
|
||||
|
||||
expect(missingTutorial).toThrow();
|
||||
});
|
||||
|
||||
it("doesn't throw an exception for missing tutorials if the lenient option is enabled", function() {
|
||||
env.opts.lenient = true;
|
||||
|
||||
expect(missingTutorial).not.toThrow();
|
||||
});
|
||||
|
||||
it("throws an exception for duplicate-named tutorials (e.g. test.md, test.html) if the lenient option is not enabled", function() {
|
||||
env.opts.lenient = false;
|
||||
expect(duplicateNamedTutorials).toThrow();
|
||||
});
|
||||
|
||||
it("doesn't throw an exception for duplicate-named tutorials (e.g. test.md, test.html) if the lenient option is not enabled", function() {
|
||||
env.opts.lenient = true;
|
||||
expect(duplicateNamedTutorials).not.toThrow();
|
||||
});
|
||||
|
||||
it("throws an exception for tutorials defined twice in .jsons if the lenient option is not enabled", function() {
|
||||
env.opts.lenient = false;
|
||||
expect(duplicateDefinedTutorials).toThrow();
|
||||
});
|
||||
|
||||
it("doesn't throw an exception for tutorials defined twice in .jsons if the lenient option is not enabled", function() {
|
||||
env.opts.lenient = true;
|
||||
expect(duplicateDefinedTutorials).not.toThrow();
|
||||
expect(logger.error).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -1,53 +1,29 @@
|
||||
/*global describe: true, env: true, it: true */
|
||||
/*global beforeEach, describe, expect, it, spyOn */
|
||||
describe("jsdoc/util/error", function() {
|
||||
var error = require('jsdoc/util/error'),
|
||||
handle = error.handle;
|
||||
var error = require('jsdoc/util/error');
|
||||
var handle = error.handle;
|
||||
var logger = require('jsdoc/util/logger');
|
||||
|
||||
it("should exist", function() {
|
||||
expect(error).toBeDefined();
|
||||
expect(typeof error).toEqual("object");
|
||||
});
|
||||
it("should exist", function() {
|
||||
expect(error).toBeDefined();
|
||||
expect(typeof error).toEqual("object");
|
||||
});
|
||||
|
||||
it("should export a 'handle' function", function() {
|
||||
expect(handle).toBeDefined();
|
||||
expect(typeof handle).toEqual("function");
|
||||
});
|
||||
it("should export a 'handle' function", function() {
|
||||
expect(handle).toBeDefined();
|
||||
expect(typeof handle).toEqual("function");
|
||||
});
|
||||
|
||||
describe("handle", function() {
|
||||
/*jshint evil: true */
|
||||
var lenient = !!env.opts.lenient;
|
||||
describe("handle", function() {
|
||||
it('should not throw', function() {
|
||||
expect(handle).not.toThrow();
|
||||
});
|
||||
|
||||
function handleError() {
|
||||
handle( new Error("foo") );
|
||||
}
|
||||
it('should log messages with logger.error()', function() {
|
||||
spyOn(logger, 'error');
|
||||
handle('test');
|
||||
|
||||
function handleObject() {
|
||||
handle( { foo: "bar", baz: "qux"} );
|
||||
}
|
||||
|
||||
afterEach(function() {
|
||||
env.opts.lenient = lenient;
|
||||
});
|
||||
|
||||
it("should re-throw errors by default", function() {
|
||||
expect(handleError).toThrow();
|
||||
});
|
||||
|
||||
it("should re-throw errors if lenient mode is not enabled", function() {
|
||||
env.opts.lenient = false;
|
||||
|
||||
expect(handleError).toThrow();
|
||||
});
|
||||
|
||||
it("should not re-throw errors if lenient mode is enabled", function() {
|
||||
env.opts.lenient = true;
|
||||
spyOn(console, 'log');
|
||||
|
||||
expect(handleError).not.toThrow();
|
||||
});
|
||||
|
||||
it("should still work if the 'e' param is not an instanceof Error", function() {
|
||||
expect(handleObject).toThrow();
|
||||
});
|
||||
});
|
||||
expect(logger.error).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
200
test/specs/jsdoc/util/logger.js
Normal file
200
test/specs/jsdoc/util/logger.js
Normal file
@ -0,0 +1,200 @@
|
||||
/*global afterEach, describe, expect, it, jasmine */
|
||||
describe('jsdoc/util/logger', function() {
|
||||
var logger = require('jsdoc/util/logger');
|
||||
|
||||
var loggerArgs = ['foo bar %s', 'hello'];
|
||||
|
||||
it('should exist', function() {
|
||||
expect(logger).toBeDefined();
|
||||
expect(typeof logger).toBe('object');
|
||||
});
|
||||
|
||||
it('should inherit from EventEmitter', function() {
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
|
||||
expect(logger instanceof EventEmitter).toBe(true);
|
||||
});
|
||||
|
||||
it('should export a "debug" method', function() {
|
||||
expect(logger.debug).toBeDefined();
|
||||
expect(typeof logger.debug).toBe('function');
|
||||
});
|
||||
|
||||
it('should export an "error" method', function() {
|
||||
expect(logger.error).toBeDefined();
|
||||
expect(typeof logger.error).toBe('function');
|
||||
});
|
||||
|
||||
it('should export a "fatal" method', function() {
|
||||
expect(logger.fatal).toBeDefined();
|
||||
expect(typeof logger.fatal).toBe('function');
|
||||
});
|
||||
|
||||
it('should export a "getLevel" method', function() {
|
||||
expect(logger.getLevel).toBeDefined();
|
||||
expect(typeof logger.getLevel).toBe('function');
|
||||
});
|
||||
|
||||
it('should export an "info" method', function() {
|
||||
expect(logger.info).toBeDefined();
|
||||
expect(typeof logger.info).toBe('function');
|
||||
});
|
||||
|
||||
it('should export a "LEVELS" object', function() {
|
||||
expect(logger.LEVELS).toBeDefined();
|
||||
expect(typeof logger.LEVELS).toBe('object');
|
||||
});
|
||||
|
||||
it('should export a "setLevel" method', function() {
|
||||
expect(logger.setLevel).toBeDefined();
|
||||
expect(typeof logger.setLevel).toBe('function');
|
||||
});
|
||||
|
||||
it('should export a "verbose" method', function() {
|
||||
expect(logger.verbose).toBeDefined();
|
||||
expect(typeof logger.verbose).toBe('function');
|
||||
});
|
||||
|
||||
it('should export a "warn" method', function() {
|
||||
expect(logger.warn).toBeDefined();
|
||||
expect(typeof logger.warn).toBe('function');
|
||||
});
|
||||
|
||||
// helpers for testing logger methods
|
||||
function eventIsEmitted(name) {
|
||||
var called = false;
|
||||
|
||||
logger.once('logger:' + name, function() {
|
||||
called = true;
|
||||
});
|
||||
logger[name]();
|
||||
|
||||
expect(called).toBe(true);
|
||||
}
|
||||
|
||||
function eventGetsArguments(name) {
|
||||
var args;
|
||||
|
||||
logger.once('logger:' + name, function() {
|
||||
args = Array.prototype.slice.call(arguments, 0);
|
||||
});
|
||||
logger[name](loggerArgs[0], loggerArgs[1]);
|
||||
|
||||
expect(args).toBeDefined();
|
||||
expect( Array.isArray(args) ).toBe(true);
|
||||
expect(args[0]).toBe(loggerArgs[0]);
|
||||
expect(args[1]).toBe(loggerArgs[1]);
|
||||
}
|
||||
|
||||
describe('debug', function() {
|
||||
var methodName = 'debug';
|
||||
|
||||
it('should cause the logger to emit the correct event', function() {
|
||||
eventIsEmitted(methodName);
|
||||
});
|
||||
|
||||
it('should pass its arguments to listeners', function() {
|
||||
eventGetsArguments(methodName);
|
||||
});
|
||||
});
|
||||
|
||||
describe('error', function() {
|
||||
var methodName = 'error';
|
||||
|
||||
it('should cause the logger to emit the correct event', function() {
|
||||
eventIsEmitted(methodName);
|
||||
});
|
||||
|
||||
it('should pass its arguments to listeners', function() {
|
||||
eventGetsArguments(methodName);
|
||||
});
|
||||
});
|
||||
|
||||
describe('fatal', function() {
|
||||
var methodName = 'fatal';
|
||||
|
||||
it('should cause the logger to emit the correct event', function() {
|
||||
eventIsEmitted(methodName);
|
||||
});
|
||||
|
||||
it('should pass its arguments to listeners', function() {
|
||||
eventGetsArguments(methodName);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLevel', function() {
|
||||
it('should return LEVELS.SILENT when we are running tests', function() {
|
||||
expect( logger.getLevel() ).toBe(logger.LEVELS.SILENT);
|
||||
});
|
||||
});
|
||||
|
||||
describe('info', function() {
|
||||
var methodName = 'info';
|
||||
|
||||
it('should cause the logger to emit the correct event', function() {
|
||||
eventIsEmitted(methodName);
|
||||
});
|
||||
|
||||
it('should pass its arguments to listeners', function() {
|
||||
eventGetsArguments(methodName);
|
||||
});
|
||||
});
|
||||
|
||||
describe('LEVELS', function() {
|
||||
var LEVELS = logger.LEVELS;
|
||||
|
||||
it('should include the correct properties', function() {
|
||||
expect(LEVELS.VERBOSE).toBeDefined();
|
||||
expect(LEVELS.DEBUG).toBeDefined();
|
||||
expect(LEVELS.INFO).toBeDefined();
|
||||
expect(LEVELS.WARN).toBeDefined();
|
||||
expect(LEVELS.ERROR).toBeDefined();
|
||||
expect(LEVELS.SILENT).toBeDefined();
|
||||
});
|
||||
|
||||
it('should weight the logging levels correctly relative to one another', function() {
|
||||
expect(LEVELS.VERBOSE).toBeGreaterThan(LEVELS.DEBUG);
|
||||
expect(LEVELS.DEBUG).toBeGreaterThan(LEVELS.INFO);
|
||||
expect(LEVELS.INFO).toBeGreaterThan(LEVELS.WARN);
|
||||
expect(LEVELS.WARN).toBeGreaterThan(LEVELS.ERROR);
|
||||
expect(LEVELS.ERROR).toBeGreaterThan(LEVELS.SILENT);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setLevel', function() {
|
||||
var oldLevel = logger.getLevel();
|
||||
|
||||
afterEach(function() {
|
||||
logger.setLevel(oldLevel);
|
||||
});
|
||||
|
||||
it('should update the log level', function() {
|
||||
logger.setLevel(logger.LEVELS.VERBOSE);
|
||||
expect( logger.getLevel() ).toBe(logger.LEVELS.VERBOSE);
|
||||
});
|
||||
});
|
||||
|
||||
describe('verbose', function() {
|
||||
var methodName = 'verbose';
|
||||
|
||||
it('should cause the logger to emit the correct event', function() {
|
||||
eventIsEmitted(methodName);
|
||||
});
|
||||
|
||||
it('should pass its arguments to listeners', function() {
|
||||
eventGetsArguments(methodName);
|
||||
});
|
||||
});
|
||||
|
||||
describe('warn', function() {
|
||||
var methodName = 'warn';
|
||||
|
||||
it('should cause the logger to emit the correct event', function() {
|
||||
eventIsEmitted(methodName);
|
||||
});
|
||||
|
||||
it('should pass its arguments to listeners', function() {
|
||||
eventGetsArguments(methodName);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,11 +1,11 @@
|
||||
/*global afterEach: true, beforeEach: true, describe: true, expect: true, env: true, it: true,
|
||||
jasmine: true, spyOn: true, xdescribe: true */
|
||||
/*global afterEach, beforeEach, describe, expect, env, it, jasmine, spyOn */
|
||||
var hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
|
||||
describe("jsdoc/util/templateHelper", function() {
|
||||
var helper = require('jsdoc/util/templateHelper'),
|
||||
doclet = require('jsdoc/doclet'),
|
||||
doop = require('jsdoc/util/doop'),
|
||||
logger = require('jsdoc/util/logger'),
|
||||
resolver = require('jsdoc/tutorial/resolver'),
|
||||
taffy = require('taffydb').taffy;
|
||||
helper.registerLink('test', 'path/to/test.html');
|
||||
@ -141,18 +141,11 @@ describe("jsdoc/util/templateHelper", function() {
|
||||
});
|
||||
|
||||
it("setting tutorials to the root tutorial object lets lookups work", function() {
|
||||
var lenient = !!env.opts.lenient;
|
||||
spyOn(console, 'log');
|
||||
|
||||
// tutorial doesn't exist, we want to muffle that error
|
||||
env.opts.lenient = true;
|
||||
|
||||
helper.setTutorials(resolver.root);
|
||||
spyOn(resolver.root, 'getByName');
|
||||
helper.tutorialToUrl('asdf');
|
||||
expect(resolver.root.getByName).toHaveBeenCalled();
|
||||
|
||||
env.opts.lenient = lenient;
|
||||
expect(resolver.root.getByName).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@ -747,23 +740,6 @@ describe("jsdoc/util/templateHelper", function() {
|
||||
|
||||
delete helper.longnameToUrl.MyClass;
|
||||
});
|
||||
|
||||
it("doesn't throw an error in lenient mode if a 'returns' item has no value", function() {
|
||||
function getReturns() {
|
||||
return helper.getSignatureReturns(doc);
|
||||
}
|
||||
|
||||
var doc;
|
||||
var lenient = !!env.opts.lenient;
|
||||
|
||||
env.opts.lenient = true;
|
||||
spyOn(console, 'log');
|
||||
doc = new doclet.Doclet('/** @function myFunction\n@returns */', {});
|
||||
|
||||
expect(getReturns).not.toThrow();
|
||||
|
||||
env.opts.lenient = lenient;
|
||||
});
|
||||
});
|
||||
|
||||
describe("getAncestorLinks", function() {
|
||||
@ -926,44 +902,32 @@ describe("jsdoc/util/templateHelper", function() {
|
||||
});
|
||||
|
||||
describe("tutorialToUrl", function() {
|
||||
var lenient = !!env.opts.lenient;
|
||||
|
||||
function missingTutorial() {
|
||||
var url = helper.tutorialToUrl("be-a-perfect-person-in-just-three-days");
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
spyOn(console, 'log');
|
||||
spyOn(logger, 'error');
|
||||
helper.setTutorials(resolver.root);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.setTutorials(null);
|
||||
env.opts.lenient = lenient;
|
||||
});
|
||||
|
||||
it('throws an exception if the tutorial is missing and the lenient option is not enabled', function() {
|
||||
env.opts.lenient = false;
|
||||
expect(missingTutorial).toThrow();
|
||||
it('logs an error if the tutorial is missing', function() {
|
||||
helper.tutorialToUrl('be-a-perfect-person-in-just-three-days');
|
||||
|
||||
expect(logger.error).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not throw an exception if the tutorial is missing and the lenient option is enabled', function() {
|
||||
env.opts.lenient = true;
|
||||
it("logs an error if the tutorial's name is a reserved JS keyword and it doesn't exist", function() {
|
||||
helper.tutorialToUrl('prototype');
|
||||
|
||||
expect(missingTutorial).not.toThrow();
|
||||
});
|
||||
|
||||
it("does not return a tutorial if its name is a reserved JS keyword and it doesn't exist", function() {
|
||||
env.opts.lenient = false;
|
||||
expect(function () { helper.tutorialToUrl('prototype'); }).toThrow();
|
||||
expect(logger.error).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("creates links to tutorials if they exist", function() {
|
||||
// NOTE: we have to set lenient = true here because otherwise JSDoc will
|
||||
// cry when trying to resolve the same set of tutorials twice (once
|
||||
// for the tutorials tests, and once here).
|
||||
env.opts.lenient = true;
|
||||
|
||||
// load the tutorials we already have for the tutorials tests
|
||||
resolver.load(env.dirname + "/test/tutorials/tutorials");
|
||||
resolver.resolve();
|
||||
@ -985,34 +949,21 @@ describe("jsdoc/util/templateHelper", function() {
|
||||
});
|
||||
|
||||
describe("toTutorial", function() {
|
||||
var lenient = !!env.opts.lenient;
|
||||
|
||||
function missingParam() {
|
||||
helper.toTutorial();
|
||||
}
|
||||
|
||||
afterEach(function() {
|
||||
env.opts.lenient = lenient;
|
||||
helper.setTutorials(null);
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
spyOn(logger, 'error');
|
||||
helper.setTutorials(resolver.root);
|
||||
});
|
||||
|
||||
it('throws an exception if the first param is missing and the lenient option is not enabled', function() {
|
||||
env.opts.lenient = false;
|
||||
afterEach(function() {
|
||||
helper.setTutorials(null);
|
||||
});
|
||||
|
||||
expect(missingParam).toThrow();
|
||||
it('logs an error if the first param is missing', function() {
|
||||
helper.toTutorial();
|
||||
|
||||
expect(logger.error).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not throw an exception if the first param is missing and the lenient option is enabled', function() {
|
||||
spyOn(console, 'log');
|
||||
env.opts.lenient = true;
|
||||
|
||||
expect(missingParam).not.toThrow();
|
||||
});
|
||||
|
||||
// missing tutorials
|
||||
it("returns the tutorial name if it's missing and no missingOpts is provided", function() {
|
||||
helper.setTutorials(resolver.root);
|
||||
@ -1046,12 +997,6 @@ describe("jsdoc/util/templateHelper", function() {
|
||||
|
||||
// now we do non-missing tutorials.
|
||||
it("returns a link to the tutorial if not missing", function() {
|
||||
// NOTE: we have to set lenient = true here because otherwise JSDoc will
|
||||
// cry when trying to resolve the same set of tutorials twice (once
|
||||
// for the tutorials tests, and once here).
|
||||
env.opts.lenient = true;
|
||||
spyOn(console, 'log');
|
||||
|
||||
// load the tutorials we already have for the tutorials tests
|
||||
resolver.load(env.dirname + "/test/tutorials/tutorials");
|
||||
resolver.resolve();
|
||||
|
||||
@ -78,14 +78,9 @@ describe("@param tag", function() {
|
||||
expect(commit.params[0].name).toBe('atomic');
|
||||
});
|
||||
|
||||
it('When a symbol has a @param tag with an invalid type expression, the doclet is generated in lenient mode, and the JSDoc comment is ignored.', function() {
|
||||
it('When a symbol has a @param tag with an invalid type expression, the JSDoc comment is ignored.', function() {
|
||||
var badDocSet;
|
||||
var test;
|
||||
var lenient = !!env.opts.lenient;
|
||||
|
||||
env.opts.lenient = true;
|
||||
spyOn(console, 'log');
|
||||
|
||||
badDocSet = jasmine.getDocSetFromFile('test/fixtures/paramtaginvalidtype.js');
|
||||
test = badDocSet.getByLongname('Test#test')[0];
|
||||
|
||||
@ -99,7 +94,5 @@ describe("@param tag", function() {
|
||||
expect(test.meta.filename).toBe('[[string0]]');
|
||||
|
||||
expect(test.description).not.toBeDefined();
|
||||
|
||||
env.opts.lenient = lenient;
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user