An introduction to JSDoc

[2011-08-17] dev, javascript, jslang, jstools
(Ad, please don’t block)

Check out my book (free online): “Speaking JavaScript”. Updated version of this blog post: chapter “JSDoc: Generating API Documentation”.

Update 2011-08-19. Tweet from JSDoc’s creator, Michael Mathews:
Awesome article about JSDoc. I learned (er remembered) a few things from reading it myself! via @rauschma 2ality.com/2011/08/jsdoc-intro.html

JSDoc is the de facto standard for documenting JavaScript code. You need to know at least its syntax (which is also used by many other tools) if you publish code. Alas, documentation is still scarce, but this post can help – it shows you how to run JSDoc and how its syntax works. (The JSDoc wiki [2] is the main source of this post, some examples are borrowed from it.)

As a tool, JSDoc takes JavaScript code with special /** */ comments and produces HTML documentation for it. For example: Given the following code.

    /** @namespace */
    var util = {
        /**
         * Repeat <tt>str</tt> several times.
         * @param {string} str The string to repeat.
         * @param {number} [times=1] How many times to repeat the string.
         * @returns {string}
         */
        repeat: function(str, times) {
            if (times === undefined || times < 1) {
                times = 1;
            }
            return new Array(times+1).join(str);
        }
    };
The generated HTML looks as follows in a web browser:
This post begins with a quick start, so can try out JSDoc immediately if you are impatient. Afterwards, more background information is given.

Quick start

For the steps described below, you need to have Java installed. JSDoc includes the shell script jsrun.sh that requires Unix (including OS X and Linux) to run. But it should be easy to translate that script to a Windows batch file.
  • Download the latest jsdoc_toolkit. Unpack the archive into, say, $HOME/jsdoc-toolkit.
  • Make the script $HOME/jsdoc-toolkit/jsrun.sh executable and tell it where to look for the JSDoc binary and the template (which controls what the result looks like).
        JSDOCDIR="$HOME/local/jsdoc-toolkit"
        JSDOCTEMPLATEDIR="$JSDOCDIR/templates/jsdoc"
    
    Now you can move the script anywhere you want to, e.g. a bin/ directory. For the purpose of this demonstration, we don’t move the script.
  • Use jsrun.sh on a directory of JavaScript files:
    $HOME/jsdoc-toolkit/jsrun.sh -d=$HOME/doc $HOME/js
    
    • Input: $HOME/js – a directory of JavaScript files (see below for an example).
    • Output: $HOME/doc – where to write the generated files.
If you put the JavaScript code at the beginning of this post into a file $HOME/js/util.js then JSDoc produces the following files:
    $HOME/doc
    ├── files.html
    ├── index.html
    └── symbols
        ├── _global_.html
        ├── src
        │   └── util.js.html
        └── util.html

Introduction: What is JSDoc?

It’s a common programming problem: You have written JavaScript code that is to be used by others and need a nice-looking HTML documentation of its API. Java has pioneered this domain via its JavaDoc tool. The quasi-standard in the JavaScript world is JSDoc. As seen above, you document an entity by putting before it a special comment that starts with two asterisks.

Templates. In order to output anything, JSDoc always needs a template, a mix of JavaScript and specially marked-up HTML that tells it how to translate the parsed documentation to HTML. JSDoc comes with a built-in template, but there are others that you can download [3].

Terminology and conventions of JSDoc

  • Doclet: JSDoc calls its comments doclets which clashes with JavaDoc terminology where such comments are called doc comments and a doclet is similar to a JSDoc template, but written in Java.
  • Variable: The term variable in JSDoc often refers to all documentable entities which include global variables, object properties, and inner members.
  • Instance properties: In JavaScript one typically puts methods into a prototype to share them with all instances of a class, while fields (non-function-valued properties) are put into each instance. JSDoc conflates shared properties and per-instance properties and calls them instance properties.
  • Class properties, static properties: are properties of classes, usually of constructor functions. For example, Object.create is a class property of Object.
  • Inner members: An inner member is data nested inside a function. Most relevant for documentation is instance-private data nested inside a constructor function.
        function MyClass() {
            var privateCounter = 0; // an inner member
            this.inc = function() { // an instance property
                privateCounter++;
            };
        }
    

Syntax

Let’s review the comment shown at the beginning:
    /**
     * Repeat <tt>str</tt> several times.
     * @param {string} str The string to repeat.
     * @param {number} [times=1] How many times to repeat the string.
     * @returns {string}
     */
