mirror of
https://github.com/konvajs/konva.git
synced 2026-03-03 16:58:33 +08:00
checking in jsdoc dir so people can generate docs themselves
This commit is contained in:
389
jsdoc-master/plugins/README.md
Normal file
389
jsdoc-master/plugins/README.md
Normal file
@@ -0,0 +1,389 @@
|
||||
Creating and Enabling a Plugin
|
||||
----
|
||||
|
||||
There are two steps required to create and enable a new JSDoc plugin:
|
||||
|
||||
1. Create a JavaScript module to contain your plugin code.
|
||||
2. Include that module in the "plugins" array of `conf.json`. You can specify
|
||||
an absolute or relative path. If you use a relative path, JSDoc searches for
|
||||
the plugin in the current working directory and the JSDoc directory, in that
|
||||
order.
|
||||
|
||||
For example, if your plugin source code was saved in the "plugins/shout.js"
|
||||
file in the current working directory, you would include it by adding a
|
||||
reference to it in conf.json like so:
|
||||
|
||||
...
|
||||
"plugins": [
|
||||
"plugins/shout"
|
||||
]
|
||||
...
|
||||
|
||||
Authoring JSDoc 3 Plugins
|
||||
----
|
||||
|
||||
The plugin system for JSDoc 3 is pretty powerful and provides plugin authors
|
||||
multiple methods, from high-level to low-level, of affecting document generation:
|
||||
|
||||
- Defining event handlers
|
||||
- Defining tags
|
||||
- Defining a parse tree node processor
|
||||
|
||||
### Event Handlers
|
||||
|
||||
At the highest level, a plugin may register handlers for specific named-events
|
||||
that occur in the documentation generation process. JSDoc will pass the handler
|
||||
an event object containing pertinent information. Your plugin module should
|
||||
export a _handlers_ object that contains your handler, like so:
|
||||
|
||||
exports.handlers = {
|
||||
newDoclet: function(e) {
|
||||
//Do something when we see a new doclet
|
||||
}
|
||||
}
|
||||
|
||||
#### Event: fileBegin
|
||||
|
||||
This is triggered when the parser has started on a new file. You might use this
|
||||
to do any per-file initialization your plugin needs to do.
|
||||
|
||||
The event object will contain the following properties:
|
||||
|
||||
- filename: the name of the file
|
||||
|
||||
#### Event: beforeParse
|
||||
|
||||
This is triggered before parsing has begun. You can use this method to modify
|
||||
the source code that will be parsed. For instance, you might add some virtual
|
||||
doclets so they get added to the documentation.
|
||||
|
||||
The event object will contain the following properties:
|
||||
|
||||
- filename: the name of the file
|
||||
- source: the contents of the file
|
||||
|
||||
Below is an example that adds a virtual doclet for a function to the source so
|
||||
that it will get parsed and added to the documentation. This might be done to
|
||||
document methods that will be present for end-user use, but might not be in the
|
||||
source code being documented, like methods provided by a third-party superclass:
|
||||
|
||||
exports.handlers = {
|
||||
beforeParse: function(e) {
|
||||
var extraDoc = ["",
|
||||
"/**",
|
||||
"Here's a description of this function",
|
||||
"@name superFunc",
|
||||
"@memberof ui.mywidget",
|
||||
"@function",
|
||||
"*/", ""];
|
||||
e.source += extraDoc.join("\n");
|
||||
}
|
||||
}
|
||||
|
||||
#### Event: jsdocCommentFound
|
||||
|
||||
This is fired whenever a jsdoc comment is found. It may or may not be associated
|
||||
with any code. You might use this to modify the contents of a comment before it
|
||||
is processed.
|
||||
|
||||
The event object will contain the following properties:
|
||||
|
||||
- filename: the name of the file
|
||||
- comment: the text of the comment
|
||||
- lineno: the line number the comment was found on
|
||||
|
||||
#### Event: symbolFound
|
||||
|
||||
This is fired when the parser comes across a symbol in the code it thinks is
|
||||
important. This usually means things that one might want to document --
|
||||
variables, functions, object literals, object property definitions,
|
||||
assignments, etc., but the symbols the parser finds can be modified by a plugin
|
||||
(see "Node Visitors" below).
|
||||
|
||||
The event object will contain the following properties:
|
||||
|
||||
- filename: the name of the file
|
||||
- comment: the comment associated with the symbol, if any
|
||||
- id: the unique id of the symbol
|
||||
- lineno: the line number the symbols was found on
|
||||
- range: an array containing the first and last characters of the code
|
||||
associated with the symbol
|
||||
- astnode: the node of the parse tree
|
||||
- code: information about the code. This usually contains "name", "type", and
|
||||
"node" properties and might also have "value", "paramnames", or "funcscope"
|
||||
properties depending on the symbol.
|
||||
|
||||
#### Event: newDoclet
|
||||
|
||||
This is the highest level event and is fired when a new doclet has been created.
|
||||
This means that a jsdoc or a symbol has been processed and the actual doclet
|
||||
that will be passed to the template has been created.
|
||||
|
||||
The event object will contain the following properties:
|
||||
|
||||
- doclet: the new doclet that was created
|
||||
|
||||
The properties of the doclet can vary depending on the comment or symbol used to
|
||||
create it. Additionally, tag definitions (See "Tag Definitions" below) can
|
||||
modify the doclet. Some common properties you're likely to see include:
|
||||
|
||||
- comment: the text of the comment (may be empty if symbol is undocumented)
|
||||
- meta: some information about the doclet, like filename, line number, etc.
|
||||
- description
|
||||
- kind
|
||||
- name
|
||||
- longname: the fully qualified name, including memberof info
|
||||
- memberof: the function/class/namespace that this is a member of
|
||||
- scope: (global|static|instance|inner)
|
||||
- undocumented: true if the symbol didn't have a jsdoc comment
|
||||
- defaultvalue: the specified default value for a property/variable
|
||||
- type: the specified type of parameter/property/function return (e.g. Boolean)
|
||||
- params: an object containing the list of parameters to a function
|
||||
- tags: an object containing the set of tags not handled by the parser (note:
|
||||
this is only available if ```allowUnknownTags``` is set to true in the conf.json
|
||||
file for JSDoc3)
|
||||
|
||||
Below is an example of a newDoclet handler that shouts the descriptions:
|
||||
|
||||
exports.handlers = {
|
||||
newDoclet: function(e) {
|
||||
// e.doclet will refer to the newly created doclet
|
||||
// you can read and modify properties of that doclet if you wish
|
||||
if (typeof e.doclet.description === 'string') {
|
||||
e.doclet.description = e.doclet.description.toUpperCase();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#### Event: fileComplete
|
||||
|
||||
This is fired when the parser is done with a file. You might use this to
|
||||
perform some cleanup for your plugin.
|
||||
|
||||
The event object will contain the following properties:
|
||||
|
||||
- filename: the name of the file
|
||||
- source: the contents of the file
|
||||
|
||||
### Tag Definitions
|
||||
|
||||
Adding tags to the tag dictionary is a mid-level way to affect documentation
|
||||
generation. Before a newDoclet event is triggered, jsdoc comment blocks are
|
||||
parsed to determine the description and any jsdoc tags that may be present. When
|
||||
a tag is found, if it has been defined in the tag dictionary, it is given a
|
||||
chance to modify the doclet.
|
||||
|
||||
Plugins can define tags by exporting a _defineTags_ function. That function will
|
||||
be passed a dictionary that can be used to define tags, like so:
|
||||
|
||||
exports.defineTags = function(dictionary) {
|
||||
//define tags here
|
||||
}
|
||||
|
||||
#### The Dictionary
|
||||
|
||||
The dictionary provides the following methods:
|
||||
|
||||
1. defineTag(title, opts)
|
||||
Used to define tags.
|
||||
The first parameter is the name of the tag (e.g. "param" or "overview"). the
|
||||
second is an object containing options for the tag. The options can be the
|
||||
following:
|
||||
- mustHaveValue (Boolean): whether or not the tag must have a value
|
||||
(e.g "@name TheName")
|
||||
- mustNotHaveValue (Boolean): whether or not the tag must not have a value
|
||||
- canHaveType (Boolean): Whether or not the tag can have a type
|
||||
(e.g. "@param **{String}** name the description of name")
|
||||
- canHaveName (Boolean): Whether or not the tag can have a name
|
||||
(e.g. "@param {String} **name** the description of name")
|
||||
- isNamespace (Boolean): Whether or not the tag marks a doclet as representing
|
||||
a namespace. The "@module" tag, for instance, sets this to true.
|
||||
- onTagged (Function): A callback function executed when the tag is found. The
|
||||
function is passed two parameters: the doclet and the tag. Here's an example:
|
||||
|
||||
dictionary.defineTag('instance', {
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.scope = "instance";
|
||||
}
|
||||
});
|
||||
The defineTag method returns a Tag. The Tag object has a method "synonym"
|
||||
that can be used to declare synonyms to the tag. For example:
|
||||
|
||||
dictionary.defineTag('exception', {
|
||||
<options for exception tag>
|
||||
})
|
||||
.synonym('throws');
|
||||
2. lookUp(title)
|
||||
Used to lookup a tag. Returns either the tag or false if it's not defined
|
||||
3. isNamespace(kind)
|
||||
Used to determine if a particular doclet type represents a namespace
|
||||
4. normalise(title)
|
||||
Used to find the canonical name of a tag. The name passed in might be that
|
||||
name or a synonym
|
||||
|
||||
### Node Visitors
|
||||
|
||||
At the lowest level, plugin authors can process each node in the parse tree by
|
||||
defining a node visitor that will visit each node, creating an opportunity to
|
||||
do things like modify comments and trigger parser events for any arbitrary piece
|
||||
of code.
|
||||
|
||||
Plugins can define a node visitor by exporting a ```nodeVisitor``` object that
|
||||
contains a ```visitNode``` function, like so:
|
||||
|
||||
exports.nodeVisitor = {
|
||||
visitNode: function(node, e, parser, currentSourceName) {
|
||||
//do all sorts of crazy things here
|
||||
}
|
||||
}
|
||||
|
||||
The function is called on each node with the following parameters:
|
||||
|
||||
- node: the node of the parse tree
|
||||
- e: the event. If the node is one that the parser handles, this will already
|
||||
be populated with the same things described in the _symbolFound_ event above.
|
||||
Otherwise, it will be an empty object on which to set various properties.
|
||||
- parser: the parser
|
||||
- currentSourceName: the name of the file being parsed
|
||||
|
||||
#### Making things happen
|
||||
|
||||
The primary reasons to implement a node visitor are to be able to document
|
||||
things that aren't normally documented (like function calls that create classes)
|
||||
or to auto generate documentation for code that isn't documented. For instance,
|
||||
a plugin might look for calls to a "_trigger" method since it knows that means
|
||||
an event is fired and then generate documentation for the event.
|
||||
|
||||
To make things happen, the ```visitNode``` function should modify properties
|
||||
of the event parameter. In general the goal is to construct a comment and then
|
||||
get an event to fire. After the parser lets all of the node visitors have a
|
||||
look at the node, it looks to see if the event object has a ```comment```
|
||||
property and an ```event``` property. If it has both, the event named in the event
|
||||
property is fired. The event is usually "symbolFound" or "jsdocCommentFound",
|
||||
but theoretically, a plugin could define its own events and handle them.
|
||||
|
||||
#### Example
|
||||
|
||||
Below is an example of what a plugin for documenting jQuery UI widgets might do.
|
||||
jQuery UI uses a factory function call to create widget classes. The plugin
|
||||
looks for that function call and creates a symbol with documentation. It also
|
||||
looks for any "this._trigger" function calls and automatically creates
|
||||
documentation for the events that are triggered:
|
||||
|
||||
exports.nodeVisitor = {
|
||||
visitNode: function(node, e, parser, currentSourceName) {
|
||||
if (node.type === Token.OBJECTLIT && node.parent && node.parent.type === Token.CALL && isInWidgetFactory(node, 1)) {
|
||||
var widgetName = node.parent.arguments.get(0).toSource();
|
||||
e.id = 'astnode' + node.hashCode(); // the id of the object literal node
|
||||
e.comment = String(node.parent.jsDoc||'');
|
||||
e.lineno = node.parent.getLineno();
|
||||
e.filename = currentSourceName;
|
||||
e.astnode = node;
|
||||
e.code = {
|
||||
name: "" + widgetName.substring(1, widgetName.length() - 1),
|
||||
type: "class",
|
||||
node: node
|
||||
};
|
||||
e.event = "symbolFound";
|
||||
e.finishers = [parser.addDocletRef];
|
||||
|
||||
addCommentTag(e, "param", "{Object=} options A set of configuration options");
|
||||
}
|
||||
else if(isTriggerCall(node)) {
|
||||
var nameNode = node.arguments.get(0);
|
||||
eventName = String((nameNode.type == Token.STRING) ? nameNode.value : nameNode.toSource()),
|
||||
func = {},
|
||||
comment = "@event\n",
|
||||
eventKey = "";
|
||||
|
||||
if (node.enclosingFunction) {
|
||||
func.id = 'astnode'+node.enclosingFunction.hashCode();
|
||||
func.doclet = parser.refs[func.id];
|
||||
}
|
||||
if(func.doclet) {
|
||||
func.doclet.addTag("fires", eventName);
|
||||
if (func.doclet.memberof) {
|
||||
eventKey = func.doclet.memberof + "#event:" + eventName;
|
||||
comment += "@name " + func.doclet.memberof + "#" + eventName;
|
||||
}
|
||||
}
|
||||
e.comment = comment;
|
||||
e.lineno = node.getLineno();
|
||||
e.filename = currentSourceName;
|
||||
e.event = "jsdocCommentFound";
|
||||
}
|
||||
}
|
||||
};
|
||||
function isTriggerCall(node) {
|
||||
if(node.type != Token.CALL) { return false; }
|
||||
var target = node.getTarget(),
|
||||
left = target && target.left && String(target.left.toSource()),
|
||||
right = target && target.right && String(target.right.toSource());
|
||||
return (left === "this" && right === "_trigger");
|
||||
}
|
||||
|
||||
function isInWidgetFactory(node, depth) {
|
||||
var parent = node.parent,
|
||||
d = 0;
|
||||
while(parent && (!depth || d < depth)) {
|
||||
if (parent.type === Token.CALL) {
|
||||
var target = parent.getTarget(),
|
||||
left = target && target.left && String(target.left.toSource()),
|
||||
right = target && target.right && String(target.right.toSource());
|
||||
return ((left === "$" || left === "jQuery") && right === "widget");
|
||||
} else {
|
||||
parent = parent.parent;
|
||||
d++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
You'll notice a "finishers" property set. The finishers property should contain
|
||||
an array of functions to be called after the event is fired and all the handlers
|
||||
have processed it. The parser provides an ```addDocletRef``` function that adds the
|
||||
doclet to the map (keyed off of the id property) of doclets it knows about.
|
||||
|
||||
Lastly, the visitors are executed in the order the plugins are listed in the
|
||||
conf.json file. A plugin can stop later plugins from visiting a node by
|
||||
setting a ```stopPropagation``` property on the event object (e.stopPropagation = true).
|
||||
A plugin can stop the event from firing setting a ```preventDefault``` property.
|
||||
|
||||
### Throwing Errors
|
||||
|
||||
If you wish your plugin to throw an error, do it using the `handle` function in
|
||||
the `jsdoc/util/error` module:
|
||||
|
||||
require('jsdoc/util/error').handle( new Error('I do not like green eggs and ham!') );
|
||||
|
||||
By default, this will throw the error, halting the execution of JSDoc. However,
|
||||
if the user enabled JSDoc's `--lenient` switch, JSDoc will simply log the error
|
||||
to the console and continue.
|
||||
|
||||
Packaging JSDoc 3 Plugins
|
||||
----
|
||||
|
||||
The JSDoc 3 Jakefile has an ```install``` task that can be used to install a
|
||||
plugin into the JSDoc directory. So running the following will install the
|
||||
plugin:
|
||||
|
||||
$>jake install[path/to/YourPluginFolder]
|
||||
|
||||
**Note**: On some operating systems, including OS X, you may need to quote the
|
||||
target name and parameters:
|
||||
|
||||
$>jake 'install[path/to/YourPluginFolder]'
|
||||
|
||||
The task is passed a directory that should look something like the following:
|
||||
|
||||
YourPluginFolder
|
||||
|- plugins
|
||||
| |- YourPlugin.js
|
||||
| \- test
|
||||
| |- fixtures
|
||||
| | \- YourFixtures.js
|
||||
| \- specs
|
||||
| \- YourTests.js
|
||||
\- templates
|
||||
\- YourTemplate
|
||||
\- publish.js
|
||||
Reference in New Issue
Block a user