buy the book to support the author.

Chapter 29. JSDoc: Generating API Documentation

It is a common development problem: you have written JavaScript code that is to be used by others and need a nice-looking HTML documentation of its API. The de facto standard tool in the JavaScript world for generating API documentation is JSDoc.[23] It is modeled after its Java analog, JavaDoc.

JSDoc takes JavaScript code with /* / comments (normal block comments that start with an asterisk) and produces HTML documentation for it. For example, given the following code:

  1. /** @namespace */
  2. var util = {
  3. /**
  4. * Repeat <tt>str</tt> several times.
  5. * @param {string} str The string to repeat.
  6. * @param {number} [times=1] How many times to repeat the string.
  7. * @returns {string}
  8. */
  9. repeat: function(str, times) {
  10. if (times === undefined || times < 1) {
  11. times = 1;
  12. }
  13. return new Array(times+1).join(str);
  14. }
  15. };

the generated HTML looks as shown in Figure 29-1 in a web browser.

HTML output produced by JSDoc.

Figure 29-1. HTML output produced by JSDoc.

The Readme on the JSDoc website explains how to install and call this tool.

The Basics of JSDoc

JSDoc is all about documenting entities (functions, methods, constructors, etc.). That is achieved via comments that precede the entities and start with /**.

Syntax

Let’s review the comment shown at the beginning:

  1. /**
  2. * Repeat <tt>str</tt> several times.
  3. * @param {string} str The string to repeat.
  4. * @param {number} [times=1] How many times to repeat the string.
  5. * @returns {string}
  6. */

This demonstrates some of the JSDoc syntax, which consists of thefollowing pieces:

  • JSDoc comment
  • This is a JavaScript block comment whose first character is an asterisk. This creates the illusion that the token /** starts such a comment.
  • Tags
  • You structure comments by starting lines with tags, keywords that are prefixed with an @ symbol. @param is an example in the preceding code.
  • HTML
  • You can freely use HTML in JSDoc comments. For example, <tt> displays a word in a monospaced font.
  • Type annotations
  • You can document the type of an entity via a type name in braces. Variations include:
  • Single type: @param {string} name
  • Multiple types: @param {string|number} idCode
  • Arrays of a type: @param {string[]} names
  • Namepaths
  • Inside JSDoc comments, so-called namepaths are used to refer to entities. The syntax of such paths is as follows:
  1. myFunction
  2. MyClass
  3. MyClass.staticMember
  4. MyClass#instanceMember

Classes are usually (implemented by) constructors. Static members are, for example, properties of constructors. JSDoc has a broad definition of instance member. It means everything that can be accessed via an instance. Therefore, instance members include instance properties and prototype properties.

Naming Types

The types of entities are either primitive types or classes. The names of the former always start with lowercase letters; the names of the latter always start with uppercase letters. In other words, the type names of primitives are boolean, number, and string, just like the results returned by the typeof operator. That way, you cannot confuse strings (primitives) with instances of the constructor String (objects).

Basic Tags

Following are the basic metadata tags:

  • @fileOverview description
  • Marks a JSDoc comment that describes thewhole file. For example:
  1. /**
  2. * @fileOverview Various tool functions.
  3. * @author <a href="mailto:jd@example.com">John Doe</a>
  4. * @version 3.1.2
  5. */
  • @author
  • Refers to who has written the entity being documented.
  • @deprecated
  • Indicates that the entity is not supported anymore. It is a good practice to document what to use instead.
  • @example
  • Contains a code example illustrating how the given entityshould be used:
  1. /**
  2. * @example
  3. * var str = 'abc';
  4. * console.log(repeat(str, 3)); // abcabcabc
  5. */

Basic tags for linking are as follows:

  • @see
  • Points to a related resource:
  1. /**
  2. * @see MyConstructor#myMethod
  3. * @see The <a href="http://example.com">Example Project</a>.
  4. */
  • {@link …}
  • Works like @see, but can be used inside other tags.
  • @requires resourceDescription
  • Indicates a resource that the documented entityneeds. The resource description is either a namepath or a naturallanguage description.

Versioning tags include the following:

  • @version versionNumber
  • Indicates the version of the documentedentity. For example:

  1. @version 10.3.1

  • @since versionNumber
  • Indicates since which version the documentedentity has been available. For example:

  1. @since 10.2.0

Documenting Functions and Methods

For functions and methods, you can document parameters, return values, and exceptions they may throw:

  • @param {paramType} paramName description
  • Describes the parameter whose name is paramName. Type and description are optional. Here are some examples:

  1. @param str The string to repeat.
  2. @param {string} str
  3. @param {string} str The string to repeat.

Advanced features:

  • Optional parameter:

  1. @param {number} [times] The number of times is optional.

  • Optional parameter with default value:

  1. @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 type annotations to @param and @returns:

  1. /**
  2. * @param {String} name
  3. * @returns {Object}
  4. */
  5. function getPerson(name) {
  6. }

