diff --git a/Jake/templates/package.json.tmpl b/Jake/templates/package.json.tmpl
index d5159473..4d6773d7 100644
--- a/Jake/templates/package.json.tmpl
+++ b/Jake/templates/package.json.tmpl
@@ -28,7 +28,7 @@
"underscore": "1.4.2",
"wrench": "1.3.9"
},
- "bin": "./nodejs/bin/jsdoc",
+ "bin": "./node/bin/jsdoc",
"bugs": "https://github.com/jsdoc3/jsdoc/issues",
"author": {
"name": "Michael Mathews",
diff --git a/jsdoc.js b/jsdoc.js
index b1f27885..9b2b614a 100644
--- a/jsdoc.js
+++ b/jsdoc.js
@@ -72,9 +72,9 @@ require('lib/jsdoc/util/global').env = {
// initialize the environment for the current JavaScript VM
(function(args) {
- var vm = require('jsdoc/util/vm').vm;
+ var runtime = require('jsdoc/util/runtime').getRuntime();
// TODO: may need to move this file to support Node.js
- require('initialize')[vm](args);
+ require('initialize')[runtime](args);
})( Array.prototype.slice.call(arguments, 0) );
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
@@ -87,7 +87,11 @@ require('lib/jsdoc/util/global').env = {
require('lib/jsdoc/util/global').app = {
jsdoc: {
scanner: new (require('jsdoc/src/scanner').Scanner)(),
- parser: new (require('jsdoc/src/parser').Parser)(),
+ // TODO: allow the config file to specify the parser module
+ parser: (function() {
+ var modulePath = require('jsdoc/util/runtime').getModulePath('jsdoc/src/parser');
+ return new ( require(modulePath) ).Parser();
+ })(),
name: require('jsdoc/name')
}
};
diff --git a/lib/jsdoc/fs.js b/lib/jsdoc/fs.js
index ee365a8d..1993807a 100644
--- a/lib/jsdoc/fs.js
+++ b/lib/jsdoc/fs.js
@@ -4,11 +4,11 @@
*/
var fs = exports.fs = require('fs');
-var vm = require('jsdoc/util/vm');
+var runtime = require('jsdoc/util/runtime');
// export the VM-specific implementations of the extra methods
// TODO: document extra methods here
-var extras = vm.getModule('fs');
+var extras = require( runtime.getModulePath('fs') );
Object.keys(extras).forEach(function(extra) {
exports[extra] = extras[extra];
});
diff --git a/lib/jsdoc/path.js b/lib/jsdoc/path.js
index 4ddb031d..0be64476 100644
--- a/lib/jsdoc/path.js
+++ b/lib/jsdoc/path.js
@@ -5,7 +5,7 @@
var fs = require('fs');
var path = require('path');
-var vm = require('jsdoc/util/vm');
+var runtime = require('jsdoc/util/runtime');
function prefixReducer(previousPath, current) {
@@ -71,7 +71,7 @@ exports.commonPrefix = function(paths) {
* @param {string} path The path to convert.
* @return {string} A URI that meets the operating system's requirements, or the original path.
*/
-var pathToUri = vm.getModule('jsdoc').pathToUri;
+var pathToUri = require( runtime.getModulePath('jsdoc') ).pathToUri;
// TODO: do we need this? if so, any way to stop exporting it?
/**
@@ -82,7 +82,7 @@ var pathToUri = vm.getModule('jsdoc').pathToUri;
* @param {string} uri The URI to convert.
* @return {string} A path that meets the operating system's requirements.
*/
-exports._uriToPath = vm.getModule('jsdoc').uriToPath;
+exports._uriToPath = require( runtime.getModulePath('jsdoc') ).uriToPath;
/**
* Retrieve the fully qualified path to the requested resource.
diff --git a/lib/jsdoc/plugins.js b/lib/jsdoc/plugins.js
index 5e2637bc..963f0a97 100644
--- a/lib/jsdoc/plugins.js
+++ b/lib/jsdoc/plugins.js
@@ -36,10 +36,15 @@ exports.installPlugins = function(plugins, p) {
plugin.defineTags(dictionary);
}
- //...add a node visitor
+ //...add a Rhino node visitor (deprecated in JSDoc 3.3)
if (plugin.nodeVisitor) {
parser.addNodeVisitor(plugin.nodeVisitor);
}
+
+ //...add a Mozilla Parser API node visitor
+ if (plugin.astNodeVisitor) {
+ parser.addAstNodeVisitor(plugin.astNodeVisitor);
+ }
}
}
};
diff --git a/lib/jsdoc/src/parser.js b/lib/jsdoc/src/parser.js
index 01e958f6..f0d02031 100644
--- a/lib/jsdoc/src/parser.js
+++ b/lib/jsdoc/src/parser.js
@@ -24,13 +24,33 @@ var SCHEMA = 'javascript:';
* @example
Create a new parser.
* var jsdocParser = new (require('jsdoc/src/parser').Parser)();
*/
-var Parser = exports.Parser = function() {
+var Parser = exports.Parser = function(builderInstance, visitorInstance, walkerInstance) {
this.clear();
- // TODO: require the appropriate AstBuilder based on a config setting
- this._astBuilder = new (require('jsdoc/src/rhino/astbuilder'))();
- this._visitor = new (require('jsdoc/src/visitor'))(this);
- this._walker = new (require('jsdoc/src/walker')).Walker();
+ // TODO: replace with a runtime-agnostic default builder
+ var runtime = require('jsdoc/util/runtime');
+ this._astBuilder = builderInstance ||
+ new ( require(runtime.getModulePath('jsdoc/src/astbuilder')) )();
+ this._visitor = visitorInstance || new (require('jsdoc/src/visitor')).Visitor(this);
+ this._walker = walkerInstance || new (require('jsdoc/src/walker')).Walker();
+
+ Object.defineProperties(this, {
+ astBuilder: {
+ get: function() {
+ return this._astBuilder;
+ }
+ },
+ visitor: {
+ get: function() {
+ return this._visitor;
+ }
+ },
+ walker: {
+ get: function() {
+ return this._walker;
+ }
+ }
+ });
};
util.inherits(Parser, require('events').EventEmitter);
@@ -42,12 +62,6 @@ Parser.prototype.clear = function() {
meta: {}
}
};
- this._visitor = null;
-};
-
-// TODO: docs
-Parser.prototype.getVisitor = function() {
- return this._visitor;
};
// TODO: docs
@@ -134,9 +148,6 @@ Parser.prototype.fireProcessingComplete = function(doclets) {
};
// TODO: docs
-/**
- * @returns {Array} The accumulated results of any calls to parse.
- */
Parser.prototype.results = function() {
return this._resultBuffer;
};
@@ -149,20 +160,14 @@ Parser.prototype.addResult = function(o) {
this._resultBuffer.push(o);
};
-// TODO: update docs
-/**
- * Adds a node visitor to use in parsing
- */
-Parser.prototype.addNodeVisitor = function(visitor) {
- this._visitor._addRhinoNodeVisitor(visitor);
+// TODO: docs
+Parser.prototype.addAstNodeVisitor = function(visitor) {
+ this._visitor.addAstNodeVisitor(visitor);
};
// TODO: docs
-/**
- * Get the node visitors used in parsing
- */
-Parser.prototype.getVisitors = function() {
- return this._visitor._getRhinoNodeVisitors();
+Parser.prototype.getAstNodeVisitors = function() {
+ return this._visitor.getAstNodeVisitors();
};
// TODO: docs
@@ -424,7 +429,6 @@ Parser.prototype.getBasename = function(name) {
if (name !== undefined) {
return name.replace(/^([$a-z_][$a-z_0-9]*).*?$/i, '$1');
}
- return name;
};
// TODO: docs
@@ -433,7 +437,6 @@ function definedInScope(doclet, basename) {
hasOwnProp.call(doclet.meta.vars, basename);
}
-
// TODO: docs
/**
* Given a node, determine what the node is a member of.
diff --git a/lib/jsdoc/src/visitor.js b/lib/jsdoc/src/visitor.js
index 51961903..7b7f3f28 100644
--- a/lib/jsdoc/src/visitor.js
+++ b/lib/jsdoc/src/visitor.js
@@ -68,13 +68,11 @@ function JsdocCommentFound(comment, filename) {
// TODO: docs
-var Visitor = module.exports = function(parser) {
+var Visitor = exports.Visitor = function(parser) {
this._parser = parser;
// Mozilla Parser API node visitors added by plugins
this._nodeVisitors = [];
- // Rhino node visitors added by plugins (deprecated in JSDoc 3.3)
- this._rhinoNodeVisitors = [];
// built-in visitors
this._visitors = [
this.visitNodeComments,
@@ -83,12 +81,12 @@ var Visitor = module.exports = function(parser) {
};
// TODO: docs
-Visitor.prototype.addNodeVisitor = function(visitor) {
+Visitor.prototype.addAstNodeVisitor = function(visitor) {
this._nodeVisitors.push(visitor);
};
// TODO: docs
-Visitor.prototype.removeNodeVisitor = function(visitor) {
+Visitor.prototype.removeAstNodeVisitor = function(visitor) {
var idx = this._nodeVisitors.indexOf(visitor);
if (idx !== -1) {
this._nodeVisitors.splice(idx, 1);
@@ -96,20 +94,10 @@ Visitor.prototype.removeNodeVisitor = function(visitor) {
};
// TODO: docs
-Visitor.prototype.getNodeVisitors = function() {
+Visitor.prototype.getAstNodeVisitors = function() {
return this._nodeVisitors;
};
-// TODO: docs (deprecated)
-Visitor.prototype._addRhinoNodeVisitor = function(visitor) {
- this._rhinoNodeVisitors.push(visitor);
-};
-
-// TODO: docs (deprecated)
-Visitor.prototype._getRhinoNodeVisitors = function() {
- return this._rhinoNodeVisitors;
-};
-
// TODO: docs; visitor signature is (node, parser, filename)
Visitor.prototype.visit = function(node, filename) {
var i;
@@ -203,18 +191,10 @@ Visitor.prototype.visitNodeComments = function(node, parser, filename) {
// TODO: docs
Visitor.prototype.visitNode = function(node, parser, filename) {
- var e = this.makeSymbolFoundEvent(node, parser, filename);
+ var i;
+ var l;
- function callNodeVisitors(visitors, nodeToVisit) {
- if (visitors) {
- for (var i = 0, l = visitors.length; i < l; i++) {
- visitors[i].visitNode(nodeToVisit, e, parser, filename);
- if (e.stopPropagation) {
- break;
- }
- }
- }
- }
+ var e = this.makeSymbolFoundEvent(node, parser, filename);
if (!node.nodeId) {
Object.defineProperty(node, 'nodeId', {
@@ -222,9 +202,13 @@ Visitor.prototype.visitNode = function(node, parser, filename) {
});
}
- callNodeVisitors(this._nodeVisitors, node);
- if (e.code && e.code.node) {
- callNodeVisitors(this._rhinoNodeVisitors, e.code.node); // TODO: check this!!
+ if (this._nodeVisitors && this._nodeVisitors.length) {
+ for (i = 0, l = this._nodeVisitors.length; i < l; i++) {
+ this._nodeVisitors[i].visitNode(node, e, parser, filename);
+ if (e.stopPropagation) {
+ break;
+ }
+ }
}
if (!e.preventDefault && e.comment && isValidJsdoc(e.comment)) {
@@ -234,7 +218,7 @@ Visitor.prototype.visitNode = function(node, parser, filename) {
// add the node to the parser's lookup table
parser.addDocletRef(e);
- for (var i = 0, l = e.finishers.length; i < l; i++) {
+ for (i = 0, l = e.finishers.length; i < l; i++) {
e.finishers[i].call(parser, e);
}
diff --git a/lib/jsdoc/util/include.js b/lib/jsdoc/util/include.js
index 54d1efa4..a877a1f9 100644
--- a/lib/jsdoc/util/include.js
+++ b/lib/jsdoc/util/include.js
@@ -1,5 +1,5 @@
var path = require('path');
-var vm = require('jsdoc/util/vm');
+var runtime = require('jsdoc/util/runtime');
/**
* Read and execute a JavaScript file in global scope.
@@ -11,7 +11,7 @@ module.exports = function(filepath) {
filepath = path.resolve(__dirname, filepath);
try {
- vm.getModule('jsdoc/util/include')(filepath);
+ require( runtime.getModulePath('jsdoc/util/include') )(filepath);
}
catch (e) {
console.log('Cannot include ' + filepath + ': ' + e);
diff --git a/lib/jsdoc/util/vm.js b/lib/jsdoc/util/runtime.js
similarity index 53%
rename from lib/jsdoc/util/vm.js
rename to lib/jsdoc/util/runtime.js
index eb7048b1..ce3c0786 100644
--- a/lib/jsdoc/util/vm.js
+++ b/lib/jsdoc/util/runtime.js
@@ -1,16 +1,18 @@
/*global Packages: true */
/**
- * Helper functions to enable JSDoc to run on multiple JavaScript virtual machines.
- * @module jsdoc/util/vm
+ * Helper functions to enable JSDoc to run on multiple JavaScript runtimes.
+ *
+ * @module jsdoc/util/runtime
+ * @private
*/
var os = require('os');
// These strings represent directory names; do not modify them!
/** @private */
-const RHINO = exports.RHINO = 'rhino';
+var RHINO = exports.RHINO = 'rhino';
/** @private */
-const NODEJS = exports.NODEJS = 'nodejs';
+var NODE = exports.NODE = 'node';
// hacky conversion from Windows path to URI
function pathToUri(filepath) {
@@ -33,51 +35,63 @@ function pathToUri(filepath) {
}
/**
- * The JavaScript VM that is executing JSDoc:
+ * The JavaScript runtime that is executing JSDoc:
*
- * + `module:jsdoc/util/vm.RHINO`: Mozilla Rhino.
- * + `module:jsdoc/util/vm.NODEJS`: Node.js (not currently supported).
+ * + `module:jsdoc/util/runtime~RHINO`: Mozilla Rhino.
+ * + `module:jsdoc/util/runtime~NODE`: Node.js (not currently supported).
+ *
+ * @private
*/
-var vm = exports.vm = (function() {
+var runtime = (function() {
if (Packages && typeof Packages === 'object' &&
Object.prototype.toString.call(Packages) === '[object JavaPackage]') {
return RHINO;
} else if ( require && require.main && module && (require.main === module) ) {
- return NODEJS;
+ return NODE;
} else {
- // unknown VM
- throw new Error('Unable to identify the current JavaScript VM.');
+ // unknown runtime
+ throw new Error('Unable to identify the current JavaScript runtime.');
}
})();
/**
- * Load the VM-specific implementation of a module.
+ * Get the require path for the runtime-specific implementation of a module.
*
- * @param {string} modulePath - The relative path to the module. Use the same format as when calling
+ * @param {string} partialPath - The partial path to the module. Use the same format as when calling
* `require()`.
- * @return {object} An object containing VM-specific functions for the requested module.
+ * @return {object} The require path for the runtime-specific implementation of the module.
*/
-exports.getModule = function(modulePath) {
- modulePath = [__dirname, vm, modulePath].join('/').replace(/ /g, '%20');
+exports.getModulePath = function(partialPath) {
+ var modulePath = [__dirname, runtime, partialPath].join('/').replace(/ /g, '%20');
if (os.platform() === 'win32') {
modulePath = pathToUri(modulePath);
}
- return require(modulePath);
+ return modulePath;
+};
+
+/**
+ * Retrieve the identifier for the current JavaScript runtime.
+ *
+ * @private
+ * @return {string} The runtime identifier.
+ */
+exports.getRuntime = function() {
+ return runtime;
};
/**
* Check whether Mozilla Rhino is running JSDoc.
- * @return {boolean} Set to `true` if the current VM is Mozilla Rhino.
+ * @return {boolean} Set to `true` if the current runtime is Mozilla Rhino.
*/
exports.isRhino = function() {
- return vm === RHINO;
+ return runtime === RHINO;
};
/**
* Check whether Node.js is running JSDoc. (Node.js is not currently supported.)
- * @return {boolean} Set to `true` if the current VM is Node.js.
+ * @return {boolean} Set to `true` if the current runtime is Node.js.
*/
-exports.isNodejs = function() {
- return vm === NODEJS;
+exports.isNode = function() {
+ return runtime === NODE;
};
diff --git a/nodejs/bin/jsdoc b/node/bin/jsdoc
similarity index 66%
rename from nodejs/bin/jsdoc
rename to node/bin/jsdoc
index c53efc4d..d2f56ad1 100755
--- a/nodejs/bin/jsdoc
+++ b/node/bin/jsdoc
@@ -7,19 +7,12 @@
var fs = require('fs');
var os = require('os');
var path = require('path');
-var spawnProc = require('child_process').spawn;
var args = process.argv.slice(2);
var script = path.normalize( path.join( path.dirname(fs.realpathSync(process.argv[1])), '..', '..',
'jsdoc' ) );
-var jsdoc;
-
-if (process.platform === 'win32') {
- jsdoc = spawnProc(script + '.cmd', args, {stdio: 'inherit'});
-}
-else {
- jsdoc = spawnProc(script, args, {stdio: 'inherit'});
-}
+var command = process.platform === 'win32' ? script + '.cmd' : script;
+var jsdoc = require('child_process').spawn(command, args, {stdio: 'inherit'});
jsdoc.on('close', function(code) {
process.exit(code);
diff --git a/nodejs/jsdoc/fs.js b/node/jsdoc/fs.js
similarity index 100%
rename from nodejs/jsdoc/fs.js
rename to node/jsdoc/fs.js
diff --git a/node/jsdoc/src/parser.js b/node/jsdoc/src/parser.js
new file mode 100644
index 00000000..1b146d91
--- /dev/null
+++ b/node/jsdoc/src/parser.js
@@ -0,0 +1 @@
+module.exports = require('jsdoc/src/parser');
diff --git a/nodejs/jsdoc/util/include.js b/node/jsdoc/util/include.js
similarity index 100%
rename from nodejs/jsdoc/util/include.js
rename to node/jsdoc/util/include.js
diff --git a/package.json b/package.json
index 17546150..820a8ef3 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "jsdoc",
"version": "3.2.0-dev",
- "revision": "1366409063892",
+ "revision": "1373039791834",
"description": "An API documentation generator for JavaScript.",
"keywords": [ "documentation", "javascript" ],
"licenses": [
@@ -28,7 +28,7 @@
"underscore": "1.4.2",
"wrench": "1.3.9"
},
- "bin": "./nodejs/bin/jsdoc",
+ "bin": "./node/bin/jsdoc",
"bugs": "https://github.com/jsdoc3/jsdoc/issues",
"author": {
"name": "Michael Mathews",
diff --git a/rhino/js.jar b/rhino/js.jar
index 30e26793..244aa614 100644
Binary files a/rhino/js.jar and b/rhino/js.jar differ
diff --git a/lib/jsdoc/src/rhino/astbuilder.js b/rhino/jsdoc/src/astbuilder.js
similarity index 71%
rename from lib/jsdoc/src/rhino/astbuilder.js
rename to rhino/jsdoc/src/astbuilder.js
index bb934b24..9a6c0cde 100644
--- a/lib/jsdoc/src/rhino/astbuilder.js
+++ b/rhino/jsdoc/src/astbuilder.js
@@ -1,7 +1,7 @@
/*global Packages: true */
/**
* Creates an Esprima-compatible AST using Rhino's JavaScript parser.
- * @module jsdoc/src/rhino/astbuilder
+ * @module rhino/jsdoc/src/astbuilder
*/
var AstBuilder = module.exports = function() {
@@ -11,3 +11,7 @@ var AstBuilder = module.exports = function() {
AstBuilder.prototype.build = function(sourceCode, sourceName) {
return this._builder.build(sourceCode, sourceName);
};
+
+AstBuilder.prototype.getRhinoNodes = function() {
+ return this._builder.getRhinoNodes();
+};
diff --git a/rhino/jsdoc/src/parser.js b/rhino/jsdoc/src/parser.js
new file mode 100644
index 00000000..b3c16177
--- /dev/null
+++ b/rhino/jsdoc/src/parser.js
@@ -0,0 +1,34 @@
+// TODO: module docs
+
+// TODO: docs
+var Parser = exports.Parser = function() {
+ var astBuilder;
+ var visitor;
+
+ var runtime = require('jsdoc/util/runtime');
+ if ( !runtime.isRhino() ) {
+ throw new Error('You must run JSDoc on Mozilla Rhino to use the Rhino parser.');
+ }
+
+ astBuilder = new ( require(runtime.getModulePath('jsdoc/src/astbuilder')) )();
+ visitor = new ( require(runtime.getModulePath('jsdoc/src/visitor')) ).Visitor(this);
+
+ Parser.super_.call(this, astBuilder, visitor);
+};
+require('util').inherits(Parser, require('jsdoc/src/parser').Parser);
+
+// TODO: update docs
+/**
+ * Adds a node visitor to use in parsing
+ */
+Parser.prototype.addNodeVisitor = function(visitor) {
+ this._visitor.addRhinoNodeVisitor(visitor);
+};
+
+// TODO: docs
+/**
+ * Get the node visitors used in parsing
+ */
+Parser.prototype.getNodeVisitors = function() {
+ return this._visitor.getRhinoNodeVisitors();
+};
diff --git a/rhino/jsdoc/src/visitor.js b/rhino/jsdoc/src/visitor.js
new file mode 100644
index 00000000..a12fadff
--- /dev/null
+++ b/rhino/jsdoc/src/visitor.js
@@ -0,0 +1,56 @@
+// TODO: module docs
+
+// TODO: docs
+var Visitor = exports.Visitor = function(parser) {
+ var runtime = require('jsdoc/util/runtime');
+ if ( !runtime.isRhino() ) {
+ throw new Error('You must run JSDoc on Mozilla Rhino to use the Rhino node visitor.');
+ }
+
+ Visitor.super_.call(this, parser);
+
+ // Rhino node visitors added by plugins (deprecated in JSDoc 3.3)
+ this._rhinoNodeVisitors = [];
+ // Rhino nodes retrieved from the org.jsdoc.AstBuilder instance
+ this._rhinoNodes = null;
+
+ this.addAstNodeVisitor({
+ visitNode: this._visitRhinoNode.bind(this)
+ });
+};
+require('util').inherits(Visitor, require('jsdoc/src/visitor').Visitor);
+
+// TODO: docs (deprecated)
+Visitor.prototype.addRhinoNodeVisitor = function(visitor) {
+ this._rhinoNodeVisitors.push(visitor);
+};
+
+// TODO: docs (deprecated)
+Visitor.prototype.getRhinoNodeVisitors = function() {
+ return this._rhinoNodeVisitors;
+};
+
+// TODO: docs (deprecated)
+Visitor.prototype._visitRhinoNode = function(astNode, e, parser, filename) {
+ var rhinoNode;
+
+ var visitors = this._rhinoNodeVisitors;
+ // if there are no visitors, bail out before we retrieve all the nodes
+ if (!visitors.length) {
+ return;
+ }
+
+ if (!this._rhinoNodes) {
+ this._rhinoNodes = parser.astBuilder.getRhinoNodes();
+ }
+
+ rhinoNode = this._rhinoNodes ? this._rhinoNodes.get(astNode.nodeId) : null;
+ if (rhinoNode) {
+ for (var i = 0, l = visitors.length; i < l; i++) {
+ visitors[i].visitNode(rhinoNode, e, parser, filename);
+ if (e.stopPropagation) {
+ break;
+ }
+ }
+ }
+};
diff --git a/test/jasmine-jsdoc.js b/test/jasmine-jsdoc.js
index f77b0f5f..79064337 100644
--- a/test/jasmine-jsdoc.js
+++ b/test/jasmine-jsdoc.js
@@ -110,10 +110,12 @@ jasmine.asyncSpecDone = function() {
};
jasmine.getDocSetFromFile = function(filename, parser) {
- var sourceCode = fs.readFileSync(__dirname + '/' + filename, 'utf8'),
- testParser = parser || new (require('jsdoc/src/parser')).Parser(),
- indexAll = require('jsdoc/borrow').indexAll,
- doclets;
+ var sourceCode = fs.readFileSync(__dirname + '/' + filename, 'utf8');
+ var runtime = require('jsdoc/util/runtime');
+ var testParser = parser ||
+ new ( require(runtime.getModulePath('jsdoc/src/parser')) ).Parser();
+ var indexAll = require('jsdoc/borrow').indexAll;
+ var doclets;
require('jsdoc/src/handlers').attachTo(testParser);
diff --git a/test/specs/documentation/modules.js b/test/specs/documentation/modules.js
index 52481150..9d31e402 100644
--- a/test/specs/documentation/modules.js
+++ b/test/specs/documentation/modules.js
@@ -1,7 +1,9 @@
/*global beforeEach: true, describe: true, env: true, expect: true, it: true */
describe("module names", function() {
- var parser = require('jsdoc/src/parser'),
- srcParser = null, doclets;
+ var runtime = require('jsdoc/util/runtime');
+ var parser = require( runtime.getModulePath('jsdoc/src/parser') );
+ var srcParser = null;
+ var doclets;
beforeEach(function() {
env.opts._ = [__dirname + '/test/fixtures/modules/'];
diff --git a/test/specs/jsdoc/src/handlers.js b/test/specs/jsdoc/src/handlers.js
index f43ac711..66f0368b 100644
--- a/test/specs/jsdoc/src/handlers.js
+++ b/test/specs/jsdoc/src/handlers.js
@@ -1,8 +1,9 @@
/*global describe: true, expect: true, it: true */
describe("jsdoc/src/handlers", function() {
- var jsdoc = {src: { parser: require('jsdoc/src/parser')}},
- testParser = new jsdoc.src.parser.Parser(),
- handlers = require('jsdoc/src/handlers');
+ var runtime = require('jsdoc/util/runtime');
+ var parser = require( runtime.getModulePath('jsdoc/src/parser') );
+ var testParser = new parser.Parser();
+ var handlers = require('jsdoc/src/handlers');
handlers.attachTo(testParser);
@@ -52,4 +53,4 @@ describe("jsdoc/src/handlers", function() {
describe("symbolFound handler", function() {
//TODO
});
-});
\ No newline at end of file
+});
diff --git a/test/specs/jsdoc/src/parser.js b/test/specs/jsdoc/src/parser.js
index d75f554a..6babbef8 100644
--- a/test/specs/jsdoc/src/parser.js
+++ b/test/specs/jsdoc/src/parser.js
@@ -1,15 +1,16 @@
-/*global beforeEach: true, describe: true, expect: true, it: true, jasmine: true, xdescribe: true, xit: true */
+/*global beforeEach: true, describe: true, expect: true, it: true, jasmine: true, spyOn: true,
+xit: true */
describe("jsdoc/src/parser", function() {
- var jsdoc = {src: { parser: require('jsdoc/src/parser')}};
+ var jsdoc = { src: { parser: require('jsdoc/src/parser') } };
it("should exist", function() {
expect(jsdoc.src.parser).toBeDefined();
- expect(typeof jsdoc.src.parser).toEqual("object");
+ expect(typeof jsdoc.src.parser).toBe('object');
});
it("should export a 'Parser' constructor", function() {
expect(jsdoc.src.parser.Parser).toBeDefined();
- expect(typeof jsdoc.src.parser.Parser).toEqual("function");
+ expect(typeof jsdoc.src.parser.Parser).toBe('function');
});
describe("Parser", function() {
@@ -19,14 +20,69 @@ describe("jsdoc/src/parser", function() {
parser = new jsdoc.src.parser.Parser();
}
- it("should have a 'parse' function", function() {
- expect(jsdoc.src.parser.Parser.prototype.parse).toBeDefined();
- expect(typeof jsdoc.src.parser.Parser.prototype.parse).toEqual("function");
+ newParser();
+
+ it('should have an "astBuilder" property', function() {
+ expect(parser.astBuilder).toBeDefined();
});
- it("should have a 'results' function", function() {
- expect(jsdoc.src.parser.Parser.prototype.results).toBeDefined();
- expect(typeof jsdoc.src.parser.Parser.prototype.results).toEqual("function");
+ it('should have a "visitor" property', function() {
+ expect(parser.visitor).toBeDefined();
+ });
+
+ it('should have a "walker" property', function() {
+ expect(parser.walker).toBeDefined();
+ });
+
+ it('should accept an astBuilder, visitor, and walker as arguments', function() {
+ var astBuilder = {};
+ var visitor = {};
+ var walker = {};
+
+ var myParser = new jsdoc.src.parser.Parser(astBuilder, visitor, walker);
+
+ expect(myParser.astBuilder).toBe(astBuilder);
+ expect(myParser.visitor).toBe(visitor);
+ expect(myParser.walker).toBe(walker);
+ });
+
+ it('should have a "parse" method', function() {
+ expect(parser.parse).toBeDefined();
+ expect(typeof parser.parse).toBe('function');
+ });
+
+ it('should have a "results" method', function() {
+ expect(parser.results).toBeDefined();
+ expect(typeof parser.results).toBe('function');
+ });
+
+ it('should have an "addAstNodeVisitor" method', function() {
+ expect(parser.addAstNodeVisitor).toBeDefined();
+ expect(typeof parser.addAstNodeVisitor).toBe('function');
+ });
+
+ it('should have a "getAstNodeVisitors" method', function() {
+ expect(parser.getAstNodeVisitors).toBeDefined();
+ expect(typeof parser.getAstNodeVisitors).toBe('function');
+ });
+
+ describe('astBuilder', function() {
+ // TODO: enable
+ xit('should contain an appropriate astBuilder by default', function() {
+ expect( parser.astBuilder instanceof (require('jsdoc/src/astbuilder')) ).toBe(true);
+ });
+ });
+
+ describe('visitor', function() {
+ it('should contain an appropriate visitor by default', function() {
+ expect( parser.visitor instanceof (require('jsdoc/src/visitor')).Visitor ).toBe(true);
+ });
+ });
+
+ describe('walker', function() {
+ it('should contain an appropriate walker by default', function() {
+ expect( parser.walker instanceof (require('jsdoc/src/walker')).Walker ).toBe(true);
+ });
});
describe("parse", function() {
@@ -70,6 +126,70 @@ describe("jsdoc/src/parser", function() {
expect(spy).toHaveBeenCalled();
});
+ it('should call AST node visitors', function() {
+ var Syntax = require('jsdoc/src/syntax').Syntax;
+
+ var args;
+
+ var sourceCode = ['javascript:/** foo */var foo;'];
+ var visitor = {
+ visitNode: function(node, e, parser, sourceName) {
+ if (e && e.code && !args) {
+ args = Array.prototype.slice.call(arguments);
+ }
+ }
+ };
+
+ require('jsdoc/src/handlers').attachTo(parser);
+ parser.addAstNodeVisitor(visitor);
+ parser.parse(sourceCode);
+
+ expect(args).toBeDefined();
+ expect( Array.isArray(args) ).toBe(true);
+ expect(args.length).toBe(4);
+
+ // args[0]: AST node
+ expect(args[0].type).toBeDefined();
+ expect(args[0].type).toBe(Syntax.VariableDeclarator);
+
+ // args[1]: JSDoc event
+ expect(typeof args[1]).toBe('object');
+ expect(args[1].code).toBeDefined();
+ expect(args[1].code.name).toBeDefined();
+ expect(args[1].code.name).toBe('foo');
+
+ // args[2]: parser
+ expect(typeof args[2]).toBe('object');
+ expect(args[2] instanceof jsdoc.src.parser.Parser).toBe(true);
+
+ // args[3]: current source name
+ expect( String(args[3]) ).toBe('[[string0]]');
+ });
+
+ it('should reflect changes made by AST node visitors', function() {
+ var doclet;
+
+ var sourceCode = ['javascript:/** foo */var foo;'];
+ var visitor = {
+ visitNode: function(node, e, parser, sourceName) {
+ if (e && e.code && e.code.name === 'foo') {
+ e.code.name = 'bar';
+ }
+ }
+ };
+
+ require('jsdoc/src/handlers').attachTo(parser);
+ parser.addAstNodeVisitor(visitor);
+ parser.parse(sourceCode);
+
+ doclet = parser.results()[0];
+
+ expect(doclet).toBeDefined();
+ expect(typeof doclet).toBe('object');
+ expect(doclet.name).toBeDefined();
+ expect(doclet.name).toBe('bar');
+ });
+
it("should fire 'parseComplete' events after it finishes parsing files", function() {
var spy = jasmine.createSpy(),
sourceCode = ['javascript:var bar = false;'];
@@ -101,15 +221,31 @@ describe("jsdoc/src/parser", function() {
});
});
- describe("results", function() {
+ describe('results', function() {
beforeEach(newParser);
- xit("contains an empty array before files are parsed", function() {
- // TODO
+ it('returns an empty array before files are parsed', function() {
+ var results = parser.results();
+
+ expect(results).toBeDefined();
+ expect( Array.isArray(results) ).toBe(true);
+ expect(results.length).toBe(0);
});
- xit("contains an array of doclets after files are parsed", function() {
+ it('returns an array of doclets after files are parsed', function() {
+ var source = 'javascript:var foo;';
+ var results;
+ require('jsdoc/src/handlers').attachTo(parser);
+
+ parser.parse(source);
+ results = parser.results();
+
+ expect(results).toBeDefined();
+ expect(results[0]).toBeDefined();
+ expect(typeof results[0]).toBe('object');
+ expect(results[0].name).toBeDefined();
+ expect(results[0].name).toBe('foo');
});
it("should reflect comment changes made by 'jsdocCommentFound' handlers", function() {
@@ -129,5 +265,47 @@ describe("jsdoc/src/parser", function() {
});
});
});
+
+ describe('addAstNodeVisitor', function() {
+ function visitorA() {}
+ function visitorB() {}
+
+ var visitors;
+
+ beforeEach(newParser);
+
+ it('should work with a single node visitor', function() {
+ parser.addAstNodeVisitor(visitorA);
+
+ visitors = parser.getAstNodeVisitors();
+
+ expect(visitors.length).toBe(1);
+ expect(visitors[0]).toBe(visitorA);
+ });
+
+ it('should work with multiple node visitors', function() {
+ parser.addAstNodeVisitor(visitorA);
+ parser.addAstNodeVisitor(visitorB);
+
+ visitors = parser.getAstNodeVisitors();
+
+ expect(visitors.length).toBe(2);
+ expect(visitors[0]).toBe(visitorA);
+ expect(visitors[1]).toBe(visitorB);
+ });
+ });
+
+ describe('getAstNodeVisitors', function() {
+ beforeEach(newParser);
+
+ it('should return an empty array by default', function() {
+ var visitors = parser.getAstNodeVisitors();
+
+ expect( Array.isArray(visitors) ).toBe(true);
+ expect(visitors.length).toBe(0);
+ });
+
+ // other functionality is covered by the addNodeVisitors tests
+ });
});
-});
\ No newline at end of file
+});
diff --git a/test/specs/jsdoc/util/runtime.js b/test/specs/jsdoc/util/runtime.js
new file mode 100644
index 00000000..2efb1a81
--- /dev/null
+++ b/test/specs/jsdoc/util/runtime.js
@@ -0,0 +1,62 @@
+/*global describe: true, expect: true, it: true, xit: true */
+describe("jsdoc/util/runtime", function() {
+ var runtime = require('jsdoc/util/runtime');
+ var isRhino;
+ var isNode;
+
+ it("should exist", function() {
+ expect(runtime).toBeDefined();
+ expect(typeof runtime).toEqual('object');
+ });
+
+ it("should export a 'RHINO' constant", function() {
+ expect(runtime.RHINO).toBeDefined();
+ expect(typeof runtime.RHINO).toEqual('string');
+ });
+
+ it("should export a 'NODE' constant", function() {
+ expect(runtime.NODE).toBeDefined();
+ expect(typeof runtime.NODE).toEqual('string');
+ });
+ it("should export an 'isRhino' function", function() {
+ expect(runtime.isRhino).toBeDefined();
+ expect(typeof runtime.isRhino).toEqual('function');
+ });
+
+ it("should export an 'isNode' function", function() {
+ expect(runtime.isNode).toBeDefined();
+ expect(typeof runtime.isNode).toEqual('function');
+ });
+
+ describe("isRhino", function() {
+ isRhino = runtime.isRhino();
+
+ it("should return a boolean", function() {
+ expect(typeof isRhino).toEqual('boolean');
+ });
+
+ it("should return the opposite value from isNode()", function() {
+ if (isNode === undefined) {
+ isNode = runtime.isNode();
+ }
+
+ expect(!isRhino).toBe(isNode);
+ });
+ });
+
+ describe("isNode", function() {
+ isNode = runtime.isNode();
+
+ it("should return a boolean", function() {
+ expect(typeof isNode).toEqual('boolean');
+ });
+
+ it("should return the opposite value from isRhino()", function() {
+ if (isRhino === undefined) {
+ isRhino = runtime.isRhino();
+ }
+
+ expect(!isNode).toBe(isRhino);
+ });
+ });
+});
diff --git a/test/specs/jsdoc/util/vm.js b/test/specs/jsdoc/util/vm.js
deleted file mode 100644
index a141a4cc..00000000
--- a/test/specs/jsdoc/util/vm.js
+++ /dev/null
@@ -1,66 +0,0 @@
-/*global describe: true, expect: true, it: true, xit: true */
-describe("jsdoc/util/vm", function() {
- var vm = require('jsdoc/util/vm');
-
- it("should exist", function() {
- expect(vm).toBeDefined();
- expect(typeof vm).toEqual('object');
- });
-
- it("should export a 'RHINO' constant", function() {
- expect(vm.RHINO).toBeDefined();
- expect(typeof vm.RHINO).toEqual('string');
- });
-
- it("should export a 'NODEJS' constant", function() {
- expect(vm.NODEJS).toBeDefined();
- expect(typeof vm.NODEJS).toEqual('string');
- });
-
- it("should export a 'vm' property", function() {
- expect(vm.vm).toBeDefined();
- expect(typeof vm.vm).toEqual('string');
- });
-
- it("should export an 'isRhino' function", function() {
- expect(vm.isRhino).toBeDefined();
- expect(typeof vm.isRhino).toEqual('function');
- });
-
- it("should export an 'isNodejs' function", function() {
- expect(vm.isNodejs).toBeDefined();
- expect(typeof vm.isNodejs).toEqual('function');
- });
-
-
- describe("vm", function() {
- it("should match either 'vm.RHINO' or 'vm.NODEJS'", function() {
- expect(vm.vm).toEqual(vm.RHINO || vm.NODEJS);
- });
-
- xit("should return the correct value for the current VM", function() {
- // TODO: is there a reasonable test that doesn't just replicate getVm()?
- });
- });
-
- describe("isRhino", function() {
- it("should return a boolean", function() {
- expect( typeof vm.isRhino() ).toEqual('boolean');
- });
-
- it("should reflect the value of 'vm.vm'", function() {
- expect( vm.isRhino() ).toEqual(vm.vm === vm.RHINO ? true : false);
- });
- });
-
- describe("isNodejs", function() {
- it("should return a boolean", function() {
- expect( typeof vm.isNodejs() ).toEqual('boolean');
- });
-
- it("should reflect the value of 'vm.vm'", function() {
- expect( vm.isNodejs() ).toEqual(vm.vm === vm.NODEJS ? true : false);
- });
- });
-
-});
diff --git a/test/specs/rhino/src/parser.js b/test/specs/rhino/src/parser.js
new file mode 100644
index 00000000..5926606d
--- /dev/null
+++ b/test/specs/rhino/src/parser.js
@@ -0,0 +1,154 @@
+/*global beforeEach: true, describe: true, expect: true, it: true, jasmine: true, spyOn: true */
+describe('rhino/jsdoc/src/parser', function() {
+ var jsdoc = {
+ src: {
+ parser: (function() {
+ var runtime = require('jsdoc/util/runtime');
+ return require( runtime.getModulePath('jsdoc/src/parser') );
+ })()
+ }
+ };
+
+ it('should exist', function() {
+ expect(jsdoc.src.parser).toBeDefined();
+ expect(typeof jsdoc.src.parser).toBe('object');
+ });
+
+ it('should export a "Parser" constructor', function() {
+ expect(jsdoc.src.parser.Parser).toBeDefined();
+ expect(typeof jsdoc.src.parser.Parser).toBe('function');
+ });
+
+ describe('Parser', function() {
+ var parser;
+
+ function newParser() {
+ parser = new jsdoc.src.parser.Parser();
+ }
+
+ newParser();
+
+ it('should inherit from jsdoc/src/parser', function() {
+ var parent = require('jsdoc/src/parser').Parser;
+ expect(parser instanceof parent).toBe(true);
+ });
+
+ it('should have an "addNodeVisitor" method', function() {
+ expect(parser.addNodeVisitor).toBeDefined();
+ expect(typeof parser.addNodeVisitor).toBe('function');
+ });
+
+ it('should have a "getNodeVisitors" method', function() {
+ expect(parser.getNodeVisitors).toBeDefined();
+ expect(typeof parser.getNodeVisitors).toBe('function');
+ });
+
+ describe('addNodeVisitor', function() {
+ function visitorA() {}
+ function visitorB() {}
+
+ var visitors;
+
+ beforeEach(newParser);
+
+ it('should work with a single Rhino node visitor', function() {
+ parser.addNodeVisitor(visitorA);
+
+ visitors = parser.getNodeVisitors();
+
+ expect(visitors.length).toBe(1);
+ expect(visitors[0]).toBe(visitorA);
+ });
+
+ it('should work with multiple Rhino node visitors', function() {
+ parser.addNodeVisitor(visitorA);
+ parser.addNodeVisitor(visitorB);
+
+ visitors = parser.getNodeVisitors();
+
+ expect(visitors.length).toBe(2);
+ expect(visitors[0]).toBe(visitorA);
+ expect(visitors[1]).toBe(visitorB);
+ });
+ });
+
+ describe('getNodeVisitors', function() {
+ beforeEach(newParser);
+
+ it('should return an empty array by default', function() {
+ var visitors = parser.getNodeVisitors();
+
+ expect( Array.isArray(visitors) ).toBe(true);
+ expect(visitors.length).toBe(0);
+ });
+
+ // other functionality is covered by the addNodeVisitors tests
+ });
+
+ describe('parse', function() {
+ beforeEach(newParser);
+
+ var sourceCode = ['javascript:/** foo */var foo;'];
+
+ it('should call Rhino node visitors', function() {
+ var args;
+
+ var visitor = {
+ visitNode: function(rhinoNode, e, parser, sourceName) {
+ if (e && e.code && !args) {
+ args = Array.prototype.slice.call(arguments);
+ }
+ }
+ };
+
+ require('jsdoc/src/handlers').attachTo(parser);
+ parser.addNodeVisitor(visitor);
+ parser.parse(sourceCode);
+
+ expect(args).toBeDefined();
+ expect( Array.isArray(args) ).toBe(true);
+ expect(args.length).toBe(4);
+
+ // args[0]: Rhino node
+ expect(args[0].toSource).toBeDefined();
+ expect( String(args[0].toSource()) ).toBe('foo');
+
+ // args[1]: JSDoc event
+ expect(typeof args[1]).toBe('object');
+ expect(args[1].code).toBeDefined();
+ expect(args[1].code.name).toBeDefined();
+ expect( String(args[1].code.name) ).toBe('foo');
+
+ // args[2]: parser
+ expect(typeof args[2]).toBe('object');
+ expect(args[2] instanceof jsdoc.src.parser.Parser).toBe(true);
+
+ // args[3]: current source name
+ expect( String(args[3]) ).toBe('[[string0]]');
+ });
+
+ it('should reflect changes made by Rhino node visitors', function() {
+ var doclet;
+
+ var visitor = {
+ visitNode: function(rhinoNode, e, parser, sourceName) {
+ if (e && e.code && e.code.name === 'foo') {
+ e.code.name = 'bar';
+ }
+ }
+ };
+
+ require('jsdoc/src/handlers').attachTo(parser);
+ parser.addNodeVisitor(visitor);
+ parser.parse(sourceCode);
+
+ doclet = parser.results()[0];
+
+ expect(doclet).toBeDefined();
+ expect(typeof doclet).toBe('object');
+ expect(doclet.name).toBeDefined();
+ expect(doclet.name).toBe('bar');
+ });
+ });
+ });
+});
diff --git a/test/specs/rhino/src/visitor.js b/test/specs/rhino/src/visitor.js
new file mode 100644
index 00000000..1c26ae23
--- /dev/null
+++ b/test/specs/rhino/src/visitor.js
@@ -0,0 +1,88 @@
+/*global beforeEach: true, describe: true, expect: true, it: true */
+describe('rhino/jsdoc/src/visitor', function() {
+ var runtime = require('jsdoc/util/runtime');
+ var jsdoc = {
+ src: {
+ visitor: require( runtime.getModulePath('jsdoc/src/visitor') )
+ }
+ };
+
+ it('should exist', function() {
+ expect(jsdoc.src.visitor).toBeDefined();
+ expect(typeof jsdoc.src.visitor).toBe('object');
+ });
+
+ it('should export a "Visitor" constructor', function() {
+ expect(jsdoc.src.visitor.Visitor).toBeDefined();
+ expect(typeof jsdoc.src.visitor.Visitor).toBe('function');
+ });
+
+ describe('Visitor', function() {
+ var parser;
+ var visitor;
+
+ function newVisitor() {
+ parser = new ( require(runtime.getModulePath('jsdoc/src/parser')) ).Parser();
+ visitor = new jsdoc.src.visitor.Visitor(parser);
+ }
+
+ newVisitor();
+
+ it('should inherit from jsdoc/src/visitor', function() {
+ var parent = require('jsdoc/src/visitor').Visitor;
+ expect(visitor instanceof parent).toBe(true);
+ });
+
+ it('should have an "addRhinoNodeVisitor" method', function() {
+ expect(visitor.addRhinoNodeVisitor).toBeDefined();
+ expect(typeof visitor.addRhinoNodeVisitor).toBe('function');
+ });
+
+ it('should have a "getRhinoNodeVisitors" method', function() {
+ expect(visitor.getRhinoNodeVisitors).toBeDefined();
+ expect(typeof visitor.getRhinoNodeVisitors).toBe('function');
+ });
+
+ describe('addRhinoNodeVisitor', function() {
+ function visitorA() {}
+ function visitorB() {}
+
+ var visitors;
+
+ beforeEach(newVisitor);
+
+ it('should work with a single Rhino node visitor', function() {
+ visitor.addRhinoNodeVisitor(visitorA);
+
+ visitors = visitor.getRhinoNodeVisitors();
+
+ expect(visitors.length).toBe(1);
+ expect(visitors[0]).toBe(visitorA);
+ });
+
+ it('should work with multiple Rhino node visitors', function() {
+ visitor.addRhinoNodeVisitor(visitorA);
+ visitor.addRhinoNodeVisitor(visitorB);
+
+ visitors = visitor.getRhinoNodeVisitors();
+
+ expect(visitors.length).toBe(2);
+ expect(visitors[0]).toBe(visitorA);
+ expect(visitors[1]).toBe(visitorB);
+ });
+ });
+
+ describe('getRhinoNodeVisitors', function() {
+ beforeEach(newVisitor);
+
+ it('should return an empty array by default', function() {
+ var visitors = visitor.getRhinoNodeVisitors();
+
+ expect( Array.isArray(visitors) ).toBe(true);
+ expect(visitors.length).toBe(0);
+ });
+
+ // other functionality is covered by the addNodeVisitors tests
+ });
+ });
+});
diff --git a/test/specs/tags/overviewtag.js b/test/specs/tags/overviewtag.js
index 6087be5b..925412a9 100644
--- a/test/specs/tags/overviewtag.js
+++ b/test/specs/tags/overviewtag.js
@@ -1,9 +1,10 @@
/*global describe: true, env: true, expect: true, it: true */
describe("@overview tag", function() {
- var parser = require('jsdoc/src/parser'),
- srcParser = new parser.Parser(),
- doclets;
+ var runtime = require('jsdoc/util/runtime');
+ var parser = require( runtime.getModulePath('jsdoc/src/parser') );
+ var srcParser = new parser.Parser();
+ var doclets;
require('jsdoc/src/handlers').attachTo(srcParser);
doclets = srcParser.parse(__dirname + '/test/fixtures/file.js');