jleyba / js-dossier

A JavaScript documentation generation tool.
Apache License 2.0
150 stars 15 forks source link

Dossier

Dossier is a JSDoc parsing tool built on top of the Closure Compiler. Dossier uses the compiler to parse your code and build a type graph. It then traverses the graph to find types to generate documentation for. Proper use of Closure's annotations will not only improve the type-checking and optimizations of the Closure Compiler, but will also improve Dossier's ability to generate meaningful documentation.

Usage

Dossier requires Java 7 or newer

java -jar dossier.jar -c config.json

Where config.json is a configuration file with the options listed below.

Configuration Options

ES6 Support

Dossier supports ES6 code insofar as the Closure Compiler does. Since the compiler transpiles ES6 to ES5 for analysis, there is some information loss with Dossier. Most notably, type information is lost for Symbol types and generator functions. To use Dossier with ES6 code, in your configuration file, simply set the input language to ES6 or ES6_STRICT (which is the default).

Module Support

Dossier currently recognizes three types of JavaScript modules:

  1. Closure modules identified by goog.module(id) declaration
  2. ES6 modules identified by the use of an export or import declaration
  3. Node-style CommonJS modules

Node modules must be explicitly declared as modules inputs in your configuration file so Dossier knows to look for require() and exports expressions.

For Node and ES6 modules, you may import other modules by their relative path:

import {Foo as Bar} from './lib';  // ES6
const Baz = require('./dir/lib');  // Node

Refer to the section on type linking below for information on how to refer to imported types within a JSDoc comment.

Formatting

Before generating the final HTML output, Dossier runs all comments through a CommonMark parser. Since markdown is sensitive to the leading whitespace on each line, care must be taken with comment formatting. Comments are extracted from the source according to the follow rules:

  1. The /** on the opening line is removed; all subsequent content is considered part of the comment.
  2. On each subsequent line, all whitespace up to the first non-space character is removed.
  3. If the first character on a line after removing whitespace is a *, it is removed from the line. All subsequent content is considered part of the comment.
  4. On the final line, the closing */ is removed.

For example, the JSDoc comment (.'s inserted to highlight whitespace)

/**
.*.Line one.
.*.Line two.
.*
.*.* list item one
.*.* line item two
.*
.*.....code block
.*/

is passed to the parser as

.Line one.
.Line two.

.* list item one
.* list item two

.....code block

When applied to comments attached to annotations, the same rules apply, except the comment text starts after the annotation, type, or name (as applicable for the annotation). For instance,

/**
 * @param {string} x This is the comment for
 *     parameter x.
 */

the comment string parsed for parameter x is (again, .'s inserted to denote leading whitespace):

.This is the comment for
.....parameter x.

The @code and @literal Taglets

The @code and @literal taglets may be used to specify text that should be HTML escaped for rendering; the @code taglet will wrap its output in <code> tags. For example, the following

{@code 1 < 2 && 3 < 4;}

will produce

<code>1 &lt; 2 &amp;&amp; 3 &lt; 4;</code>

Type Linking

Dossier uses the @link and @linkplain taglets to generate links to named types (@link will generate <code> formatted links). The taglet contents up to the first space are parsed as the type name and everything after the space is the link text. If there is no text within the taglet, the type name will be used. For example, suppose there is a type named example.Widget, then

An {@link example.Widget} link.
A {@link example.Widget widget link}.

would produce

An <a href="https://github.com/jleyba/js-dossier/blob/master/path/to/example.Widget.html"><code>example.Widget</code></a> link.
A <a href="https://github.com/jleyba/js-dossier/blob/master/path/to/example.Widget.html"><code>widget link</code></a>.

You may use a hash tag (#) to reference a type's property inside a link: {@link example.Widget#build()}. You may omit the type's name as a qualifier when linking to one of its own properties: {@link #build()}. Dossier will favor instance over static properties when de-referencing a hash link.

Dossier tracks type aliases so your documentation may reflect the actual source. For instance, if you import a type from a module, you may refer to that type by its imported alias:

import {Widget as Whatsit} from './lib';

/** A {@link Whatsit} object. */
export const w = new Whatsit;

Here, the comment on the exported w property produces

<p>A <a href="https://github.com/jleyba/js-dossier/blob/master/module/lib_exports_Widget"><code>Whatsit</code></a> object.</p>

When using the revealing module pattern, your module's documentation can refer to a type by its internal name and Dossier will generate a link to the exported type.

class Widget {}

/** A factory that generates {@link Widget} objects. */
class WidgetFactory {}

export {Widget as WhatsIt, WidgetFactory}

In the above, since Widget's public name is WhatsIt, the generate documentation would be (extra newlines inserted for readability)

<p>A factory that generates
<a href="https://github.com/jleyba/js-dossier/blob/master/module/lib_exports_WhatsIt.html"><code>Widget</code></a> objects.
</p>

Within an ES6 or Node module, you may refer to another module without importing using the module's relative path as your type symbol. To refer to an exported type from another module, simply qualify it with the module's relative path.

/** A link to module {@link ./foo/bar} */
/** A link to type {@link ./foo/bar.Baz} */

The @see Annotation

Use the @see annotation in your JSDoc to add a reference to another type or an external resource. The text context following the annotation is processed in the following order:

  1. The annotation contents are processed as a type link using the rules defined in the previous section. If the contents define a valid reference to another type or property, a link will be included in the HTML output.
  2. If the annotation is a well-formed http or https URL, it will be rendered as a link.
  3. Otherwise, the contents of the annotation are processed as markdown like a comment's main body.

Example

class Greeter {
  /** @param {!Person} person . */
  greet(person) {}
}

/**
 * @see Greeter
 * @see #name
 * @see http://www.example.com
 */
class Person {
  /** @return {string} . */
  name() { return ''; }
}

In this example, the @see annotations on the Person class would generate the following links:

<a href="https://github.com/jleyba/js-dossier/blob/master/Greeter.html"><code>Greeter</code></a>
<a href="https://github.com/jleyba/js-dossier/blob/master/Person.html#name"><code>#name</code></a>
<a href="http://www.example.com">http://www.example.com</a>

HTML Sanitization

All HTML output is sanitized using the owasp HTML sanitizer. Refer to the source for an up-to-date list of the supported HTML tags and attributes.

Building

Dossier is built using Bazel. Once you have installed Bazel, you can use the gendossier.sh script to complete various actions:

./gendossier.sh -h

LICENSE

Copyright 2013-2015 Jason Leyba

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.