This demonstrates some of the JSDoc syntax which consists of the following pieces.
  • JSDoc comment: is a JavaScript block comment whose first character is an asterisk. This creates the illusion that the token /** starts such a comment.
  • Tags: Comments are structured by starting lines with tags, keywords that are prefixed with an @ symbol. @param is an example above.
  • HTML: You can freely use HTML in JSDoc comments; for example, <tt> to display a word in a monospaced font.
  • Type annotations: You can document the type of a value by putting the type name in braces after the appropriate tags. Variations:
    Single type:@param {string} name
    Multiple types:@param {string|number} idCode
    Arrays of a type:@param {string[]} names
  • Name paths: are used to refer to variables inside JSDoc comments. The syntax of such paths is as follows.
        myFunction
        MyConstructor
        MyConstructor.classProperty
        MyConstructor#instanceProperty
        MyConstructor-innerMember
    

A word on types

There are two kinds of values in JavaScript: primitives and objects [7].
  • Primitive types: boolean, number, string. The values undefined and null are also considered primitive.
  • Object types: All other types are object types, including arrays and functions.
Watch out: the names of primitive types start with a lowercase letter. Each primitive type has a corresponding wrapper type, an object type with a capital name whose instances are objects. In contrast to some other programming languages (such as Java), you will hardly ever use wrapper types.
  • The wrapper type of boolean is Boolean.
  • The wrapper type of number is Number.
  • The wrapper type of string is String.
Getting the name of the type of a value:
  • Primitive value p: via typeof p.
        > typeof ""
        'string'
    
    Compare: an instance of the wrapper type is an object.
        > typeof new String()
        'object'
    
  • Object value o: via o.constructor.name. Example:
        > new String().constructor.name
        'String'
    

Basic tags

Meta-data:
  • @fileOverview description: marks a JSDoc comment that describes the whole file. Example:
        /**
         * @fileOverview Various tool functions.
         * @author <a href="mailto:jd@example.com">John Doe</a>
         * @version 3.1.2
         */
    
  • @author: Who has written the variable being documented?
  • @deprecated: indicates that the variable is not supported, any more. It is a good practice to document what to use instead.
  • @example: contains a code example, illustrating how the given entity should be used.
        /**
         * @example
         * var str = "abc";
         * console.log(repeat(str, 3)); // abcabcabc
         */
    
Linking:
  • @see: points to a related resource.
    /**
     * @see MyClass#myInstanceMethod
     * @see The <a href="http://example.com">Example Project</a>.
     */
    
  • {@link ...}: works like @see, but can be used inside other tags.
  • @requires resourceDescription: a resource that the documented entity needs. The resource description is either a name path or a natural language description.
Versioning:
  • @version versionNumber: indicates the version of the documented entity. Example:
        @version 10.3.1
    
  • @since versionNumber: indicates since which version the documented entity has been available. Example:
        @since 10.2.0
    

Documenting functions and methods

For functions and methods, one can document parameters, return values, and exceptions they might throw.
  • @param {paramType} paramName description: describes the parameter whose name is paramName. Type and description are optional. Examples:
        @param str
        @param str The string to repeat.
        @param {string} str
        @param {string} str The string to repeat.
    
    Advanced features:
    • Optional parameter:
          @param {number} [times] The number of times is optional.
      
    • Optional parameter with default value:
          @param {number} [times=1] The number of times is optional.
      
  • @returns {returnType} description: describes the return value of the function or method. Either type or description can be omitted.
  • @throws {exceptionType} description: describes an exception that might be thrown during the execution of the function or method. Either type or description can be omitted.

Inline type information (“inline doc comments”)

There are two ways of providing type information for parameters and return values. First, you can add a type annotation to @param and @returns.
    /**
     * @param {String} name
     * @returns {Object}
     */
    function getPerson(name) {
    }
Second, you can inline the type information:
    function getPerson(/**String*/ name) /**Object*/ {
    }

Documenting variables and fields

Fields are properties with non-function values. Because instance fields are often created inside a constructor, you have to document them there.
  • @type {typeName}: What type does the documented variable have? Example:
        /** @constructor */
        function Car(make, owner) {
            /** @type {string} */
            this.make = make;
    
            /** @type {Person} */
            this.owner = owner;
        }
        @type {Person}
    
    This tag can also be used to document the return type of functions, but @returns is preferable in this case.
  • @constant: A flag that indicates that the documented variable has a constant value.
  • @default defaultValue: What is the default value of a variable? Example:
        /** @constructor */
        function Page(title) {
            /**
             * @default "Untitled"
             */
             this.title = title || "Untitled";
        }
    
  • @property {propType} propName description: Document an instance property in the class comment. Example:
        /**
         * @class
         * @property {string} name The name of the person.
         */
        function Person(name) {
            this.name = name;
        }
    
    Without this tag, instance properties are documented as follows.
        /**
         * @class
         */
        function Person(name) {
            /**
             * The name of the person.
             * @type {string}
             */
            this.name = name;
        }
    
    Which one of those styles to use is a matter of taste. @property does introduce redundancies, though.

