About JSDoc plugins
Creating and Enabling a Plugin
There are two steps required to create and enable a new JSDoc plugin:
- Create a JavaScript module to contain your plugin code.
- Include that module in the
plugins
array of JSDoc's configuration file. You can specify an absolute or relative path. If you use a relative path, JSDoc searches for the plugin in the current working directory; the directory where the configuration file is located; and the JSDoc directory, in that order.
For example, if your plugin is defined in the plugins/shout.js
file in the current working directory, you would add the string plugins/shout
to the plugins
array in your JSDoc configuration file:
Adding a plugin to JSDoc's configuration file
{
"plugins": ["plugins/shout"]
}
JSDoc executes plugins in the order that they are listed in the configuration file.
Authoring JSDoc 3 Plugins
JSDoc 3's plugin system offers extensive control over the parsing process. A plugin can affect the parse results by doing any of the following:
- Defining event handlers
- Defining tags
- Defining a visitor for abstract syntax tree nodes
Event Handlers
At the highest level, a plugin may register handlers for specific named events that JSDoc fires. JSDoc will pass an event object to the handler. Your plugin module should export a handlers
object that contains your handler, like so:
Event-handler plugin for 'newDoclet' events
exports.handlers = {
newDoclet: function(e) {
// Do something when we see a new doclet
}
};
JSDoc fires events in the same order as the underlying code.
An event-handler plugin can stop later plugins from running by setting a stopPropagation
property on the event object (e.stopPropagation = true
). A plugin can stop the event from firing by setting a preventDefault
property (e.preventDefault = true
).
Event: parseBegin
The parseBegin
event is fired before JSDoc starts loading and parsing the source files. Your plugin can control which files JSDoc will parse by modifying the event's contents.
Note: This event is fired in JSDoc 3.2 and later.
The event object contains the following properties:
sourcefiles
: An array of paths to source files that will be parsed.
Event: fileBegin
The fileBegin
event is fired when the parser is about to parse a file. Your plugin can use this event to trigger per-file initialization if necessary.
The event object contains the following properties:
filename
: The name of the file.
Event: beforeParse
The beforeParse
event is fired before parsing has begun. Plugins can use this method to modify the source code that will be parsed. For instance, your plugin could add a JSDoc comment, or it could remove preprocessing tags that are not valid JavaScript.
The event object contains the following properties:
filename
: The name of the file.source
: The contents of the file.
Below is an example that adds a virtual comment 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 available to users, but might not appear in the source code being documented, such as methods provided by an external superclass:
Example
exports.handlers = {
beforeParse: function(e) {
var extraDoc = [
"/**",
" * Function provided by a superclass.",
" * @name superFunc",
" * @memberof ui.mywidget",
" * @function",
" */"
];
e.source += extraDoc.join("\n");
}
};
Event: jsdocCommentFound
The jsdocCommentFound
event is fired whenever a JSDoc comment is found. The comment may or may not be associated with any code. You might use this event to modify the contents of a comment before it is processed.
The event object contains the following properties:
filename
: The name of the file.comment
: The text of the JSDoc comment.lineno
: The line number on which the comment was found.columnno
: The column number on which the comment was found. Available in JSDoc 3.5.0 and later.
Event: symbolFound
The symbolFound
event is fired when the parser comes across a symbol in the code that may need to be documented. For example, the parser fires a symbolFound
event for each variable, function, and object literal in a source file.
The event object contains the following properties:
filename
: The name of the file.comment
: The text of the comment associated with the symbol, if any.id
: The unique ID of the symbol.lineno
: The line number on which the symbol was found.columnno
: The column number on which the symbol was found. Available in JSDoc 3.5.0 and later.range
: An array containing the numeric index of the first and last characters in the source file that are associated with the symbol.astnode
: The symbol's node from the abstract syntax tree.code
: Object with detailed information about the code. This object usually containsname
,type
, andnode
properties. The object might also havevalue
,paramnames
, orfuncscope
properties depending on the symbol.
Event: newDoclet
The newDoclet
event is the highest-level event. It is fired when a new doclet has been created. This means that a JSDoc comment or a symbol has been processed, and the actual doclet that will be passed to the template has been created.
The event object contains the following properties:
doclet
: The new doclet that was created.
The doclet's properties can vary depending on the comment or symbol that the doclet represents. Some common properties you're likely to see include:
comment
: The text of the JSDoc comment, or an empty string if the symbol is undocumented.meta
: Object that describes how the doclet relates to the source file (for example, the location within the source file).description
: A description of the symbol being documented.kind
: The kind of symbol being documented (for example,class
orfunction
).name
: The short name for the symbol (for example,myMethod
).longname
: The fully qualified name, including memberof info (for example,MyClass#myMethod
).memberof
: The module, namespace, or class that this symbol belongs to (for example,MyClass
), or an empty string if the symbol does not have a parent.scope
: The scope of the symbol within its parent (for example,global
,static
,instance
, orinner
).undocumented
: Set totrue
if the symbol did not have a JSDoc comment.defaultvalue
: The default value for a symbol.type
: Object containing details about the symbol's type.params
: Object containing the list of parameters to a function.tags
: Object containing a list of tags that JSDoc did not recognize. Only available ifallowUnknownTags
is set totrue
in JSDoc's configuration file.
To see the doclets that JSDoc generates for your code, run JSDoc with the -X
command-line option.
Below is an example of a newDoclet
handler that shouts the descriptions:
Example
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
The fileComplete
event is fired when the parser has finished parsing a file. Your plugin could use this event to trigger per-file cleanup.
The event object contains the following properties:
filename
: The name of the file.source
: The contents of the file.
Event: parseComplete
The parseComplete
event is fired after JSDoc has parsed all of the specified source files.
Note: This event is fired in JSDoc 3.2 and later.
The event object contains the following properties:
sourcefiles
: An array of paths to source files that were parsed.doclets
: An array of doclet objects. See thenewDoclet
event for details about the properties that each doclet can contain. Available in JSDoc 3.2.1 and later.
Event: processingComplete
The processingComplete
event is fired after JSDoc updates the parse results to reflect inherited and borrowed symbols.
Note: This event is fired in JSDoc 3.2.1 and later.
The event object contains the following properties:
doclets
: An array of doclet objects. See thenewDoclet
event for details about the properties that each doclet can contain.
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:
Example
exports.defineTags = function(dictionary) {
// define tags here
};
The Dictionary
The dictionary provides the following methods:
defineTag(title, opts)
: Used to define tags. The first parameter is the name of the tag (for example,param
oroverview
). The second is an object containing options for the tag. You can include any of the following options; the default value for each option isfalse
:canHaveType (boolean)
: Set totrue
if the tag text can include a type expression (such as{string}
in@param {string} name - Description
).canHaveName (boolean)
: Set totrue
if the tag text can include a name (such asname
in@param {string} name - Description
).isNamespace (boolean)
: Set totrue
if the tag should be applied to the doclet's longname as a namespace. For example, the@module
tag sets this option totrue
, and using the tag@module myModuleName
results in the longnamemodule:myModuleName
.mustHaveValue (boolean)
: Set totrue
if the tag must have a value (such asTheName
in@name TheName
).mustNotHaveDescription (boolean)
: Set totrue
if the tag may have a value but must not have a description (such asTheDescription
in@tag {typeExpr} TheDescription
).mustNotHaveValue (boolean)
: Set totrue
if the tag must not have a value.onTagged (function)
: A callback function executed when the tag is found. The function is passed two parameters: the doclet and the tag object.
lookUp(tagName)
: Retrieve a tag object by name. Returns the tag object, including its options, orfalse
if the tag is not defined.isNamespace(tagName)
: Returnstrue
if the tag is applied to a doclet's longname as a namespace.normalise(tagName)
: Returns the canonical name of a tag. For example, the@const
tag is a synonym for@constant
; as a result, if you callnormalise('const')
, it returns the stringconstant
.normalize(tagName)
: Synonym fornormalise
. Available in JSDoc 3.3.0 and later.
A tag's onTagged
callback can modify the contents of the doclet or tag.
Defining an onTagged callback
dictionary.defineTag("instance", {
onTagged: function(doclet, tag) {
doclet.scope = "instance";
}
});
The defineTag
method returns a Tag
object, which has a synonym
method that can be used to declare a synonym for the tag.
Defining a tag synonym
dictionary
.defineTag("exception", {
/* options for exception tag */
})
.synonym("throws");
Node Visitors
At the lowest level, plugin authors can process each node in the abstract syntax tree (AST) by defining a node visitor that will visit each node. By using a node-visitor plugin, you can modify comments and trigger parser events for any arbitrary piece of code.
Plugins can define a node visitor by exporting an astNodeVisitor
object that contains a visitNode
function, like so:
Example
exports.astNodeVisitor = {
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 AST node. AST nodes are JavaScript objects that use the format defined by the ESTree spec. You can use AST Explorer to see the AST that will be created for your source code. As of version 3.5.0, JSDoc uses the current version of the Babylon parser with all plugins enabled.e
: The event. If the node is one that the parser handles, the event object will already be populated with the same things described in thesymbolFound
event above. Otherwise, it will be an empty object on which to set various properties.parser
: The JSDoc parser instance.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.
As with event-handler plugins, a node-visitor plugin can stop later plugins from running by setting a stopPropagation
property on the event object (e.stopPropagation = true
). A plugin can stop the event from firing by setting a preventDefault
property (e.preventDefault = true
).
Reporting Errors
If your plugin needs to report an error, use one of the following methods in the jsdoc/util/logger
module:
logger.warn
: Warn the user about a possible problem.logger.error
: Report an error from which the plugin can recover.logger.fatal
: Report an error that should cause JSDoc to stop running.
Using these methods creates a better user experience than simply throwing an error.
Note: Do not use the jsdoc/util/error
module to report errors. This module is deprecated and will be removed in a future version of JSDoc.
Reporting a non-fatal error
var logger = require("jsdoc/util/logger");
exports.handlers = {
newDoclet: function(e) {
// Your code here.
if (somethingBadHappened) {
logger.error("Oh, no, something bad happened!");
}
}
};