Skip to content
nene edited this page Feb 20, 2012 · 60 revisions

Writing documentation is hard. Writing good documentation is even harder. And for most developers there's a constant pressure to concentrate on all other more important things besides the documentation. There's never enough time for writing docs.

And that's why JSDuck aims to make the process of writing documentation as painless as possible.

First off JSDuck allows you to Markdown for structuring your text:

    /**
     * Returns description of the time of the day.
     *
     * Different heuristics are used to come up with the **most** appropriate
     * wording for the current user.
     *
     * @return {String} Possible return values are:
     *
     * - midday
     * - late night
     * - early morning
     * - just before lunch
     * - tea time
     */
    getDayTime: function() {

You can also use HTML, because Markdown allows embedding of HTML, which will come in handy if you have a lot of legacy documentation written for ext-doc.

Second, JSDuck tries to infer as much information from code as possible. For this it looks at the code that immediately follows the doc-comment. To see this in action, we have to get into the details...

Classes

Documenting an Ext JS 4 class will be a breeze if you are using the standard Ext.define syntax:

    /**
     * A duck, not just a stupid bird.
     */
    Ext.define("Duck", {
        extend: "Bird",
        mixins: {
            observe: 'Ext.util.Observable',
            fly: 'Fliable'
        },
        alternateClassName: ['JustDuck', 'MyDuck'],
        alias: 'widget.duck',
        requires: ['Wing', 'Tail'],
        uses: ['Water'],
        singleton: true,

JSDuck will automatically recognize that this is a doc-comment for class Duck and will also understand all the special class configs.

But JavaScript is a dynamic language and there are bazillion ways to define a class. JSDuck will only auto-detect all these properties when you strictly follow the above form. But don't lose hope, you can always use @tags to say things explicitly:

    /**
     * @class Duck
     * A duck, not just a stupid bird.
     * @extends Bird
     * @mixins Ext.util.Observable
     * @mixins Fliable
     * @alternateClassName JustDuck
     * @alternateClassName MyDuck
     * @alias widget.duck
     * @requires Wing
     * @requires Tail
     * @uses Water
     * @singleton
     */
    (function() {
        this.Duck = {
            extend: "Bird",
            mixins: {
                observe: 'Ext.util.Observable',
                fly: 'Fliable'
            },
            alternateClassName: ['JustDuck', 'MyDuck'],
            alias: 'widget.duck',
            requires: ['Wing', 'Tail'],
            uses: ['Water'],
            singleton: true,

JSDuck also supports Ext.extend syntax from Ext JS 3, automatically detecting the name of the class and parent:

    /**
     * A duck, not just a stupid bird.
     * @xtype duck
     */
    Duck = Ext.extend(Bird, {
        ...
    });
    Ext.reg('duck', Duck); // register xtype

Finally, JSDuck will assume a class definition when doc-comment is followed by assignment to a variable that looks like a class name (begins with uppercase letter):

    /**
     * A simple class.
     */
    namespace.MyClass = {};

It can also be a named function:

    /**
     * A simple class.
     */
    function MyClass(){};

Lastly there are few properties of classes that can't be auto-detected:

  • @private marks the class as being for internal use only.
  • @ignore removes the class together with all of its members completely from the docs, as if it wasn't documented at all.
  • @author and @docauthor allow documenting the names of code and documentation authors. You might want to check out the --meta-tags command line option for specifying additional tags like these.

Members

All doc-comments following a class doc-comment will be assumed to be members of that class. There are four types of members: configs, properties, methods, events.

Only methods are auto-detected. Everything not looking like a method will be assumed to be a property. So be sure to always use @event and @cfg for documenting events and configs.

Methods

When doc-comment is followed by a function it's auto-detected as method. When auto-detection fails you can use @method optionally followed by a function name. A common example where auto-detection fails is closures:

    /**
     * Returns a unique ID for use in HTML id attribute.
     * @param {String} [prefix="id-"] The prefix for the ID.
     * @return {String} the new ID
     * @method
     */
    getId: (function(){
        var map = {};
        return function(prefix){ return ++map[prefix || "id-"]; };
    })(),

Here you can also see the syntax for optional parameters (these are enclosed in square brackets) and their default values. There's also an old syntax for optional parameters where you write "(optional)" right after parameter name.

I won't bother explaining the normal @param and @return syntax and will instead diverge into a more complex example:

    /**
     * Calculates the score for each item in the array.
     *
     * @param {Array} array The input array.
     *
     * @param {Function} fn The callback function.
     * For every item in array the function will be called with:
     * @param {Mixed} fn.item The item itself.
     * @param {Number} fn.index Index of the item.
     * @param {Number} fn.return Should return a numeric score between 0 and 1.
     *
     * @param {Object} scope Value for `this`.
     *
     * @return {Object[]} Array of objects with fields:
     * @return {Mixed} return.item The original item
     * @return {Number} return.score The score
     */
    score: function(array, fn, scope){

Here you see a syntax for describing parameters and return values of Function or Object type. For objects you can describe each property. For callback functions you can describe the parameters and return value. And of course you can do this all recursively however complex parameters or return values you need.

For template methods, meant to be overridden for extending the class, use the @template tag to differentiate them in docs.

Constructors are documented just like normal methods:

    /**
     * Creates new Duck from proper duck egg.
     * @param {DuckEgg} egg  Egg with DNA configuration for new duck.
     */
    constructor: function(egg) {

You can also use the @constructor tag which for JSDuck means @method constructor. The @constructor tag can for legacy reasons be used inside class doc-comment. Don't use it like this in new code.

Events

Events are a lot like methods, except that they don't have return values. Also it probably doesn't make sense to have optional parameters.

    /**
     * @event
     * Triggered after component gets hidden.
     * @param {Ext.Component}
     */
    "hide",

@event can be followed by event name, but in the above case it is auto-detected.

Configs

Configs are a lot like method parameters. They can have default values and sub-properties.

    /**
     * @cfg {Object} size Size of the item.
     * @cfg {Number} [size.width=0]
     * @cfg {Number} [size.height=0]
     */
    size: {width: 0, height: 0},

For configs with simple literal values one can take advantage of auto-detection of the type, the name and even of the default value:

    /**
     * @cfg
     * CSS class names to apply for root element.
     */
    cls: ["x-component", "x-item"],

The above will be auto detected as config option cls of type String[] with default value ["x-component", "x-item"].

JsDuck will auto-detect Number, String, Boolean, RegExp and Function types. Everything else will be labeled as Object.

Unlike with parameters, all configs are optional by default. But there is a special syntax for marking up required configs:

    /**
     * @cfg {Ext.data.Store} store (required)
     * The store to use for this view.
     */

For Ext JS 4 configs that get auto-generated get/set methods the @accessor tag can be used to let JSDuck also generate automatic getter/setter documentation:

    Ext.define("MyClass", {
        config: {
            /**
             * @cfg {Ext.data.Store} store (required)
             * The store to use for this view.
             * @accessor
             */
            store: undefined
        }
    });

This will be interpreted by JSDuck as if you had written:

    Ext.define("MyClass", {
        config: {
            /**
             * @cfg {Ext.data.Store} store (required)
             * The store to use for this view.
             */
            store: undefined
            /**
             * @method setStore
             * Sets the value of {@link #store}.
             * @param {Ext.data.Store} store
             */
            /**
             * @method getStore
             * Returns the value of {@link #store}.
             * @return {Ext.data.Store}
             */
        }
    });

Config options may also be defined in eventedConfig: property which additionally generates a '<config-name>change' event. To auto-document that event include @evented tag alongside @accessor.

Configs can also be part of class doc-comment. This is to support legacy code. Don't use this.

Properties

The syntax for @property is almost the same as for @cfg (there can be no required properties and @accessor's):

    /**
     * @property {Boolean} [readOnly=false]
     * True when component is in read-only state.
     */

Like with configs, you can take advantage of auto-detection. And with properties you can leave off the @property tag entirely:

    /**
     * True when component is in read-only state.
     */
    readOnly: false,

For properties there is one extra legacy tag - @type - which just defines the type of the property:

    /**
     * True when component is in read-only state.
     * @type Boolean
     */
    readOnly: getReadOnly(),

Common tags for all members

All types of members share the following tags:

  • @hide hides a member of a parent class. Useful if child class doesn't support everything parent supports. (One should generally keep the Liskov substitution principle in mind though.)

  • @ignore removes the member completely from documentation. As if the doc-comment never was there.

  • @private marks member as private. (Private methods shouldn't be called from outside of the class itself).

  • @protected marks member as protected. (Protected methods should be only called by child classes).

  • @static marks member as static. Note that static members aren't inherited by default.

  • @inheritable makes a static member inheritable.

  • @deprecated marks member as deprecated. It's optionally followed by version number and description. For example @deprecated 4.0.6 Use {@link #foo} instead.

  • @member ClassName defines that the member belongs to the specified class, not to the one who's doc-comment precedes it.

  • @inheritdoc - inherits documentation from another member - see "Sharing documentation" section for details.

Not all of these will make sense for all types of members.

Type definitions

Throughout this guide you've seen type definitions like {Number}. These aren't just arbitrary strings enclosed in curly braces - there's a specific syntax for specifying types and JSDuck will check that you follow it. Here's a short overview of supported syntax:

  • {Ext.Element} - a single Ext.Element.
  • {String[]} - array of strings.
  • {String[][]} - 2D array of strings.
  • {Number/String/Boolean} - either number, string, or boolean.
  • {Boolean...} - variable number of boolean arguments.

JSDuck will also check that you don't reference any unknown types. For example if you specify {Foo} and you don't have class Foo included to you documentation, JSDuck will produce a warning. Warnings aren't thrown for JavaScript builtin types (Object, String, Number, Boolean, RegExp, Function, Array, Arguments, Date, Error) and few DOM types (HTMLElement, XMLElement, NodeList, TextNode, CSSStyleSheet, CSSStyleRule, Event). To make JSDuck ignore some other type names use --external=Foo,Bar,...

To document a variable that can be of any type whatsoever, use the Mixed type. But try to keep its use to the minimum, always prefer the {Foo/Bar/Baz} syntax to list possible types.

Cross-references

Inside comments you can link to classes and class members using the {@link} tag:

{@link Class#member link text}

But JSDuck will also automatically create links to classes if it sees NameSpace.Class, SomeClass#method or #method.

For example:

Look at the {@link Duck} class.  There are methods like
Duck#fly and Duck#swim and even this
{@link Duck#walk particularly slow method}.

Now compare it to #move method of this class, that does
all the above.

This will produce something like this:

Look at the Duck class. There are methods like Duck.fly and Duck.swim end even this particularly slow method.

Now compare it to move method of this class, that does all of the above.

Sometimes the name is not enough to uniquely identify a class member. For example Ext.data.Store has a load method and load event. In such case, prepend cfg-, property-, method- or event- to the member name:

Listen to the {@link Ext.data.Store#event-load load event}

Or you might need to reference a static method when an instance method of the same name exists:

Use {@link Ext.form.field.Field#static-method-getName getName} to get class name.

For links to other websites, and things within the docs app itself like guides, use Markdown links:

See [Getting Started Guide](#!/guide/getting_started) or check
out [Sencha website][1] for more.

[1]: http://www.sencha.com/

Images

You can include images inside the documentation using the {@img} tag:

{@img path/to/image.png alt text}

The paths should be relative to the directory specified by --images option (there can be more than one to list multiple search paths).

For ExtJS 4 you can simply refer to the doc-resources directory of downloaded release:

$ jsduck extjs-4.0.7/src --images=extjs-4.0.7/docs/doc-resources --output my-docs

All the linked images will then be copied over to output directory, while {@img} tags will become repleced with markup like:

<p><img src="doc-resources/path/to/image.png" alt="alt text"/></p>

For full control over the created markup you can use the --img command line option.

Sharing documentation

Sometimes you have documented a config option extensively in parent class:

    /**
     * @cfg
     * Some very long documentation...
     */
    shape: 'line',

But in subclass you want to change the default value of the config. Now it would be good if the documentation of subclass reflected this change, but you don't want to duplicate the long documentation again. That's where @inheritdoc steps in:

    /**
     * @cfg
     * @inheritdoc
     */
    shape: 'rectangle'

Another common use of @inheritdoc is defining an alias for some method. For example Ext.each is alias for Ext.Array.each. In such case specify the class and member to inherit:

    /**
     * @member Ext
     * @method each
     * @inheritdoc Ext.Array#each
     */
    Ext.each = Ext.Array.each
Clone this wiki locally