Hello,
First off, tl;dr crowd can skip to the links at the bottom.
Background
I was excited when I came across jsdoc3 while searching for a way to generate documentation for a set of jQuery UI widgets I created, but quickly realized that there were some limitations that would make things more difficult that I wanted them to be. Specifically, JSDoc3 didn't really have support for the class factory pattern (i.e. creating a class via a call to some function that defines the class). This is how the jQuery UI widget framework works. It can also be seen in JavascriptMVC, Dojo, and a number of other projects. It was possible to get around this since JSDoc3 lets you define arbitrary doclets with the @name tag, but that would've required instrumenting the code with a lot more tags (@name, @class, @function, @memberof, @instance) that seemed unnecessary to me (not to mention I didn't want to go through all the code and do it), especially since the widget framework is fairly structured and the documentation generator should be able to automatically determine lots of things. Additionally, while the plugin/template system is great for allowing users to create custom documentation, it is not flexible enough to address this issue.
New Stuff!
So I decided to dig in and make some changes that would allow me to mostly just write basic things like descriptions (of classes, methods, and parameters)...things one might normally put in code comments anyway, without a lot of extra tags specifically for generated documentation. Because, let's face it, no one likes documentation, bute we all need it. If we can make it as convenient as possible, the software world will be better for it. I'm guessing at least a few folks with find some of these things useful:
- Modified Rhino (probably not of interest to most on this list, but listed here for the curious)
- More flexible JSDoc3
- jQuery UI widget plugin/template (but also useful to all documenting factory pattern code as an example of how you can use the more flexible JSDoc3)
- JSDoc3 ant task
Modified RhinoI found that one of the main problems was that Rhino (the project JSDoc3 uses to parse JavaScript code) wasn't attaching jsdoc comments to function calls. I wanted to do something like:
/**
* Here's a description of my widget
*/
$.widget("ui.mywidget", {
options: {
someOption: ""
},
_create: function() {
//code that creates my widget
}
});
but the comment would get attached to the options object and not the function call. This made sense, since traditionally, one would only be adding jsdoc comments to something that would be exposed, but factory functions create classes that are exposed. You could work around this, by creating an object first, commenting that, and specifying that object as the second parameter above, but again the goal is to be unobtrusive as possible and still produce quality documentation. Requiring code refactoring is a bit on the obtrusive side. Anyway, now the version of JSDoc3 below includes a version of Rhino whose parser attaches comments to the function call node.
More Flexible JSDoc3
I have made modifications to the JSDoc3 plugin framework that allow for much more customizability of the parsing process. Whereas, previously, a plugin only had access to high-level events, they now also have access to the tag dictionary, and low-level parsing events.
The same high-level events are available, but instead of defining them directly on the exports object as before, a plugin should define them in an exported handlers object, like so:
exports.handlers = {
newDoclet: function(e) {
//do something with the new doclet
}
};
A plugin can define new tags like so:
exports.defineTags(dictionary) {
dictionary.defineTag("widget", {
onTagged: function(doclet, tag) {
doclet.kind="widget"
//do something else with the doclet
});
}
};
A plugin can get access to the low-level parsing events as well by defining a node visitor. Whenever the parser visits a node in the parse tree, the plugins visitor will have a chance to process that node. For example:
exports.nodeVisitor = {
visitNode: function(node, e, parser, currentSourceName) {
// here's where I figure out if the node is a function call to the
// factory I'm interested in, namely $.widget. Then I extract the
// the name and created a symbolFound event that will make
// jsdoc3 document a class with that name
}
};
Most users will see no difference and not have to change anything. Existing plugin developers will need to put their event handlers inside a
handlers object instead of directly on the
exports object. You can find more documentation about the plugin framework enhancements on the readme in the plugins directory of the project on github (
https://github.com/jannon/jsdoc). And a more thorough example in the JSDoc-JUI plugin (below).
JSDoc-JUI
This is the plugin/template I created to document my set of widgets. It is intended to mimic the look and feel of the documentation for the main jQuery UI project. You can take a look at an example of the documentation it produces at
http://jannon.net/jui. The source that documentation comes from can be found at
https://github.com/jannon/JUI . It can be used with minimal modification by anyone documenting jQuery UI widgets (you'll want to change the header and the footer templates). It can also be a good starting point for anyone wanting to create a plugin for documenting class factory functions (e.g. JavaScriptMVC's
$.Model, or Dojo's
dojo.declare) or any other code/symbols that aren't handled by default. You can find the source for the plugin at https://github.com/jannon/JSDoc-JUI.
JSDoc3 Ant Task
Summary Links