Second, you can inline the type information:

  1. function getPerson(/**String*/ name) /**Object*/ {
  2. }

Documenting Variables, Parameters, and Instance Properties

The following tags are used for documenting variables, parameters, and instance properties:

  • @type {typeName}
  • What type does the documented variable have? For example:
  1. /** @type {number} */
  2. var carCounter = 0;

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.
  1. /** @constant */
  2. var FORD = 'Ford';
  • @property {propType} propKey description
  • Document an instance property in the constructor comment. For example:
  1. /**
  2. * @constructor
  3. * @property {string} name The name of the person.
  4. */
  5. function Person(name) {
  6. this.name = name;
  7. }

Alternatively, instance properties can be documented as follows:

  1. /**
  2. * @class
  3. */
  4. function Person(name) {
  5. /**
  6. * The name of the person.
  7. * @type {string}
  8. */
  9. this.name = name;
  10. }

Which one of those styles to use is a matter of personal preference.

  • @default defaultValue
  • What is the default value of a parameter or instance property?For example:
  1. /** @constructor */
  2. function Page(title) {
  3. /**
  4. * @default 'Untitled'
  5. */
  6. this.title = title || 'Untitled';
  7. }

Documenting Classes

JSDoc distinguishes between classes and constructors. The former concept is more like a type, while a constructor is one way of implementing a class.JavaScript’s built-in means for defining classes are limited, which is why there are many APIs that help with this task. These APIs differ, often radically, so you have to help JSDoc with figuring out what is going on. The following tags let you do that:

  • @constructor
  • Marks a function as a constructor.
  • @class
  • Marks a variable or a function as a class. In the latter case, @class is a synonym for @constructor.
  • @constructs
  • Records that a method sets up the instance data. If such a method exists, the class is documented there.
  • @lends namePath
  • Specifies to which class the following object literal contributes. There are two ways of contributing.
  • @lends Person#: The object literal contributes instance members to Person.
  • @lends Person: The object literal contributes static members to Person.
  • @memberof parentNamePath
  • The documented entity is a member of the specified object. @lends MyClass#, applied to an object literal, has the same effect as marking each property of that literal with @memberof MyClass#.

The most common ways of defining a class are: via a constructor function, via an object literal, and via an object literal that has an @constructs method.

Defining a Class via a Constructor Function

To define a class via a constructor function, you must mark the constructor function; otherwise, it will not be documented as a class. Capitalization alone does not mark a function as a constructor:

  1. /**
  2. * A class for managing persons.
  3. * @constructor
  4. */
  5. function Person(name) {
  6. }

Defining a Class via an Object Literal

To define a class via an 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. You do the latter via the @lends tag:

  1. /**
  2. * A class for managing persons.
  3. * @class
  4. */
  5. var Person = makeClass(
  6. /** @lends Person# */
  7. {
  8. say: function(message) {
  9. return 'This person says: ' + message;
  10. }
  11. }
  12. );

Defining a Class via an Object Literal with an @constructs Method

If an object literal has an @constructs method, you need to tell JSDoc about it, so that it can find the documentation for the instance properties. The documentation of the class moves to that method:

  1. var Person = makeClass(
  2. /** @lends Person# */
  3. {
  4. /**
  5. * A class for managing persons.
  6. * @constructs
  7. */
  8. initialize: function(name) {
  9. this.name = name;
  10. },
  11. say: function(message) {
  12. return this.name + ' says: ' + message;
  13. }
  14. }
  15. );

If you omit the @lends, you must specify which class the methods belong to:

  1. var Person = makeClass({
  2. /**
  3. * A class for managing persons.
  4. * @constructs Person
  5. */
  6. initialize: function(name) {
  7. this.name = name;
  8. },
  9. /** @memberof Person# */
  10. say: function(message) {
  11. return this.name + ' says: ' + message;
  12. }
  13. }
  14. );

Subclassing

JavaScript has no built-in support for subclassing. When you subclass in your code (be it manually, be it via a library), you have to tell JSDoc what is going on:

  • @extends namePath
  • Indicates that the documented class is thesubclass of another one. For example:
  1. /**
  2. * @constructor
  3. * @extends Person
  4. */
  5. function Programmer(name) {
  6. Person.call(this, name);
  7. ...
  8. }
  9. // Remaining code for subclassing omitted

Other Useful Tags

All of these tags are documented at the JSDoc website:

  • Modularity: @module, @exports, @namespace
  • Custom types (for virtual entities such as callbacks, whose signature you can document): @typedef, @callback
  • Legal matters: @copyright, @license
  • Various kinds of objects: @mixin, @enum

[23] The JSDoc website is the main source of this chapter; some examples are borrowed from it.