Web Development

Create useful relevant JavaScript documentation with JSDoc


This blog post is also available as a TechRepublic PDF download.

Whatever the reason, not documenting an application is never a good thing, even if it is usually something of a chore. This is especially true when given the task of documenting client-side JavaScript, which is usually considered something of an ugly stepchild when compared to server-side technologies. Interestingly though, the answer to the problem with JavaScript documentation comes from one of those very same server-side technologies -- Java.

There is a really neat tool for Java developers that aids in the generation of documentation called Javadoc. There is also a version for JavaScript called JSDoc, which is used to develop HTML documentation that not only fulfills the need for code documentation but also helps prevent problems such as multiple functions or objects that essentially do the same thing and the general lack of knowledge of what is in the library. This tutorial walks you through how to install and use JSDoc for documenting JavaScript.

Installing JSDoc

Unfortunately, the installation of JSDoc isn't as exactly straightforward as it could be. The reason for this is that it is written in Perl, so unless you've already installed Perl there's an additional step or two. Because I recently reinstalled Windows XP Pro on my laptop, I had run through the additional steps myself. The first thing I had to do was download and install ActivePerl, which was available as a msi file. Figure A shows part of the installation process.

Figure A

Installing ActivePerl
Once ActivePerl is installed successfully, the next step is to download and decompress JSDoc. At this point, it is possible to run JSDoc from a DOS Window, but if you do, it probably won't work. This failure is due to a missing Perl Package, as shown in Figure B. Fortunately, typing ppm in the very same Window brings up the Perl Package Manager, shown in Figure C.

Figure B

DOS Window

Figure C

Perl Package Manager
Using the Perl Package Manager, the missing HTML-Template package can be installed, as Figure D illustrates.

Figure D

Installing a Perl Package

Trying it out

Once all of the required components have been installed, it is time to kick the tires, so to speak. For this, I'm using the JavaScript shown in Listing A.

Listing A -- Sample JavaScript

