mirror of
https://github.com/jsdoc/jsdoc.git
synced 2025-12-08 19:46:11 +00:00
Merge pull request #117 from jannon/SmartTestRunner
Upgrade testing framework
This commit is contained in:
commit
7d97a17421
@ -72,12 +72,18 @@ JavaScript. Luckily it comes with a full-on debugger included that can be much
|
||||
more useful than a simple stack trace. To invoke JSDoc with the debugger try the
|
||||
following command:
|
||||
|
||||
jsdoc --debug
|
||||
|
||||
or the long form version:
|
||||
|
||||
$ java -classpath lib/js.jar \
|
||||
org.mozilla.javascript.tools.debugger.Main -debug \
|
||||
-modules node_modules -modules rhino_modules -modules . \
|
||||
jsdoc.js \
|
||||
your/script.js
|
||||
|
||||
Note: ```--debug``` must be the first argument to the short form command
|
||||
|
||||
This will open a debugging window. Choose "Break on Exceptions" from the "Debug"
|
||||
menu, then press the "Run" button. If there is an error, you should see exactly
|
||||
where it is in the source code.
|
||||
|
||||
21
jsdoc
21
jsdoc
@ -4,6 +4,23 @@
|
||||
SOURCE="$0"
|
||||
while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done
|
||||
BASEDIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
java -classpath ${BASEDIR}/lib/js.jar org.mozilla.javascript.tools.shell.Main -modules ${BASEDIR}/node_modules -modules ${BASEDIR}/rhino_modules -modules ${BASEDIR} ${BASEDIR}/jsdoc.js --dirname=${BASEDIR} $@
|
||||
|
||||
#java -classpath ${BASEDIR}/lib/js.jar org.mozilla.javascript.tools.debugger.Main -debug -modules ${BASEDIR}/node_modules -modules ${BASEDIR}/rhino_modules -modules ${BASEDIR} ${BASEDIR}/jsdoc.js --dirname=${BASEDIR} $@
|
||||
if test $1 = "--debug"
|
||||
then
|
||||
CMD="org.mozilla.javascript.tools.debugger.Main -debug"
|
||||
shift
|
||||
else
|
||||
CMD="org.mozilla.javascript.tools.shell.Main"
|
||||
fi
|
||||
|
||||
#Conditionally execute different command lines depending on whether we're running tests or not
|
||||
if test $1 = "-T"
|
||||
then
|
||||
echo "Running Tests"
|
||||
java -classpath ${BASEDIR}/lib/js.jar ${CMD} -opt -1 -modules ${BASEDIR}/node_modules -modules ${BASEDIR}/rhino_modules -modules ${BASEDIR} ${BASEDIR}/jsdoc.js --dirname=${BASEDIR} $@
|
||||
else
|
||||
echo "Running Normal"
|
||||
java -classpath ${BASEDIR}/lib/js.jar ${CMD} -modules ${BASEDIR}/node_modules -modules ${BASEDIR}/rhino_modules -modules ${BASEDIR} ${BASEDIR}/jsdoc.js --dirname=${BASEDIR} $@
|
||||
fi
|
||||
|
||||
#java -classpath ${BASEDIR}/lib/js.jar ${CMD} -modules ${BASEDIR}/node_modules -modules ${BASEDIR}/rhino_modules -modules ${BASEDIR} ${BASEDIR}/jsdoc.js --dirname=${BASEDIR} $@
|
||||
112
jsdoc.js
112
jsdoc.js
@ -34,7 +34,7 @@ load(__dirname + '/lib/rhino-shim.js');
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
|
||||
|
||||
|
||||
|
||||
/** Data representing the environment in which this app is running.
|
||||
@namespace
|
||||
*/
|
||||
@ -44,20 +44,20 @@ env = {
|
||||
start: new Date(),
|
||||
finish: null
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
The command line arguments passed into jsdoc.
|
||||
@type Array
|
||||
*/
|
||||
args: Array.prototype.slice.call(args, 0),
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
The parsed JSON data from the configuration file.
|
||||
@type Object
|
||||
*/
|
||||
conf: {},
|
||||
|
||||
|
||||
/**
|
||||
The command line arguments, parsed into a key/value hash.
|
||||
@type Object
|
||||
@ -79,12 +79,13 @@ app = {
|
||||
}
|
||||
|
||||
try { main(); }
|
||||
catch(e) {
|
||||
if (e.rhinoException != null) {
|
||||
catch(e) {
|
||||
if (e.rhinoException != null) {
|
||||
e.rhinoException.printStackTrace();
|
||||
}
|
||||
else throw e;
|
||||
}
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
finally { env.run.finish = new Date(); }
|
||||
|
||||
/** Print string/s out to the console.
|
||||
@ -119,7 +120,7 @@ function include(filepath) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
Cause the VM running jsdoc to exit running.
|
||||
@param {number} [n = 0] The exit status.
|
||||
*/
|
||||
@ -128,6 +129,33 @@ function exit(n) {
|
||||
java.lang.System.exit(n);
|
||||
}
|
||||
|
||||
function installPlugins(plugins, p) {
|
||||
var dictionary = require('jsdoc/tag/dictionary'),
|
||||
parser = p || app.jsdoc.parser;
|
||||
|
||||
// allow user-defined plugins to...
|
||||
for (var i = 0, leni = plugins.length; i < leni; i++) {
|
||||
var plugin = require(plugins[i]);
|
||||
|
||||
//...register event handlers
|
||||
if (plugin.handlers) {
|
||||
for (var eventName in plugin.handlers) {
|
||||
parser.on(eventName, plugin.handlers[eventName]);
|
||||
}
|
||||
}
|
||||
|
||||
//...define tags
|
||||
if (plugin.defineTags) {
|
||||
plugin.defineTags(dictionary);
|
||||
}
|
||||
|
||||
//...add a node visitor
|
||||
if (plugin.nodeVisitor) {
|
||||
parser.addNodeVisitor(plugin.nodeVisitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
|
||||
|
||||
|
||||
@ -144,11 +172,10 @@ function main() {
|
||||
}
|
||||
},
|
||||
resolver,
|
||||
dictionary = require('jsdoc/tag/dictionary'),
|
||||
fs = require('fs');
|
||||
|
||||
|
||||
env.opts = jsdoc.opts.parser.parse(env.args);
|
||||
|
||||
|
||||
try {
|
||||
env.conf = JSON.parse(
|
||||
fs.readFileSync( env.opts.configure || __dirname + '/conf.json' )
|
||||
@ -162,10 +189,10 @@ function main() {
|
||||
env.conf = JSON.parse(example);
|
||||
}
|
||||
catch(e) {
|
||||
throw('Configuration file cannot be evaluated. ' + e);
|
||||
throw('Configuration file cannot be evaluated. ' + e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// allow to pass arguments from configuration file
|
||||
if (env.conf.opts) {
|
||||
for (var opt in env.conf.opts) {
|
||||
@ -179,47 +206,26 @@ function main() {
|
||||
env.opts._ = env.conf.opts._.concat( env.opts._ );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (env.opts.query) {
|
||||
env.opts.query = require('common/query').toObject(env.opts.query);
|
||||
}
|
||||
|
||||
|
||||
// which version of javascript will be supported? (rhino only)
|
||||
if (typeof version === 'function') {
|
||||
version(env.conf.jsVersion || 180);
|
||||
}
|
||||
|
||||
|
||||
if (env.opts.help) {
|
||||
console.log( jsdoc.opts.parser.help() );
|
||||
exit(0);
|
||||
}
|
||||
else if (env.opts.test) {
|
||||
} else if (env.opts.test) {
|
||||
include('test/runner.js');
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// allow user-defined plugins to...
|
||||
|
||||
if (env.conf.plugins) {
|
||||
for (var i = 0, leni = env.conf.plugins.length; i < leni; i++) {
|
||||
var plugin = require(env.conf.plugins[i]);
|
||||
|
||||
//...register event handlers
|
||||
if (plugin.handlers) {
|
||||
for (var eventName in plugin.handlers) {
|
||||
app.jsdoc.parser.on(eventName, plugin.handlers[eventName]);
|
||||
}
|
||||
}
|
||||
|
||||
//...define tags
|
||||
if (plugin.defineTags) {
|
||||
plugin.defineTags(dictionary);
|
||||
}
|
||||
|
||||
//...add a node visitor
|
||||
if (plugin.nodeVisitor) {
|
||||
app.jsdoc.parser.addNodeVisitor(plugin.nodeVisitor);
|
||||
}
|
||||
}
|
||||
installPlugins(env.conf.plugins);
|
||||
}
|
||||
|
||||
// any source file named package.json is treated special
|
||||
@ -231,25 +237,25 @@ function main() {
|
||||
}
|
||||
|
||||
if (env.opts._.length > 0) { // are there any files to scan and parse?
|
||||
|
||||
|
||||
var includeMatch = (env.conf.source && env.conf.source.includePattern)? new RegExp(env.conf.source.includePattern) : null,
|
||||
excludeMatch = (env.conf.source && env.conf.source.excludePattern)? new RegExp(env.conf.source.excludePattern) : null;
|
||||
|
||||
|
||||
sourceFiles = app.jsdoc.scanner.scan(env.opts._, (env.opts.recurse? 10 : undefined), includeMatch, excludeMatch);
|
||||
|
||||
require('jsdoc/src/handlers').attachTo(app.jsdoc.parser);
|
||||
|
||||
|
||||
docs = app.jsdoc.parser.parse(sourceFiles, env.opts.encoding);
|
||||
|
||||
|
||||
//The files are ALWAYS useful for the templates to have
|
||||
//If there is no package.json, just create an empty package
|
||||
var packageDocs = new (require('jsdoc/package').Package)(packageJson);
|
||||
packageDocs.files = sourceFiles || [];
|
||||
docs.push(packageDocs);
|
||||
|
||||
|
||||
function indexAll(docs) {
|
||||
var lookupTable = {};
|
||||
|
||||
|
||||
docs.forEach(function(doc) {
|
||||
if ( !lookupTable.hasOwnProperty(doc.longname) ) {
|
||||
lookupTable[doc.longname] = [];
|
||||
@ -258,12 +264,12 @@ function main() {
|
||||
});
|
||||
docs.index = lookupTable;
|
||||
}
|
||||
|
||||
|
||||
indexAll(docs);
|
||||
|
||||
|
||||
require('jsdoc/augment').addInherited(docs);
|
||||
require('jsdoc/borrow').resolveBorrows(docs);
|
||||
|
||||
|
||||
if (env.opts.explain) {
|
||||
console.log(docs);
|
||||
exit(0);
|
||||
@ -279,7 +285,7 @@ function main() {
|
||||
}
|
||||
|
||||
env.opts.template = env.opts.template || 'templates/default';
|
||||
|
||||
|
||||
// should define a global "publish" function
|
||||
include(env.opts.template + '/publish.js');
|
||||
|
||||
|
||||
@ -11,13 +11,13 @@ console = {
|
||||
log: function(/*...*/) {
|
||||
var args = Array.prototype.slice.call(arguments, 0),
|
||||
dumper = dumper || require('jsdoc/util/dumper');
|
||||
|
||||
|
||||
for (var i = 0, len = args.length; i < len; i++) {
|
||||
if (typeof args[i] !== 'string') {
|
||||
args[i] = dumper.dump(args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
print( args.join(' ') );
|
||||
}
|
||||
};
|
||||
@ -33,4 +33,3 @@ process = {
|
||||
},
|
||||
argv: [__dirname + '/jsdoc.js'].concat(Array.prototype.slice.call(arguments, 0))
|
||||
};
|
||||
|
||||
107
node_modules/common/args.js
generated
vendored
107
node_modules/common/args.js
generated
vendored
@ -14,22 +14,24 @@
|
||||
*/
|
||||
exports.ArgParser = function() {
|
||||
this._options = [];
|
||||
}
|
||||
|
||||
this._shortNameIndex = {};
|
||||
this._longNameIndex = {};
|
||||
};
|
||||
|
||||
exports.ArgParser.prototype._getOptionByShortName = function(name) {
|
||||
for (var i = this._options.length; i--;) {
|
||||
if (this._options[i].shortName === name) { return this._options[i]; }
|
||||
if (this._shortNameIndex.hasOwnProperty(name)) {
|
||||
return this._options[this._shortNameIndex[name]];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
exports.ArgParser.prototype._getOptionByLongName = function(name) {
|
||||
for (var i = this._options.length; i--;) {
|
||||
if (this._options[i].longName === name) { return this._options[i]; }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this._longNameIndex.hasOwnProperty(name)) {
|
||||
return this._options[this._longNameIndex[name]];
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Provide information about a legal option.
|
||||
* @param {character} shortName The short name of the option, entered like: -T.
|
||||
@ -40,39 +42,47 @@
|
||||
* myParser.addOption('t', 'template', true, 'The path to the template.');
|
||||
* myParser.addOption('h', 'help', false, 'Show the help message.');
|
||||
*/
|
||||
exports.ArgParser.prototype.addOption = function(shortName, longName, hasValue, helpText) {
|
||||
this._options.push({shortName: shortName, longName: longName, hasValue: hasValue, helpText: helpText});
|
||||
exports.ArgParser.prototype.addOption = function(shortName, longName, hasValue, helpText, canHaveMultiple) {
|
||||
this._options.push({shortName: shortName, longName: longName, hasValue: hasValue, helpText: helpText, canHaveMultiple: (canHaveMultiple || false)});
|
||||
if (shortName) {
|
||||
this._shortNameIndex[shortName] = this._options.length - 1;
|
||||
}
|
||||
if (longName) {
|
||||
this._longNameIndex[longName] = this._options.length - 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Generate a summary of all the options with corresponding help text.
|
||||
@returns {string}
|
||||
*/
|
||||
exports.ArgParser.prototype.help = function() {
|
||||
var help = 'OPTIONS:\n',
|
||||
option;
|
||||
|
||||
var helpArr = ['OPTIONS:'],
|
||||
option, optionHelp;
|
||||
|
||||
for (var i = 0, leni = this._options.length; i < leni; i++) {
|
||||
option = this._options[i];
|
||||
|
||||
optionHelp = '\t';
|
||||
|
||||
if (option.shortName) {
|
||||
help += '-' + option.shortName + (option.longName? ' or ' : '');
|
||||
optionHelp += '-' + option.shortName + (option.longName ? ', ' : '');
|
||||
}
|
||||
|
||||
|
||||
if (option.longName) {
|
||||
help += '--' + option.longName;
|
||||
optionHelp += '--' + option.longName;
|
||||
}
|
||||
|
||||
|
||||
if (option.hasValue) {
|
||||
help += ' <value>';
|
||||
optionHelp += ' <value>';
|
||||
}
|
||||
|
||||
help += ' ' + option.helpText + '\n';
|
||||
|
||||
optionHelp += '\t\t' + option.helpText;
|
||||
helpArr.push(optionHelp);
|
||||
}
|
||||
|
||||
return help;
|
||||
|
||||
return helpArr.join('\n');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Get the options.
|
||||
@param {Array.<string>} args An array, like ['-x', 'hello']
|
||||
@ -82,22 +92,22 @@
|
||||
provided, or `true` if the option accepts no value.
|
||||
*/
|
||||
exports.ArgParser.prototype.parse = function(args, defaults) {
|
||||
var result = defaults || {};
|
||||
|
||||
var util = require('common/util'),
|
||||
result = defaults && util.mixin({}, 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,
|
||||
shortName = null,
|
||||
longName,
|
||||
name,
|
||||
value = null;
|
||||
|
||||
|
||||
// like -t
|
||||
if (arg.charAt(0) === '-') {
|
||||
|
||||
|
||||
// like: --template
|
||||
if (arg.charAt(1) === '-') {
|
||||
name = longName = arg.slice(2);
|
||||
@ -107,15 +117,15 @@
|
||||
name = shortName = arg.slice(1);
|
||||
option = this._getOptionByShortName(shortName);
|
||||
}
|
||||
|
||||
|
||||
if (option === null) {
|
||||
throw new Error( 'Unknown command line option found: ' + name );
|
||||
}
|
||||
|
||||
|
||||
if (option.hasValue) {
|
||||
value = next;
|
||||
i++;
|
||||
|
||||
|
||||
if (value === null || value.charAt(0) === '-') {
|
||||
throw new Error( 'Command line option requires a value: ' + name );
|
||||
}
|
||||
@ -123,18 +133,29 @@
|
||||
else {
|
||||
value = true;
|
||||
}
|
||||
|
||||
|
||||
if (option.longName && shortName) {
|
||||
name = option.longName;
|
||||
}
|
||||
|
||||
result[name] = value;
|
||||
|
||||
// Allow for multiple options of the same type to be present
|
||||
if (option.canHaveMultiple && result.hasOwnProperty(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;
|
||||
}
|
||||
};
|
||||
})();
|
||||
@ -341,4 +341,33 @@ 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.
|
||||
A plugin can stop the event from firing setting a ```preventDefault``` property.
|
||||
|
||||
Packaging JSDoc 3 Plugins
|
||||
----
|
||||
|
||||
The JSDoc 3 Jakefile has an ```install``` task that can be used to install a plugin
|
||||
into the jsdoc 3 installation. So running the following will install the plugin:
|
||||
|
||||
$>jake install[path/to/YourPluginFolder]
|
||||
|
||||
_note: on some systems (like MacOS 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
|
||||
|
||||
Basically everything is copied over into the jsdoc installation directory, the
|
||||
directory should contain anything you want to put there.
|
||||
@ -1,10 +1,10 @@
|
||||
/**
|
||||
@overview Demonstrate how to modify the source code before the parser sees it.
|
||||
@module plugins/comentConvert
|
||||
@module plugins/commentConvert
|
||||
@author Michael Mathews <micmath@gmail.com>
|
||||
*/
|
||||
|
||||
|
||||
|
||||
exports.handlers = {
|
||||
///
|
||||
/// Convert ///-style comments into jsdoc comments.
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
exports.handlers = {
|
||||
/**
|
||||
Translate HTML tags in descriptions into safe entities.
|
||||
Replaces <, & and newlines
|
||||
*/
|
||||
newDoclet: function(e) {
|
||||
if (e.doclet.description) {
|
||||
|
||||
@ -6,12 +6,12 @@
|
||||
|
||||
|
||||
exports.handlers = {
|
||||
///
|
||||
/// Remove rails tags from the source input (e.g. <% foo bar %>)
|
||||
/// @param e
|
||||
/// @param e.filename
|
||||
/// @param e.source
|
||||
///
|
||||
/**
|
||||
* Remove rails tags from the source input (e.g. <% foo bar %>)
|
||||
* @param e
|
||||
* @param e.filename
|
||||
* @param e.source
|
||||
*/
|
||||
beforeParse: function(e) {
|
||||
if (e.filename.match(/\.erb$/)) {
|
||||
e.source = e.source.replace(/<%.*%>/g, "");
|
||||
|
||||
@ -8,35 +8,36 @@ exports.handlers = {
|
||||
Support @source tag. Expected value like:
|
||||
{ "filename": "myfile.js", "lineno": 123 }
|
||||
Modifies the corresponding meta values on the given doclet.
|
||||
@source { "filename": "sourcetag.js", "lineno": 13 }
|
||||
*/
|
||||
newDoclet: function(e) {
|
||||
var tags = e.doclet.tags,
|
||||
tag,
|
||||
value;
|
||||
|
||||
|
||||
//console.log(e.doclet);
|
||||
// any user-defined tags in this doclet?
|
||||
// any user-defined tags in this doclet?
|
||||
if (typeof tags !== 'undefined') {
|
||||
// only interested in the @source tags
|
||||
tags = tags.filter(function($) {
|
||||
return $.title === 'source';
|
||||
});
|
||||
|
||||
|
||||
if (tags.length) {
|
||||
// take the first one
|
||||
tag = tags[0];
|
||||
|
||||
|
||||
try {
|
||||
value = JSON.parse(tag.value);
|
||||
}
|
||||
catch(e) {
|
||||
throw new Error('@source tag expects a valid JSON value, like { "filename": "myfile.js", "lineno": 123 }.');
|
||||
}
|
||||
|
||||
|
||||
!e.doclet.meta && (e.doclet.meta = {});
|
||||
e.doclet.meta.filename = value.filename || '';
|
||||
e.doclet.meta.lineno = value.lineno || '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
20
plugins/test/fixtures/railsTemplate.js.erb
vendored
Normal file
20
plugins/test/fixtures/railsTemplate.js.erb
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
@overview Strips the rails template tags from a js.erb file
|
||||
@module plugins/railsTemplate
|
||||
@author Jannon Frank <jannon@jannon.net>
|
||||
*/
|
||||
|
||||
|
||||
exports.handlers = {
|
||||
/**
|
||||
* Remove rails tags from the source input (e.g. <% foo bar %>)
|
||||
* @param e
|
||||
* @param e.filename
|
||||
* @param e.source
|
||||
*/
|
||||
beforeParse: function(e) {
|
||||
if (e.filename.match(/\.erb$/)) {
|
||||
e.source = e.source.replace(/<%.*%> /g, "");
|
||||
}
|
||||
}
|
||||
};
|
||||
13
plugins/test/specs/commentConvert.js
Normal file
13
plugins/test/specs/commentConvert.js
Normal file
@ -0,0 +1,13 @@
|
||||
describe("commentConvert plugin", function() {
|
||||
var parser = new (require("jsdoc/src/parser")).Parser(),
|
||||
plugin = require('plugins/commentConvert'),
|
||||
docSet;
|
||||
|
||||
installPlugins(['plugins/commentConvert'], parser);
|
||||
docSet = jasmine.getDocSetFromFile("plugins/commentConvert.js", parser);
|
||||
|
||||
it("should convert '///-style comments into jsdoc comments", function() {
|
||||
var doclet = docSet.getByLongname("module:plugins/commentConvert.handlers.beforeParse");
|
||||
expect(doclet.length).toEqual(1);
|
||||
});
|
||||
});
|
||||
13
plugins/test/specs/escapeHtml.js
Normal file
13
plugins/test/specs/escapeHtml.js
Normal file
@ -0,0 +1,13 @@
|
||||
describe("escapeHtml plugin", function() {
|
||||
var parser = new (require("jsdoc/src/parser")).Parser(),
|
||||
plugin = require('plugins/escapeHtml'),
|
||||
docSet;
|
||||
|
||||
installPlugins(['plugins/escapeHtml'], parser);
|
||||
docSet = jasmine.getDocSetFromFile("plugins/escapeHtml.js", parser);
|
||||
|
||||
it("should escape '&', '<' and newlines in doclet descriptions", function() {
|
||||
var doclet = docSet.getByLongname("module:plugins/escapeHtml.handlers.newDoclet");
|
||||
expect(doclet[0].description).toEqual("Translate HTML tags in descriptions into safe entities.<br> Replaces <, & and newlines");
|
||||
});
|
||||
});
|
||||
22
plugins/test/specs/markdown.js
Normal file
22
plugins/test/specs/markdown.js
Normal file
@ -0,0 +1,22 @@
|
||||
/**
|
||||
@overview Translate doclet descriptions from MarkDown into HTML.
|
||||
@module plugins/markdown
|
||||
@author Michael Mathews <micmath@gmail.com>
|
||||
*/
|
||||
|
||||
var mdParser = require('evilstreak/markdown');
|
||||
|
||||
exports.handlers = {
|
||||
/**
|
||||
Translate markdown syntax in a new doclet's description into HTML. Is run
|
||||
by JSDoc 3 whenever a "newDoclet" event fires.
|
||||
*/
|
||||
newDoclet: function(e) {
|
||||
if (e.doclet.description) {
|
||||
e.doclet.description = mdParser.toHTML(e.doclet.description)
|
||||
.replace( /&/g, "&" ) // because markdown escapes these
|
||||
.replace( /</g, "<" )
|
||||
.replace( />/g, ">" );
|
||||
}
|
||||
}
|
||||
};
|
||||
15
plugins/test/specs/railsTemplate.js
Normal file
15
plugins/test/specs/railsTemplate.js
Normal file
@ -0,0 +1,15 @@
|
||||
describe("railsTemplate plugin", function() {
|
||||
var parser = new (require("jsdoc/src/parser")).Parser(),
|
||||
plugin = require('plugins/railsTemplate');
|
||||
|
||||
|
||||
installPlugins(['plugins/railsTemplate'], parser);
|
||||
require('jsdoc/src/handlers').attachTo(parser);
|
||||
|
||||
it("should remove <% %> rails template tags from the source of *.erb files", function() {
|
||||
var path = require("path"),
|
||||
docSet = parser.parse([path.join(__dirname, "plugins/test/fixtures/railsTemplate.js.erb")]);
|
||||
|
||||
expect(docSet[2].description).toEqual("Remove rails tags from the source input (e.g. )");
|
||||
});
|
||||
});
|
||||
13
plugins/test/specs/shout.js
Normal file
13
plugins/test/specs/shout.js
Normal file
@ -0,0 +1,13 @@
|
||||
describe("shout plugin", function() {
|
||||
var parser = new (require("jsdoc/src/parser")).Parser(),
|
||||
plugin = require('plugins/shout'),
|
||||
docSet;
|
||||
|
||||
installPlugins(['plugins/shout'], parser);
|
||||
docSet = jasmine.getDocSetFromFile("plugins/shout.js", parser);
|
||||
|
||||
it("should make the description uppercase", function() {
|
||||
var doclet = docSet.getByLongname("module:plugins/shout.handlers.newDoclet");
|
||||
expect(doclet[0].description).toEqual("MAKE YOUR DESCRIPTIONS MORE SHOUTIER.");
|
||||
});
|
||||
});
|
||||
15
plugins/test/specs/sourcetag.js
Normal file
15
plugins/test/specs/sourcetag.js
Normal file
@ -0,0 +1,15 @@
|
||||
describe("sourcetag plugin", function() {
|
||||
var parser = new (require("jsdoc/src/parser")).Parser(),
|
||||
plugin = require('plugins/sourcetag'),
|
||||
docSet;
|
||||
|
||||
installPlugins(['plugins/sourcetag'], parser);
|
||||
docSet = jasmine.getDocSetFromFile("plugins/sourcetag.js", parser);
|
||||
|
||||
it("should set the lineno and filename of the doclet's meta property", function() {
|
||||
var doclet = docSet.getByLongname("module:plugins/sourcetag.handlers.newDoclet");
|
||||
expect(doclet[0].meta).toBeDefined();
|
||||
expect(doclet[0].meta.filename).toEqual("sourcetag.js");
|
||||
expect(doclet[0].meta.lineno).toEqual(13);
|
||||
});
|
||||
});
|
||||
@ -7,12 +7,17 @@ exports.readFileSync = function(filename, encoding) {
|
||||
var readdirSync = exports.readdirSync = function(path) {
|
||||
var dir,
|
||||
files;
|
||||
|
||||
|
||||
dir = new java.io.File(path);
|
||||
if (!dir.directory) { return [String(dir)]; }
|
||||
|
||||
|
||||
files = dir.list();
|
||||
|
||||
|
||||
//Convert files to Javascript strings so they play nice with node modules
|
||||
files = files.map(function(fileName) {
|
||||
return String(fileName);
|
||||
});
|
||||
|
||||
return files;
|
||||
};
|
||||
|
||||
@ -24,20 +29,20 @@ var ls = exports.ls = function(dir, recurse, _allFiles, _path) {
|
||||
_allFiles = [];
|
||||
_path = [dir];
|
||||
}
|
||||
|
||||
|
||||
if (_path.length === 0) { return _allFiles; }
|
||||
if (typeof recurse === 'undefined') { recurse = 1; }
|
||||
|
||||
|
||||
if ( stat(dir).isFile(dir) ) {
|
||||
files = [dir];
|
||||
}
|
||||
else {
|
||||
files = readdirSync(dir);
|
||||
}
|
||||
|
||||
|
||||
for (var f = 0, lenf = files.length; f < lenf; f++) {
|
||||
file = String(files[f]);
|
||||
|
||||
|
||||
if (file.match(/^\.[^\.\/\\]/)) { continue; } // skip dot files
|
||||
|
||||
if ((new java.io.File(_path.join('/') + '/' + file)).list()) { // it's a directory
|
||||
@ -48,7 +53,7 @@ var ls = exports.ls = function(dir, recurse, _allFiles, _path) {
|
||||
}
|
||||
_path.pop();
|
||||
}
|
||||
else { // it's a file
|
||||
else { // it's a file
|
||||
_allFiles.push(
|
||||
(_path.join('/') + '/' + file).replace(/[\/\\]+/g, '/')
|
||||
);
|
||||
@ -58,21 +63,21 @@ var ls = exports.ls = function(dir, recurse, _allFiles, _path) {
|
||||
return _allFiles;
|
||||
};
|
||||
|
||||
var stat = exports.stat = function(path, encoding) {
|
||||
var f = new java.io.File(path)
|
||||
var stat = exports.stat = exports.statSync = function(path, encoding) {
|
||||
var f = new java.io.File(path);
|
||||
return {
|
||||
isFile: function() {
|
||||
return f.isFile();
|
||||
},
|
||||
isDir: function() {
|
||||
isDirectory: function() {
|
||||
return f.isDirectory();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
exports.mkPath = function(/**Array*/ path) {
|
||||
if (path.constructor != Array) path = path.split(/[\\\/]/);
|
||||
if (path.constructor != Array){path = path.split(/[\\\/]/);}
|
||||
var make = "";
|
||||
for (var i = 0, l = path.length; i < l; i++) {
|
||||
make += path[i] + '/';
|
||||
@ -104,25 +109,25 @@ function exists(path) {
|
||||
|
||||
var toDir = exports.toDir = function(path) {
|
||||
var f = new java.io.File(path);
|
||||
|
||||
|
||||
if (f.isDirectory()){
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
var parts = path.split(/[\\\/]/);
|
||||
parts.pop();
|
||||
|
||||
|
||||
return parts.join('/');
|
||||
};
|
||||
|
||||
exports.copyFile = function(inFile, outDir, fileName) {
|
||||
if (fileName == null) fileName = toFile(inFile);
|
||||
|
||||
if (fileName == null){fileName = toFile(inFile);}
|
||||
|
||||
outDir = toDir(outDir);
|
||||
|
||||
|
||||
var inFile = new java.io.File(inFile);
|
||||
var outFile = new java.io.File(outDir+'/'+fileName);
|
||||
|
||||
|
||||
var bis = new Packages.java.io.BufferedInputStream(new Packages.java.io.FileInputStream(inFile), 4096);
|
||||
var bos = new Packages.java.io.BufferedOutputStream(new Packages.java.io.FileOutputStream(outFile), 4096);
|
||||
var theChar;
|
||||
@ -136,7 +141,7 @@ exports.copyFile = function(inFile, outDir, fileName) {
|
||||
var toFile = exports.toFile = function(path) {
|
||||
var parts = path.split(/[\\\/]/);
|
||||
return parts.pop();
|
||||
}
|
||||
};
|
||||
|
||||
exports.writeFileSync = function(filename, data, encoding) {
|
||||
encoding = encoding || 'utf-8';
|
||||
@ -147,7 +152,7 @@ exports.writeFileSync = function(filename, data, encoding) {
|
||||
encoding
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
try {
|
||||
out.write(data);
|
||||
}
|
||||
|
||||
@ -27,9 +27,13 @@ argParser.addOption('X', 'explain', false, 'Dump all found doclet internals
|
||||
argParser.addOption('q', 'query', true, 'Provide a querystring to define custom variable names/values to add to the options hash.');
|
||||
argParser.addOption('u', 'tutorials', true, 'Directory in which JSDoc should search for tutorials.');
|
||||
|
||||
//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?
|
||||
|
||||
// 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?
|
||||
//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, 'coffee', false, 'load coffee-script which allows execution .coffee files');
|
||||
|
||||
/**
|
||||
Set the options for this app.
|
||||
@ -38,13 +42,13 @@ argParser.addOption('u', 'tutorials', true, 'Directory in which JSDoc should
|
||||
*/
|
||||
exports.parse = function(args) {
|
||||
args = args || [];
|
||||
|
||||
|
||||
if (typeof args === 'string' || args.constructor === String) {
|
||||
args = (''+args).split(/\s+/g);
|
||||
}
|
||||
|
||||
|
||||
ourOptions = argParser.parse(args, defaults);
|
||||
|
||||
|
||||
return ourOptions;
|
||||
}
|
||||
|
||||
|
||||
@ -183,5 +183,5 @@ exports.attachTo = function(parser) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ exports.Parser = function() {
|
||||
}
|
||||
};
|
||||
this._visitors = [];
|
||||
}
|
||||
};
|
||||
require('common/util').mixin(exports.Parser.prototype, require('common/events'));
|
||||
|
||||
/**
|
||||
@ -72,7 +72,7 @@ exports.Parser.prototype.parse = function(sourceFiles, encoding) {
|
||||
}
|
||||
|
||||
return this._resultBuffer;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {Array<Doclet>} The accumulated results of any calls to parse.
|
||||
|
||||
@ -1,17 +1,146 @@
|
||||
|
||||
var isWindows = java.lang.System.getProperty("os.name").toLowerCase().contains("windows");
|
||||
var fileSeparator = java.lang.System.getProperty("file.separator");
|
||||
|
||||
/**
|
||||
* Returns everything on a path except for the last item
|
||||
* e.g. if the path was 'path/to/something', the return value would be 'path/to'
|
||||
*/
|
||||
exports.basename = function(path) {
|
||||
var parts = path.split('/');
|
||||
var parts = path.split(fileSeparator);
|
||||
parts.pop();
|
||||
path = parts.join('/');
|
||||
path = parts.join(fileSeparator);
|
||||
return path;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the last item on a path
|
||||
*/
|
||||
exports.filename = function(path) {
|
||||
var parts = path.split(fileSeparator);
|
||||
if (parts.length > 0) {
|
||||
return parts.pop();
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.existsSync = function(path) {
|
||||
var file = new java.io.File(path);
|
||||
|
||||
|
||||
if (file.isFile()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
};
|
||||
};
|
||||
|
||||
//Code below taken from node
|
||||
|
||||
//resolves . and .. elements in a path array with directory names there
|
||||
//must be no slashes, empty elements, or device names (c:\) in the array
|
||||
//(so also no leading and trailing slashes - it does not distinguish
|
||||
//relative and absolute paths)
|
||||
function normalizeArray(parts, allowAboveRoot) {
|
||||
// if the path tries to go above the root, `up` ends up > 0
|
||||
var up = 0;
|
||||
for ( var i = parts.length - 1; i >= 0; i--) {
|
||||
var last = parts[i];
|
||||
if (last == '.') {
|
||||
parts.splice(i, 1);
|
||||
} else if (last === '..') {
|
||||
parts.splice(i, 1);
|
||||
up++;
|
||||
} else if (up) {
|
||||
parts.splice(i, 1);
|
||||
up--;
|
||||
}
|
||||
}
|
||||
|
||||
// if the path is allowed to go above the root, restore leading ..s
|
||||
if (allowAboveRoot) {
|
||||
for (; up--; up) {
|
||||
parts.unshift('..');
|
||||
}
|
||||
}
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
if (isWindows) {
|
||||
// Regex to split a windows path into three parts: [*, device, slash,
|
||||
// tail] windows-only
|
||||
var splitDeviceRe =
|
||||
/^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?([\\\/])?([\s\S]*?)$/;
|
||||
|
||||
// windows version
|
||||
exports.normalize = function(path) {
|
||||
var result = splitDeviceRe.exec(path),
|
||||
device = result[1] || '',
|
||||
isUnc = device && device.charAt(1) !== ':',
|
||||
isAbsolute = !!result[2] || isUnc, // UNC paths are always absolute
|
||||
tail = result[3],
|
||||
trailingSlash = /[\\\/]$/.test(tail);
|
||||
|
||||
// Normalize the tail path
|
||||
tail = normalizeArray(tail.split(/[\\\/]+/).filter(function(p) {
|
||||
return !!p;
|
||||
}), !isAbsolute).join('\\');
|
||||
|
||||
if (!tail && !isAbsolute) {
|
||||
tail = '.';
|
||||
}
|
||||
if (tail && trailingSlash) {
|
||||
tail += '\\';
|
||||
}
|
||||
|
||||
return device + (isAbsolute ? '\\' : '') + tail;
|
||||
};
|
||||
|
||||
//windows version
|
||||
exports.join = function() {
|
||||
function f(p) {
|
||||
return p && typeof p === 'string';
|
||||
}
|
||||
|
||||
var paths = Array.prototype.slice.call(arguments, 0).filter(f);
|
||||
var joined = paths.join('\\');
|
||||
|
||||
// Make sure that the joined path doesn't start with two slashes
|
||||
// - it will be mistaken for an unc path by normalize() -
|
||||
// unless the paths[0] also starts with two slashes
|
||||
if (/^[\\\/]{2}/.test(joined) && !/^[\\\/]{2}/.test(paths[0])) {
|
||||
joined = joined.slice(1);
|
||||
}
|
||||
|
||||
return exports.normalize(joined);
|
||||
};
|
||||
} else {
|
||||
// path.normalize(path)
|
||||
// posix version
|
||||
exports.normalize = function(path) {
|
||||
var isAbsolute = path.charAt(0) === '/',
|
||||
trailingSlash = path.slice(-1) === '/';
|
||||
|
||||
// Normalize the path
|
||||
path = normalizeArray(path.split('/').filter(function(p) {
|
||||
return !!p;
|
||||
}), !isAbsolute).join('/');
|
||||
|
||||
if (!path && !isAbsolute) {
|
||||
path = '.';
|
||||
}
|
||||
if (path && trailingSlash) {
|
||||
path += '/';
|
||||
}
|
||||
|
||||
return (isAbsolute ? '/' : '') + path;
|
||||
};
|
||||
|
||||
// posix version
|
||||
exports.join = function() {
|
||||
var paths = Array.prototype.slice.call(arguments, 0);
|
||||
return exports.normalize(paths.filter(function(p, index) {
|
||||
return p && typeof p === 'string';
|
||||
}).join('/'));
|
||||
};
|
||||
}
|
||||
@ -1,7 +1,45 @@
|
||||
From the project root, run the following command in the terminal:
|
||||
Testing JSDoc 3
|
||||
===============
|
||||
|
||||
java -jar lib/js.jar -modules rhino_modules -modules node_modules jsdoc.js -T
|
||||
Running Tests
|
||||
-------------
|
||||
|
||||
TODO:
|
||||
Running tests is easy. Just change your working directory to the jsdoc folder
|
||||
and run the following command on Windows:
|
||||
|
||||
More info for contributors about how tests work and about plugin/template tests
|
||||
jsdoc -T
|
||||
|
||||
... or on a Max OSX or *nix platform:
|
||||
|
||||
./jsdoc -T
|
||||
|
||||
If you can't get the short-form commands to work, try invoking Java directly:
|
||||
|
||||
java -cp lib/js.jar org.mozilla.javascript.tools.shell.Main -opt -1 \
|
||||
-modules node_modules -modules rhino_modules -modules . \
|
||||
jsdoc.js -T
|
||||
|
||||
Writing Tests
|
||||
-------------
|
||||
|
||||
Adding tests is pretty easy, too. You can write tests for jsdoc itself (to
|
||||
make sure tags and the parser, etc. are working properly), tests for plugins, and/or
|
||||
tests for templates.
|
||||
|
||||
JSDoc 3 uses Jasmine (https://github.com/pivotal/jasmine) as its testing framework.
|
||||
Take a look at that project's wiki for documentation on writing tests in general.
|
||||
|
||||
### Tests for JSDoc
|
||||
|
||||
Take a look at the files in the ```test``` directory for many examples of
|
||||
writing tests for JSDoc itself. the ```test\fixtures``` directory hold fixtures
|
||||
for use in the tests and the ```test\specs``` directory holds the tests themselves.
|
||||
|
||||
### Tests for plugins
|
||||
|
||||
Tests for plugins are found in ```plugins\test``` directory. Plugins containing
|
||||
tests that were installed with the Jakefile install task will be run automatically.
|
||||
|
||||
### Tests for templates
|
||||
|
||||
TODO
|
||||
56
test/async-callback.js
Normal file
56
test/async-callback.js
Normal file
@ -0,0 +1,56 @@
|
||||
(function() {
|
||||
var withoutAsync = {};
|
||||
|
||||
["it", "beforeEach", "afterEach"].forEach(function(jasmineFunction) {
|
||||
withoutAsync[jasmineFunction] = jasmine.Env.prototype[jasmineFunction];
|
||||
return jasmine.Env.prototype[jasmineFunction] = function() {
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
var timeout = null;
|
||||
if (isLastArgumentATimeout(args)) {
|
||||
timeout = args.pop();
|
||||
}
|
||||
if (isLastArgumentAnAsyncSpecFunction(args))
|
||||
{
|
||||
var specFunction = args.pop();
|
||||
args.push(function() {
|
||||
return asyncSpec(specFunction, this, timeout);
|
||||
});
|
||||
}
|
||||
return withoutAsync[jasmineFunction].apply(this, args);
|
||||
};
|
||||
});
|
||||
|
||||
function isLastArgumentATimeout(args)
|
||||
{
|
||||
return args.length > 0 && (typeof args[args.length-1]) === "number";
|
||||
}
|
||||
|
||||
function isLastArgumentAnAsyncSpecFunction(args)
|
||||
{
|
||||
return args.length > 0 && (typeof args[args.length-1]) === "function" && args[args.length-1].length > 0;
|
||||
}
|
||||
|
||||
function asyncSpec(specFunction, spec, timeout) {
|
||||
if (timeout == null){timeout = jasmine.DEFAULT_TIMEOUT_INTERVAL || 1000;}
|
||||
var done = false;
|
||||
spec.runs(function() {
|
||||
try {
|
||||
return specFunction(function(error) {
|
||||
done = true;
|
||||
if (error != null) {
|
||||
return spec.fail(error);
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
done = true;
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
return spec.waitsFor(function() {
|
||||
if (done === true) {
|
||||
return true;
|
||||
}
|
||||
}, "spec to complete", timeout);
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
@ -1,4 +0,0 @@
|
||||
// Simple inheritance model with correct constructor
|
||||
function Test() {}
|
||||
function Test2() { Test.call(this); }
|
||||
Test2.prototype = Object.create(Test.prototype, {constructor: {value: Test2}});
|
||||
@ -1,17 +0,0 @@
|
||||
Call(
|
||||
{
|
||||
methodA: function()
|
||||
{
|
||||
this.id = this.createUUID();
|
||||
},
|
||||
|
||||
valueOf: function()
|
||||
{
|
||||
return this.id;
|
||||
},
|
||||
|
||||
toString: function()
|
||||
{
|
||||
return this.id;
|
||||
}
|
||||
});
|
||||
22
test/fixtures/objectpropertykeys.js
vendored
Normal file
22
test/fixtures/objectpropertykeys.js
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
Call(
|
||||
{
|
||||
methodA: function()
|
||||
{
|
||||
this.id = this.createUUID();
|
||||
},
|
||||
|
||||
valueOf: function()
|
||||
{
|
||||
return this.id;
|
||||
},
|
||||
|
||||
toString: function()
|
||||
{
|
||||
return this.id;
|
||||
}
|
||||
});
|
||||
|
||||
//Simple inheritance model with correct constructor
|
||||
function Test() {}
|
||||
function Test2() { Test.call(this); }
|
||||
Test2.prototype = Object.create(Test.prototype, {constructor: {value: Test2}});
|
||||
10
test/fixtures/plugins.js
vendored
Normal file
10
test/fixtures/plugins.js
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* @name virtual
|
||||
*/
|
||||
|
||||
var foo = "bar";
|
||||
|
||||
/**
|
||||
* @foo bar
|
||||
*/
|
||||
var test = "tada";
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user