-
Notifications
You must be signed in to change notification settings - Fork 240
Guide
Writing documentation is hard. Writing good documentation is even harder. And most developers are under ever-lasting pressure to concentrate on everything besides the documentation. There is never enough time for writing the docs.
And that's why JSDuck aims to make documentation as painless as possible.
First off JSDuck chooses Markdown to ease the structuring of 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...
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'
},
singleton: true,
JSDuck will automatically recognize that this is a doc-comment for class Duck
and will auto-detect several tags from the config object: @extends, @mixins and @singleton.
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
* @singleton
*/
var x = {};
JSDuck also supports Ext.extend
syntax from Ext JS 3, automatically detecting the name of the class itself and its parent:
/**
* A duck, not just a stupid bird.
*/
Duck = Ext.extend(Bird, {
...
});
See @class documentation for details.
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.
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.
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 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.
Special @preventable
tag can be used to denote that returning false from event handler will cause the action - that's supposed to follow the event - to be canceled.
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.
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,
@readonly
tag can be used to denote read-only properties.
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(),
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. -
@abstract
marks member as abstract. -
@deprecated
marks member as deprecated. It's optionally followed by version number and description. For example@deprecated 4.0.6 Use {@link #foo} instead
. -
@removed
marks member as removed. It's syntax is similar to @deprecated:@removed 4.0 Some comment
. -
@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. -
@markdown
is just ignored for backwards compatibility. There's no need for using it as everything is Markdown-formatted by default.
Not all of these will make sense for all types of members.
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.
In addition to this, JSDuck has full support for Google Closure Compiler Type Expressions. So you can even use complex type expressions like this:
{function((number|string), RegExp=): boolean}
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 primitive types:
boolean
number
string
undefined
void
for built-in JavaScript types:
Object
String
Number
Boolean
RegExp
Function
Array
Arguments
Date
Error
and for 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.
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/
For links to guides, videos and examples, check out also the @aside tag.
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.
This feature should be considered experimental, but at the moment you can include videos from Vimeo with a simple line like that:
{@video vimeo 465123 Some description here...}
The number is Vimeo clip ID.
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