关于 JSDoc 插件
创建并启用插件
🌐 Creating and Enabling a Plugin
创建并启用新的 JSDoc 插件需要两个步骤:
🌐 There are two steps required to create and enable a new JSDoc plugin:
- 创建一个 JavaScript 模块来包含你的插件代码。
- 将该模块包含在 JSDoc 的配置文件 的
plugins数组中。你可以指定绝对路径或相对路径。如果使用相对路径,JSDoc 会按以下顺序在当前工作目录、配置文件所在目录以及 JSDoc 目录中搜索插件。
例如,如果你的插件定义在当前工作目录下的 plugins/shout.js 文件中,你需要在 JSDoc 配置文件的 plugins 数组中添加字符串 plugins/shout:
🌐 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:
{
"plugins": ["plugins/shout"]
}
JSDoc 按照插件在配置文件中列出的顺序执行插件。
🌐 JSDoc executes plugins in the order that they are listed in the configuration file.
编写 JSDoc 3 插件
🌐 Authoring JSDoc 3 Plugins
JSDoc 3 的插件系统提供了对解析过程的广泛控制。插件可以通过执行以下任何操作来影响解析结果:
🌐 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:
- 定义事件处理程序
- 定义标签
- 为抽象语法树节点定义访问者
事件处理程序
🌐 Event Handlers
在最高层级,一个插件可以为 JSDoc 触发的特定命名事件注册处理程序。JSDoc 会将一个事件对象传递给处理程序。你的插件模块应该导出一个包含你的处理程序的 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:
exports.handlers = {
newDoclet: function(e) {
// Do something when we see a new doclet
}
};
JSDoc 以与底层代码相同的顺序触发事件。
🌐 JSDoc fires events in the same order as the underlying code.
事件处理插件可以通过在事件对象(e.stopPropagation = true)上设置 stopPropagation 属性来阻止后续插件运行。插件可以通过设置 preventDefault 属性(e.preventDefault = true)来阻止事件触发。
🌐 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
parseBegin 事件在 JSDoc 开始加载和解析源文件之前触发。你的插件可以通过修改该事件的内容来控制 JSDoc 将解析哪些文件。
🌐 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.
注意:此事件在 JSDoc 3.2 及更高版本中触发。
事件对象包含以下属性:
🌐 The event object contains the following properties:
sourcefiles:一个包含将被解析的源文件路径的数组。
事件:文件开始
🌐 Event: fileBegin
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:文件的名称。
事件:beforeParse
🌐 Event: beforeParse
beforeParse 事件在解析开始之前触发。插件可以使用此方法修改将要解析的源代码。例如,你的插件可以添加一个 JSDoc 注释,或者可以删除不符合 JavaScript 规范的预处理标签。
🌐 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:文件的名称。source:文件的内容。
下面是一个示例,向源代码中为一个函数添加虚拟注释,以便它能被解析并添加到文档中。这可能用于记录将对用户可用的方法,但可能不会出现在被记录的源代码中,例如由外部超类提供的方法:
🌐 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:
exports.handlers = {
beforeParse: function(e) {
var extraDoc = [
'/**',
' * Function provided by a superclass.',
' * @name superFunc',
' * @memberof ui.mywidget',
' * @function',
' */'
];
e.source += extraDoc.join('\n');
}
};
事件:发现 jsdoc 注释
🌐 Event: jsdocCommentFound
jsdocCommentFound 事件在每次发现 JSDoc 注释时触发。该注释可能与任何代码相关,也可能无关。你可以使用此事件在注释被处理之前修改其内容。
🌐 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:文件的名称。comment:JSDoc 注释的内容。lineno:发现注释的行号。columnno:发现注释的列号。适用于 JSDoc 3.5.0 及更高版本。
事件:符号已找到
🌐 Event: symbolFound
symbolFound 事件在解析器遇到代码中可能需要记录的符号时触发。例如,解析器会为源文件中的每个变量、函数和对象字面量触发 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:文件的名称。comment:与符号相关的注释文本(如果有)。id:符号的唯一 ID。lineno:找到符号的行号。columnno:找到符号的列号。JSDoc 3.5.0 及更高版本可用。range:包含源文件中与符号关联的第一个和最后一个字符的数字索引的数组。astnode:抽象语法树中符号的节点。code:包含代码详细信息的对象。此对象通常包含name、type和node属性。根据符号的不同,该对象也可能具有value、paramnames或funcscope属性。
事件:newDoclet
🌐 Event: newDoclet
newDoclet 事件是最高级别的事件。当创建了一个新的文档元素时会触发该事件。这意味着一个 JSDoc 注释或一个符号已经被处理,并且将传递给模板的实际文档元素已经被创建。
🌐 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:新创建的文档片段。
Doclet 的属性可能会根据 doclet 所代表的注释或符号而有所不同。一些你可能会看到的常见属性包括:
🌐 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,classorfunction).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 totrueif 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 ifallowUnknownTagsis set totruein JSDoc's configuration file.
要查看 JSDoc 为你的代码生成的文档片段,请使用 -X 命令行选项 运行 JSDoc。
🌐 To see the doclets that JSDoc generates for your code, run JSDoc with the -X command-line
option.
下面是一个 newDoclet 处理程序的示例,它会大声喊出描述内容:
🌐 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
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:文件的名称。source:文件的内容。
事件:解析完成
🌐 Event: parseComplete
parseComplete 事件在 JSDoc 解析完所有指定的源文件后触发。
🌐 The parseComplete event is fired after JSDoc has parsed all of the specified source files.
注意:此事件在 JSDoc 3.2 及更高版本中触发。
事件对象包含以下属性:
🌐 The event object contains the following properties:
sourcefiles:已解析的源文件路径数组。doclets:doclet 对象数组。有关每个 doclet 可以包含的属性的详细信息,请参见newDoclet事件。在 JSDoc 3.2.1 及更高版本中可用。
事件:处理完成
🌐 Event: processingComplete
processingComplete 事件在 JSDoc 更新解析结果以反映继承和借用的符号之后触发。
🌐 The processingComplete event is fired after JSDoc updates the parse results to reflect inherited
and borrowed symbols.
注意:此事件在 JSDoc 3.2.1 及更高版本中触发。
事件对象包含以下属性:
🌐 The event object contains the following properties:
doclets:一个 doclet 对象数组。有关每个 doclet 可以包含的属性的详细信息,请参见newDoclet事件。
标签定义
🌐 Tag Definitions
向标签字典添加标签是一种中等级别的方法来影响文档生成。在触发 newDoclet 事件之前,JSDoc 注释块会被解析以确定描述和可能存在的任何 JSDoc 标签。当找到一个标签时,如果它已在标签字典中定义,它将有机会修改 doclet。
🌐 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.
插件可以通过导出一个 defineTags 函数来定义标签。该函数将传入一个可以用来定义标签的字典,如下所示:
🌐 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:
defineTag(title, opts): Used to define tags. The first parameter is the name of the tag (for example,paramoroverview). 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 totrueif the tag text can include a type expression (such as{string}in@param {string} name - Description).canHaveName (boolean): Set totrueif the tag text can include a name (such asnamein@param {string} name - Description).isNamespace (boolean): Set totrueif the tag should be applied to the doclet's longname as a namespace. For example, the@moduletag sets this option totrue, and using the tag@module myModuleNameresults in the longnamemodule:myModuleName.mustHaveValue (boolean): Set totrueif the tag must have a value (such asTheNamein@name TheName).mustNotHaveDescription (boolean): Set totrueif the tag may have a value but must not have a description (such asTheDescriptionin@tag {typeExpr} TheDescription).mustNotHaveValue (boolean): Set totrueif 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, orfalseif the tag is not defined.isNamespace(tagName): Returnstrueif the tag is applied to a doclet's longname as a namespace.normalise(tagName): Returns the canonical name of a tag. For example, the@consttag 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.
标签的 onTagged 回调可以修改文档对象或标签的内容。
🌐 A tag's onTagged callback can modify the contents of the doclet or tag.
dictionary.defineTag('instance', {
onTagged: function(doclet, tag) {
doclet.scope = "instance";
}
});
defineTag 方法返回一个 Tag 对象,该对象具有一个 synonym 方法,可用于为标签声明同义词。
🌐 The defineTag method returns a Tag object, which has a synonym method that can be used to
declare a synonym for the tag.
dictionary.defineTag('exception', { /* options for exception tag */ })
.synonym('throws');
节点访问者
🌐 Node Visitors
在最低层次上,插件作者可以通过定义一个节点访问器来处理抽象语法树(AST)中的每个节点,该访问器将访问每个节点。通过使用节点访问器插件,你可以修改注释并为任意代码片段触发解析器事件。
🌐 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.
插件可以通过导出一个包含 visitNode 函数的 astNodeVisitor 对象来定义节点访问器,如下所示:
🌐 Plugins can define a node visitor by exporting an astNodeVisitor object that contains a
visitNode function, like so:
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:AST 节点。AST 节点是使用 ESTree 规范 定义的格式的 JavaScript 对象。你可以使用 AST 浏览器 查看将为你的源代码创建的 AST。从版本 3.5.0 起,JSDoc 使用带有启用所有插件的当前版本 巴比伦 解析器。e:事件。如果该节点是解析器处理的节点,则事件对象将已经填充上与上面symbolFound事件中描述的相同内容。否则,它将是一个空对象,可在其上设置各种属性。parser:JSDoc 解析器实例。currentSourceName:正在解析的文件名。
让事情发生
🌐 Making things happen
实现节点访问器的主要原因是能够记录通常不被记录的内容(例如创建类的函数调用),或者为未被记录的代码自动生成文档。例如,一个插件可能会查找对 _trigger 方法的调用,因为它知道这意味着事件被触发,然后为该事件生成文档。
🌐 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.
要让事情发生,visitNode 函数应该修改事件参数的属性。一般来说,目标是构造一个评论,然后触发一个事件。在解析器让所有节点访问者查看节点之后,它会检查事件对象是否具有 comment 属性和 event 属性。如果两者都有,就会触发事件属性中命名的事件。这个事件通常是 symbolFound 或 jsdocCommentFound,但理论上,插件可以定义自己的事件并处理它们。
🌐 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.
与事件处理程序插件一样,节点访问者插件可以通过在事件对象(e.stopPropagation = true)上设置 stopPropagation 属性来阻止后续插件运行。插件可以通过设置 preventDefault 属性(e.preventDefault = true)来阻止事件触发。
🌐 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
如果你的插件需要报告错误,请在 jsdoc/util/logger 模块中使用以下方法之一:
🌐 If your plugin needs to report an error, use one of the following methods in the jsdoc/util/logger
module:
logger.warn:警告用户可能出现的问题。logger.error:报告一个插件可以恢复的错误。logger.fatal:报告一个应该导致 JSDoc 停止运行的错误。
使用这些方法可以比简单地抛出错误创造更好的用户体验。
🌐 Using these methods creates a better user experience than simply throwing an error.
注意:不要使用 jsdoc/util/error 模块来报告错误。该模块已被弃用,并将在未来的 JSDoc 版本中移除。
var logger = require('jsdoc/util/logger');
exports.handlers = {
newDoclet: function(e) {
// Your code here.
if (somethingBadHappened) {
logger.error('Oh, no, something bad happened!');
}
}
};