10000 update node-visitor plugin docs for JSDoc 3.3.0 (#98) · removed-usr/jsdoc.github.io@fba0ada · GitHub
[go: up one dir, main page]

Skip to content

Commit fba0ada

Browse files
committed
update node-visitor plugin docs for JSDoc 3.3.0 (jsdoc#98)
1 parent 11255b4 commit fba0ada

File tree

2 files changed

+71
-219
lines changed

2 files changed

+71
-219
lines changed

about-plugins.html

Lines changed: 28 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -39,29 +39,28 @@ <h2>Table of Contents</h2>
3939
<li>
4040
<a href="#node-visitors">Node Visitors</a>
4141
</li>
42-
<li>
43-
<a href="#reporting-errors">Reporting Errors</a>
44-
</li>
4542
</ul>
4643
</li>
44+
<li>
45+
<a href="#reporting-errors">Reporting Errors</a>
46+
</li>
4747
</ul>
4848
<h2 id="creating-and-enabling-a-plugin">Creating and Enabling a Plugin</h2>
4949
<p>There are two steps required to create and enable a new JSDoc plugin:</p>
5050
<ol>
5151
<li>Create a JavaScript module to contain your plugin code.</li>
52-
<li>Include that module in the <code>plugins</code> array of <code>conf.json</code>. You can specify an absolute or relative path. If you use a relative path,
53-
JSDoc searches for the plugin in the current working directory and the JSDoc directory, in that order.</li>
52+
<li>Include that module in the <code>plugins</code> array of <a href="about-configuring-jsdoc.html">JSDoc&#39;s configuration file</a>. You can specify an absolute
53+
or relative path. If you use a relative path, JSDoc searches for the plugin in the directory where the configuration file is located; the current working
54+
directory; and the JSDoc directory, in that order.</li>
5455
</ol>
55-
<p>For example, if your plugin source code was saved in the <code>plugins/shout.js</code> file in the current working directory, you would include it by adding
56-
a reference to it in <code>conf.json</code> like so:</p>
56+
<p>For example, if your plugin is defined in the <code>plugins/shout.js</code> file in the current working directory, you would add the string <code>plugins/shout</code> to the <code>plugins</code> array in your JSDoc configuration file:</p>
5757
<figure>
58-
<figcaption>Example</figcaption><pre class="prettyprint"><code>...
59-
"plugins": [
60-
"plugins/shout"
61-
]
62-
...
58+
<figcaption>Adding a plugin to JSDoc&#39;s configuration file</figcaption><pre class="prettyprint lang-json"><code>{
59+
"plugins": ["plugins/shout"]
60+
}
6361
</code></pre>
6462
</figure>
63+
<p>JSDoc executes plugins in the order that they are listed in the configuration file.</p>
6564
<h2 id="authoring-jsdoc-3-plugins">Authoring JSDoc 3 Plugins</h2>
6665
<p>JSDoc 3&#39;s plugin system offers extensive control over the parsing process. A plugin can affect the parse results by doing any of the following:</p>
6766
<ul>
@@ -70,11 +69,10 @@ <h2 id="authoring-jsdoc-3-plugins">Authoring JSDoc 3 Plugins</h2>
7069
<li>Defining a visitor for abstract syntax tree nodes</li>
7170
</ul>
7271
<h3 id="event-handlers">Event Handlers</h3>
73-
<p>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
74-
an event object containing pertinent information. Your plugin module should export a <code>handlers</code> object that contains your handler, like so:
75-
</p>
72+
<p>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
73+
module should export a <code>handlers</code> object that contains your handler, like so:</p>
7674
<figure>
77-
<figcaption>Example</figcaption><pre class="prettyprint lang-js"><code>exports.handlers = {
75+
<figcaption>Event-handler plugin for &#39;newDoclet&#39; events</figcaption><pre class="prettyprint lang-js"><code>exports.handlers = {
7876
newDoclet: function(e) {
7977
// Do something when we see a new doclet
8078
}
@@ -83,6 +81,8 @@ <h3 id="event-handlers">Event Handlers</h3>
8381
</figure>
8482
<p>On Node.js, JSDoc fires events in the same order as the underlying code. On Mozilla Rhino, JSDoc fires all of the <code>jsdocCommentFound</code> events at once
8583
as soon as it starts parsing a file; all other events are fired in the same order as the underlying code.</p>
84+
<p>An event-handler plugin can stop later plugins from running by setting a <code>stopPropagation</code> property on the event object (<code>e.stopPropagation = true</code>).
85+
A plugin can stop the event from firing by setting a <code>preventDefault</code> property (<code>e.preventDefault = true</code>).</p>
8686
<h4 id="event-parsebegin">Event: parseBegin</h4>
8787
<p>The <code>parseBegin</code> event is fired before JSDoc starts loading and parsing the source files. Your plugin can control which files JSDoc will parse by
8888
modifying the event&#39;s contents.</p>
@@ -263,11 +263,12 @@ <h4 id="the-dictionary">The Dictionary</h4>
263263
</code></pre>
264264
</figure>
265265
<h3 id="node-visitors">Node Visitors</h3>
266-
<p>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, creating an
267-
opportunity to do things like modify comments and trigger parser events for any arbitrary piece of code.</p>
268-
<p>Plugins can define a node visitor by exporting a <code>nodeVisitor</code> object that contains a <code>visitNode</code> function, like so:</p>
266+
<p>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
267+
node-visitor plugin, you can modify comments and trigger parser events for any arbitrary piece of code.</p>
268+
<p>Plugins can define a node visitor by exporting an <code>astNodeVisitor</code> object that contains a
269+
<code>visitNode</code> function, like so:</p>
269270
<figure>
270-
<figcaption>Example</figcaption><pre class="prettyprint lang-js"><code>exports.nodeVisitor = {
271+
<figcaption>Example</figcaption><pre class="prettyprint lang-js"><code>exports.astNodeVisitor = {
271272
visitNode: function(node, e, parser, currentSourceName) {
272273
// do all sorts of crazy things here
273274
}
@@ -276,101 +277,23 @@ <h3 id="node-visitors">Node Visitors</h3>
276277
</figure>
277278
<p>The function is called on each node with the following parameters:</p>
278279
<ul>
279-
<li><code>node</code>: The AST node.</li>
280+
<li><code>node</code>: The AST node. AST nodes are JavaScript objects that use the format defined by the Mozilla Parser API. You can use <a href="http://esprima.org/demo/parse.html">Esprima&#39;s parser demo</a> to see the AST that will be created for your source code.</li>
280281
<li><code>e</code>: The event. If the node is one that the parser handles, the event object will already be populated with the same things described in the <code>symbolFound</code> event above. Otherwise, it will be an empty object on which to set various properties.</li>
281282
<li><code>parser</code>: The JSDoc parser instance.</li>
282283
<li><code>currentSourceName</code>: The name of the file being parsed.</li>
283284
</ul>
285+
<p>If you run JSDoc on Mozilla Rhino, you can also export a <code>nodeVisitor</code> object that contains a
286+
<code>visitNode</code> function. The <code>visitNode</code> function receives the same parameters as for <code>astNodeVisitor</code> objects, but the <code>node</code> parameter is a Rhino AST node, which is a Java object, rather than an Esprima-style JavaScript object. Rhino node visitors are deprecated as of JSDoc 3.3.0,
287+
and support will be removed in a future version of JSDoc.</p>
284288
<h4 id="making-things-happen">Making things happen</h4>
285289
<p>The primary reasons to implement a node visitor are to be able to document things that aren&#39;t normally documented (like function calls that create classes)
286290
or to auto generate documentation for code that isn&#39;t documented. For instance, a plugin might look for calls to a <code>_trigger</code> method since it
287291
knows that means an event is fired and then generate documentation for the event.</p>
288292
<p>To make things happen, the <code>visitNode</code> function should modify properties of the event parameter. In general the goal is to construct a comment and
289293
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 <code>comment</code> property and an <code>event</code> property. If it has both, the event named in the event property is fired. The event is usually <code>symbolFound</code> or <code>jsdocCommentFound</code>, but theoretically, a plugin could define its own events and handle them.</p>
290-
<h4 id="example-of-a-node-visitor">Example of a node visitor</h4>
291-
<p>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
292-
looks for that function call and creates a symbol with documentation. It also looks for any <code>this._trigger</code> function calls and automatically creates
293-
documentation for the events that are triggered:</p>
294-
<figure>
295-
<figcaption>Example</figcaption><pre class="prettyprint lang-js"><code>exports.nodeVisitor = {
296-
visitNode: function(node, e, parser, currentSourceName) {
297-
if (node.type === Token.OBJECTLIT && node.parent && node.parent.type === Token.CALL &&
298-
isInWidgetFactory(node, 1)) {
299-
var widgetName = node.parent.arguments.get(0).toSource();
300-
e.id = 'astnode' + node.hashCode(); // the id of the object literal node
301-
e.comment = String(node.parent.jsDoc||'');
302-
e.lineno = node.parent.getLineno();
303-
e.filename = currentSourceName;
304-
e.astnode = node;
305-
e.code = {
306-
name: "" + widgetName.substring(1, widgetName.length() - 1),
307-
type: "class",
308-
node: node
309-
};
310-
e.event = "symbolFound";
311-
e.finishers = [parser.addDocletRef];
312-
313-
addCommentTag(e, "param", "{Object=} options A set of configuration options");
314-
}
315-
else if (isTriggerCall(node)) {
316-
var nameNode = node.arguments.get(0);
317-
eventName = String((nameNode.type == Token.STRING) ? nameNode.value : nameNode.toSource()),
318-
func = {},
319-
comment = "@event\n",
320-
eventKey = "";
321-
322-
if (node.enclosingFunction) {
323-
func.id = 'astnode'+node.enclosingFunction.hashCode();
324-
func.doclet = parser.refs[func.id];
325-
}
326-
if (func.doclet) {
327-
func.doclet.addTag("fires", eventName);
328-
if (func.doclet.memberof) {
329-
eventKey = func.doclet.memberof + "#event:" + eventName;
330-
comment += "@name " + func.doclet.memberof + "#" + eventName;
331-
}
332-
}
333-
e.comment = comment;
334-
e.lineno = node.getLineno();
335-
e.filename = currentSourceName;
336-
e.event = "jsdocCommentFound";
337-
}
338-
}
339-
};
340-
341-
function isTriggerCall(node) {
342-
if(node.type != Token.CALL) { return false; }
343-
var target = node.getTarget(),
344-
left = target && target.left && String(target.left.toSource()),
345-
right = target && target.right && String(target.right.toSource());
346-
return (left === "this" && right === "_trigger");
347-
}
348-
349-
function isInWidgetFactory(node, depth) {
350-
var parent = node.parent,
351-
d = 0;
352-
while (parent && (!depth || d &lt; depth)) {
353-
if (parent.type === Token.CALL) {
354-
var target = parent.getTarget(),
355-
left = target && target.left && String(target.left.toSource()),
356-
right = target && target.right && String(target.right.toSource());
357-
return ((left === "$" || left === "jQuery") && right === "widget");
358-
} else {
359-
parent = parent.parent;
360-
d++;
361-
}
362-
}
363-
return false;
364-
}
365-
</code></pre>
366-
</figure>
367-
<p>You&#39;ll notice a <code>finishers</code> property set. The finishers property should contain an array of functions to be called after the event is fired and
368-
all the handlers have processed it. The parser provides an <code>addDocletRef</code> function that adds the doclet to the map (keyed off of the id property)
369-
of doclets it knows about.</p>
370-
<p>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
371-
a <code>stopPropagation</code> property on the event object (<code>e.stopPropagation = true</code>). A plugin can stop the event from firing by setting a
372-
<code>preventDefault</code> property.</p>
373-
<h3 id="reporting-errors">Reporting Errors</h3>
294+
<p>As with event-handler plugins, a node-visitor plugin can stop later plugins from running by setting a <code>stopPropagation</code> property on the event object
295+
(<code>e.stopPropagation = true</code>). A plugin can stop the event from firing by setting a <code>preventDefault</code> property (<code>e.preventDefault = true</code>).</p>
296+
<h2 id="reporting-errors">Reporting Errors</h2>
374297
<p>If your plugin needs to report an error, use one of the following methods in the <code>jsdoc/util/logger</code> module:
375298
</p>
376299
<ul>

0 commit comments

Comments
 (0)
0