Documenting classes

JavaScript’s built-in means for defining classes are weak, which is why there are many APIs that help with this task [5]. These APIs differ, often radically, so you have to help JSDoc with figuring out what is going on. There are three basic ways of defining a class:
  • Constructor function: You must mark a constructor function, otherwise it will not be documented as a class. That is, capitalization alone does not mark a function as a constructor.
        /**
         * @constructor
         */
        function Person(name) {
        }
    
    @class is a synonym for @constructor, but it also allows you to describe the class – as opposed to the function setting up an instance (see tag documentation below for an example).
  • API call and object literal: You need two markers. First, you need to tell JSDoc that a given variable holds a class. Second, you need to mark an object literal as defining a class. The latter is done via the @lends tag.
        /** @class */
        var Person = makeClass(
            /** @lends Person# */
            {
                say: function(message) {
                    return "This person says: " + message;
                }
            }
        );
    
  • API call and object literal with a constructor method: If one of the methods in an object literal performs the task of a constructor (setting up instance data, [8]), you need to mark it as such so that fields are found by JSDoc. Then the documentation of the class moves to that method.
        var Person = makeClass(
            /** @lends Person# */
            {
                /**
                 * A class for managing persons.
                 * @constructs
                 */
                initialize: function(name) {
                    this.name = name;
                },
                say: function(message) {
                    return this.name + " says: " + message;
                }
            }
        );
    
Tags:
  • @constructor: marks a function as a constructor.
  • @class: marks a variable as a class or a function as a constructor. Can be used in a constructor comment to separate the description of the constructor (first line below) from the description of the class (second line below).
        /**
         * Creates a new instance of class Person.
         * @class Represents a person.
         */
        Person = function() {
        }
    
  • @constructs: marks a method in an object literal as taking up the duties of a constructor. That is, setting up instance data. In such a case, the class must be documented there. Works in tandem with @lends.
  • @lends namePath: specifies to which class the following object literal contributes. There are two ways of contributing.
    • @lends Person# – the object literal contributes instance properties to Person.
    • @lends Person – the object literal contributes class properties to Person.

Inheritance, namespacing

JavaScript has no simple support for subclassing and no real namespaces [6]. When you are using work-arounds, you therefore have to help JSDoc see what is going on .
  • @extends namePath: indicates that the documented class is the subclass of another one. Example:
        /**
         * @constructor
         * @extends Person
         */
        function Programmer(name) {
            Person.call(this, name);
            ...
        }
        // Remaining code for subclassing omitted
    
  • @augments: a synonym for @extends.
  • @namespace: One can use objects to simulate namespaces in JavaScript. This tag marks such objects. Example:
        /** @namespace */
        var util = {
            ...
        };
    

Meta-tags

Meta-tags are tags that are added to several variables. You put them in a comment that starts with “/**#@+”. They are then added to all variables until JSDoc encounters the closing comment “/**#@-*/”. Example:
    /**#@+
     * @private
     * @memberOf Foo
     */

    function baz() {}
    function zop() {}
    function pez() {}

    /**#@-*/

Rarely used tags

  • @ignore: ignore a variable. Note that variables without /** comments are ignored, anyway.
  • @borrows otherNamePath as this.propName: A variable is just a reference to somewhere else; it is documented there. Example:
        /**
         * @constructor
         * @borrows Remote#transfer as this.send
         */
        function SpecialWriter() {
            this.send = Remote.prototype.transfer;
        }
    
  • @description text: Provide a description, the same as all of the text before the first tag.
Manual categorization. Sometimes JSDoc misinterprets what a variable is. Then you can help it via one of the following tags:
TagMark variable as
@functionfunction
@fieldnon-function value
@publicpublic (especially inner variables)
@privateprivate
@innerinner and thus also private
@staticaccessible without instantiation
Name and membership:
  • @name namePath: override the parsed name and use the given name, instead.
  • @memberOf parentNamePath: the documented variable is a member of the specified object.
Not explained here: @event, see [2].

Related reading

  1. jsdoc-toolkit - A documentation generator for JavaScript: JSDoc homepage on Google Code. Includes a link to the downloads.
  2. JSDoc wiki: the official documentation of JSDoc and source of this post.
  3. JSDoc wiki – TemplateGallery: lists available JSDoc templates.
  4. JSDoc wiki – TagReference: a handy cheat-sheet for JSDoc tags.
  5. Lightweight JavaScript inheritance APIs
  6. Modules and namespaces in JavaScript
  7. JavaScript values: not everything is an object
  8. Prototypes as classes – an introduction to JavaScript inheritance