<!-- <![CDATA[
/**
 * @fileoverview This file contains the information necessary to add client-side
 * keyboard restriction functionality to a web page.
 */
/**
 * Accept 'Y' or 'N' and return issue an error message.
 * @requires keybEdit
 */
var keybYN = new keybEdit('yn','Valid values are 'Y' or 'N'.');
/**
 * Accept numeric input and return issue an error message.
 * @requires keybEdit
 */
var keybNumeric = new keybEdit('01234567890','Numeric input only.');
/**
 * Accept numeric input and return issue an error message.
 * @requires keybEdit
 */
var keybAlpha = new keybEdit('abcdefghijklmnopqurstuvwxyz','Alpha input only.');
/**
 * Accept alphabetic input and return issue an error message.
 * @requires keybEdit
 */
var keybAlphaNumeric = new keybEdit('abcdefghijklmnopqurstuvwxyz01234567890/ -,.=!@#$%^&*()_+'":;','Alpha-numeric input only.');
/**
 * Accept alphabetic or numeric input and return issue an error message.
 * @requires keybEdit
 */
var keybDecimal = new keybEdit('01234567890.','Decimal input only.');
/**
 * Accept decimal input and return issue an error message.
 * @requires keybEdit
 */
var keybDate =  new keybEdit('01234567890/','Date input only');;
/**
 * Accept date input and return issue an error message.
 * @requires keybEdit
 */
var keybYNNM = new keybEdit('yn','');
/**
 * Accept numeric input.
 * @requires keybEdit
 */
var keybNumericNM = new keybEdit('01234567890','');
/**
 * Accept alphabetic input.
 * @requires keybEdit
 */
var keybAlphaNM = new keybEdit('abcdefghijklmnopqurstuvwxyz','');
/**
 * Accept alphabetic or numeric input.
 * @requires keybEdit
 */
var keybAlphaNumericNM = new keybEdit('abcdefghijklmnopqurstuvwxyz01234567890/ -,.=!@#$%^&*()_+'":;','');
/**
 * Accept decimal input.
 * @requires keybEdit
 */
var keybDecimalNM = new keybEdit('01234567890.','');
/**
 * Accept date input.
 * @requires keybEdit
 */
var keybDateNM =  new keybEdit('01234567890/','');;

/**
 * keybEdit
 * @class The purpose of this function is to be a constructor for the keybEdit
 * object. keybEdit objects are used by the function editKeyBoard to
 * determine which keystrokes are valid for form objects. In addition, if an
 * error occurs, they provide the error message.
 * @constructor
 * @param {string} strValid Valid input characters
 * @param {string} strMsg Error message
 */
function keybEdit(strValid, strMsg) {
      //    Variables
      var reWork = new RegExp('[a-z]','gi');       //    Regular expression

      //    Properties
      if(reWork.test(strValid))
             this.valid = strValid.toLowerCase() + strValid.toUpperCase();
      else
             this.valid = strValid;

      if((strMsg == null) || (typeof(strMsg) == 'undefined'))
             this.message = '';
      else
             this.message = strMsg;

      /**
       * @ignore
       */
      this.getValid = keybEditGetValid;
      /**
       * @ignore
       */
      this.getMessage = keybEditGetMessage;

      /**
       * Return a boolean indicating whether or not a key stroke is valid.
       * @method getValid
       * @return string-boolean Indicates whether or not a key is valid.
       */
      function keybEditGetValid() {
             return this.valid.toString();
      }

      /**
       * Return an error message associated with a key stroke.
       * @method getMessage
       * @return string Error message.
       */
      function keybEditGetMessage() {
             return this.message;
      }
}

/**
 * The purpose of this function is to edit edit keyboard input to determine if
 * the keystrokes are valid.
 * @requires keybEdit
 * @param {Object} evt
 * @param {Object} objKeyb
 */
function editKeyBoard(evt, objKeyb) {
      var strWork = objKeyb.getValid();
      var strMsg = '';                                   // Error message
      var blnValidChar = false;                    // Valid character flag
      var intCode = evt.charCode == undefined ? evt.keyCode : evt.charCode;

      // Part 1: Validate input
      if(!blnValidChar)
             switch(true) {
                   case(intCode == 8):
                   case(intCode == 9):
                   case(intCode == 10):
                   case(intCode == 13):
                          blnValidChar = true;

                          break;
                   default:
                          for(i=0;i < strWork.length;i++)
                                if(intCode == strWork.charCodeAt(i)) {
                                      blnValidChar = true;

                                      break;
                                }

                          break;
             }

      // Part 2: Build error message
      if(!blnValidChar) {
             if(objKeyb.getMessage().toString().length != 0)
                   alert('Error: ' + objKeyb.getMessage());

             evt.stopPropagation = true;

             try {
                   evt.preventDefault();
             }
             catch(e) {
                   window.event.returnValue = false;            // Clear invalid character
             }
      }
}
// ]]> -->
Using the above JavaScript as input requires once again going into the DOS command prompt, as shown in Figure E. This image also shows the command necessary to generate the documentation. Figure F shows some of the documentation itself.

Figure E

Generating documentation

Figure F

Generated documentation

Options and hints

The example just scratches the surface of the capabilities of JSDoc, as you can probably figure out from my lame example. To fully appreciate just what JSDoc is capable of, you might want to look at Table A, which shows the tags that can be used within JavaScript documentation.

Table A

Tag

Description

@addon

Marks a function as an extension of a function whose definition is not within the source file.

@argument

Describes an argument with the argument type being in curly braces.

@author

Names the author of the function/class.

@base

Defines the provided class name as the class being inherited from.

@class

Used to provide a description of a class, which will not be used in the constructor's documentation.

@constructor

Describes the constructor for a class.

@deprecated

Signifies that the function/class has been deprecated.

@exception

Describes an error that the function/class may throw.

@exec

 

@extends

Signifies the class that the current class is derived from.

@fileoverview

Signifies that the documentation block is to be used to describe the current file. This tag should be placed before any other tags.

@final

Indicates that the function/class

@ignore

Causes JSDoc to ignore the subsequent code.

@link

Similar to the @link tag, used to link to a number of other pages.

@member

Defines the subsequent function as a member of the provided class name.

@param

Describes a parameter with the parameter type being in curly braces.

@private

Signifies that the function/class is private and should not be included in the generated documentation.

@requires

Signifies that another function/class is required.

@return

Describes the return value for a function.

@returns

Describes the return value for a function.

@see

Links to another function/class.

@throws

Describes an error that the function/class may throw.

@type

Specifies the return type of a function/member.

@version

The function's/classes' version number.

In addition to the information shown, executing JSDoc.pl with the -h or -help option will display a list of options available when generating documentation. Figure G shows the result of the help option.

Figure G

The -help option

No more excuses

While the documentation generated by JSDoc might not conform to your local standards, it does provide a starting point. Say, for instance, that the local standard is UML, then you might want to try to generate XMI using the -format option. It seems that with JSDoc the list of excuses for not documenting is growing short.

7 comments
FrankBerger
FrankBerger

I followed the instructions thoroughly but there is no jsdoc.pl anywhere. This is frustrating!

Wayne M.
Wayne M.

To repeat a recommendation I constantly make, use self documenting code techniques in lieu of comments as much as possible. From the example above, there is no reason to use names like "keybAlphaNumeric" and then describe what it really does. Use a name like IsAValidAlphabeticOrNumericInput and break the function into a separate validation function and error generating function - the "and" in the original comment is a prime indicator that this should be done to clarify the the purpose of the function. Aggressively clarify code and the need for documentation greatly diminishes.

Ed Woychowsky
Ed Woychowsky

Oops, the @final indicates that this is the final value. The @exec indicates that the method is to be executed during the JSDoc pre-processor step.

Justin James
Justin James

That looks like a neat tool, and certainly fills a humongous hole in the JavaScript development landscape. Now that being said, it is much more important *what* you document rather than *how* you document. All too often, JavaDocs are filled will little more than a walk through the class tree via reflection, and add little value other than syntactic reference. You have to document not just "how", but "why". Hopefully, tools like this (also it does seem like a rather clumsy process to use) will encourage developers to write documentation beyond "i is the variable to loop iterates through". :) J.Ja

apotheon
apotheon

Avoid the trap of [url=http://www.codinghorror.com/blog/archives/000451.html][b]undocumentation[/b][/url]. Your job is far from being over when you run a documentation generation tool -- it doesn't actually generate documentation, but just a basic scaffold for documentation. You need more. I find that languages with the best documentation generation tools tend to suffer the most from "undocumentation".

Justin James
Justin James

There is something about those code generators, that typically do not do more than spit out a syntax reference, that gives the illusion of documentation. Granted, if you use verbose naming (as Wayne recommends, and I generally follow as well), it does do a fairly decent job to the end user... but it still gives little help to the coder who wants to know internal details like thread safety, or contextual details such as when to use it vs. a similar function, and so on. So far, my favorite documentation is Perl's, it is nearly 100% "why", and only somewhat "how". using those docs not only helps you write working code, but it helps you write good code. No code generator can do that. J.Ja

apotheon
apotheon

Notice that some of the best software documentation in the world is in CPAN -- and Perl doesn't have doc generators of the sort you see in those languages that are plagued by tons of "undocumentation". Instead, what Perl provides is nothing to automatically create documentation, but excellent tools to [b]format[/b] the documentation you write, for a number of different file types. If you eliminate the drudgery of having to create the output document types for documentation, but avoid giving the illusion of automatically generated documentation content that you get with automatic syntax documentation generation tools, I think you'll get exactly what Perl has: the best documentation tools I've ever seen, in terms of encouraging good documentation by developers. Since that's really the end result we want, it trumps the whiz-bang automatic documentation tools of other languages like JavaDoc and RDoc.

Editor's Picks