Let's Make a Framework: JSDoc

2011-01-20 00:00:00 +0000 by Alex R. Young

Welcome to part 47 of Let's Make a Framework, the ongoing series about
building a JavaScript framework.

If you haven't been following along, these articles are tagged with
lmaf. The project we're creating is called Turing.


Last week I reviewed various approaches to JavaScript documentation, and
I decided to use dox. Dox can be
installed with npm:

npm install dox

By the end of this tutorial, you'll be able to make something like this:

Although dox produces readable documentation -- which is incidentally
perfect for writing tutorials because the code is inline -- it can't
parse everything JSDoc offers. It's a simple tool designed to suit the
author's requirements, but I like it and would like to see it grow in
the future.

Despite not supporting everything outlined by
jsdoc-toolkit, I'm going to use dox and write JSDoc comments as if it fully supports them.

JSDoc Comment Structure

Each file in your project should contain author, copyright, and license
details. For example:

 * Turing - Module Name
 * Copyright (C) 2010-2011 Alex R. Young
 * MIT Licensed

 * A private namespace to set things up against the global object.
(function(global) {

I like to write comments in a relatively informal conversational style,
as full sentences. I might be extra-verbose because this is a tutorial,
so you can be a bit more succinct in your own projects.

Where JSDoc comments come in handy is outlining the intended inputs and
outputs of a function:

   * Determine if an object is an `Array`.
   * @param {Object} object An object that may or may not be an array
   * @returns {Boolean} True if the parameter is an array
  turing.isArray = Array.isArray || function(object) {
    return !!(object && object.concat
              && object.unshift && !object.callee);

Notice I've used backticks around the Array keyword. Dox
has markdown support, so this will be converted into a code
tags in the resulting HTML.

The param</code> and <code>returns directives are known
as tags. The
jsdoc-toolkit wiki lists lots of tags. The
@param tag actually has quite a few ways of defining method parameters, including
support for optional parameters.

Long Examples

Because dox supports markdown, long code examples can be included simply
through indentation:

 * Chain animation module calls, for example:
 *     turing.anim.chain(element)
 *       .highlight()
 *       .pause(250)
 *       .move(100, { x: '100px', y: '100px', easing: 'ease-in-out' })
 *       .animate(250, { width: '1000px' })
 *       .fadeOut(250)
 *       .pause(250)
 *       .fadeIn(250)
 *       .animate(250, { width: '20px' });
 * @param {Object} element A DOM element
 * @returns {Chainer} Chained API object
anim.chain = function(element) {
  return new Chainer(element);

Generating the Documentation

Dox can be run with just dox file.js, and it'll output the
HTML to the console. The HTML is totally self-contained, which means
there are no extra image, CSS, or JavaScript files. This will generate
the documentation for

dox --title Turing turing.core.js  > index.html

I also added this to the project's Jakefile (node-jake):

var exec = require('child_process').exec;

task('docs', [], function() {
  exec('dox --title Turing *.js  > docs/index.html');

Build Systems

The build system is closely tied to project management tasks like
generating documentation. Generating documentation should be consistent
and easy to run so it doesn't get forgotten as the project changes over
time, therefore adding a docs task is a good idea.

Every time I go over TJ Holowaychuk's projects (and
jQuery) I'm reminded that GNU make was more than enough for our needs.
Build system choice is partially dependent on how much JavaScript from
Node, Narwhal, Rhino, etc. you want to reuse in your build system --
Python, Java, and Ruby projects often use native build systems to get
access to native libraries. Also, you already know how to write
JavaScript pretty well but might not be familiar with make.

However, when writing your own projects make is more likely
to be on a system than node-jake,
and it could always invoke JavaScript scripts anyway. I recommend giving
it a look before deciding on the build system for your own projects.

Side note: I've removed the Narwhal support from the Jakefile to focus
on using Node for the build system instead. The main motivation for this
was to get some cross-pollination between the Node tutorial series and
this series.