关于JSDoc插件

Creating and Enabling a Plugin(创建并启用插件)

创建并启用新JSDoc插件,需要两个步骤:

  1. 创建一个包含你的插件代码的JavaScript模块.
  2. 将该模块添加到JSDoc配置文件plugins数组中。你可以指定一个绝对或相对路径。如果使用相对路径,JSDoc按照相对于配置文件所在的目录,当前的工作目录和JSDoc安装目录的顺序搜索插件。

例如,如果你的插件是在当前工作目录下,plugins/shout.js文件中定义的,你应该在JSDoc配置文件中的plugins数组中添加字符串plugins/shout

例如,在JSDoc配置文件中添加一个插件:

{
    "plugins": ["plugins/shout"]
}

JSDoc按配置文件plugins数组中列出的顺序执行的插件。

Authoring JSDoc 3 Plugins(创建JSDoc3插件)

JSDoc 3的插件系统广泛的控制着解析过程。一个插件可以通过执行以下任何一项操作,影响解析结果:

  • 定义事件处理程序
  • 定义标签
  • 定义一个抽象语法树节点的访问者

Event Handlers(事件处理程序)

最高级别,一个插件可以注册具体命名事件的处理程序,让JSDoc触发。 JSDoc将一个事件对象传递给处理程序。你的插件模块要导出一个包含处理程序的handlers对象,像这样。

例如,事件处理程序插件 'newDoclet' 事件:

exports.handlers = {
    newDoclet: function(e) {
        // Do something when we see a new doclet
    }
};

JSDoc触发事件的顺序和底层代码是一样。

事件处理程序插件可以通过设置事件对象的stopPropagation属性(e.stopPropagation = true)停止运行后面的插件。一个插件可以通过设置preventDefault属性(e.preventDefault = true)阻止触发事件。

事件: parseBegin

JSDoc开始加载和解析源文件之前,parseBegin事件被触发。你的插件可以通过修改事件的内容,来控制哪些文件将被JSDoc解析。

注意:此事件在JSDoc3.2及更高版本有效。

该事件对象包含下列属性:

  • sourcefiles:源文件的路径数组,这些源文件将被解析。

事件: fileBegin

当解析器即将解析一个文件fileBegin事件触发。如果需要,你的插件可以使用此事件触发每个文件的初始化。

该事件对象包含下列属性:

  • filename:文件的名称。

事件: beforeParse

beforeParse事件在解析开始之前被触发。插件可以使用此方法来修改将被解析的源代码。例如,你的插件可以添加一个JSDoc注释,也可以删除不是有效JavaScript的预处理标记。

该事件对象包含下列属性:

  • filename:文件的名称。
  • source:文件的内容。

下面是为一个函数增加了一个虚拟的doclet到源文件的例子,这样它会被解析并添加到文档。这样做,文档的方法就可以提供给用户,但在被文档化的源代码中不可能出现,如由外部超类所提供的方法:

示例:

exports.handlers = {
    beforeParse: function(e) {
        var extraDoc = [
            '/**',
            ' * Function provided by a superclass.',
            ' * @name superFunc',
            ' * @memberof ui.mywidget',
            ' * @function',
            ' */'
        ];
        e.source += extraDoc.join('\n');
    }
};

事件: jsdocCommentFound

每当JSDoc注释被发现,jsdocCommentFound事件就会被触发。注释可以或不与任何代码相关联。您可以在注释被处理之前使用此事件修改注释的内容。

该事件对象包含下列属性:

  • filename: 该文件的名称。
  • comment:JSDoc注释的文本。
  • lineno: 注释被发现的行号。

事件: symbolFound

当解析器在代码中遇到一个可能需要被文档化的标识符时,symbolFound 事件就会被触发。例如,解析器会为源文件中每个变量,函数和对象字面量触发一个symbolFound事件。

该事件对象包含下列属性:

  • filename:该文件的名称。
  • comment:与标识符相关联的任何注释文本。
  • id:标识符的唯一ID。
  • lineno:标识符被发现的行号。
  • range:包含标识符相关联的源文件中第一个和最后一个字符的数字索引的一个数组。
  • astnode:抽象语法树中标识符的节点。
  • code:有关该代码的详细信息的对象。这个对象通常包含name,type, 和 node 属性。对象也可能具有value, paramnames, 或 funcscope属性,这取决于标识符。

事件: newDoclet

newDoclet事件是最高级别的事件。新的doclet已被创建时,它就会被触发。这意味着一个JSDoc注释或标识符已被处理,并且实际传递给模板的doclet已被创建。

该事件对象包含下列属性:

  • doclet: 已被创建的新 doclet 。

所述的doclet的属性取决于doclet表示的注释或标识符。你可能会看到一些共同的属性包括:

  • comment:JSDoc注释文本,或者,如果标识符没被描述,那么该值是一个空字符串。
  • meta:对象,描述doclet如何关联源文件(例如,在源文件中的位置)。
  • description:被记录的标识符的说明。
  • kind:被记录的标识符的种类(例如,class 或者 function)。
  • name:标识符的短名称(例如,myMethod)。
  • longname:全名,其中包含成员信息(例如,MyClass#myMethod)。
  • memberof:该标识符所读的模块,命名空间或类(例如,MyClass),或者,如果该标识符没有父级,那么该值是一个空字符串。
  • scope:标识符在其父级内的作用域范围(例如,global, static, instance,或 inner)。
  • undocumented:如果标识符没有JSDoc注释,设置为true。
  • defaultvalue:标识符的默认值。
  • type:包含关于标识符类型详细信息的对象。
  • params:包含参数列表的对象。
  • tags:对象,包含JSDoc不识别的标记列表。只有当JSDoc的配置文件中allowUnknownTags设置为true时可用。

下面是一个newDoclet 处理程序的一个例子说明:

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();
        }
    }
};

事件: fileComplete

当解析器解析完一个文件时,fileComplete 事件就会被触发。你的插件可以使用这个事件来触发每个文件的清理。

该事件对象包含下列属性:

  • filename: 文件名称.
  • source:该文件的内容.

事件: parseComplete

JSDoc解析所有指定的源文件之后,parseComplete事件就会被触发。

注意:此事件在JSDoc3.2及更高版本会被触发。

该事件对象包含下列属性:

  • sourcefiles:被解析的源代码文件的路径数组。
  • doclets:doclet对象的数组。见newDoclet事件,有关每个的doclet可以包含属性的详细信息。注意:这个属性在JSDoc3.2.1及更高版本中可用。

事件: processingComplete

JSDoc更新反映继承和借来的标识符的解析结果后,processingComplete事件被触发。

注意:此事件在JSDoc3.2.1及更高版本中会被触发。

该事件对象包含下列属性:

  • doclets:doclet对象的数组。见newDoclet事件,有关每个的doclet可以包含属性的详细信息。

Tag Definitions (标签定义)

添加标签到标签字典是影响文档生成的一个中级方式。在一个newDoclet事件被触发前,JSDoc注释块被解析以确定可能存在的说明和任何JSDoc标签。当一个标签被发现,如果它已在标签字典被定义,它就会被赋予一个修改doclet的机会。

插件可以通过导出一个defineTags函数来定义标签。该函数将传递一个可用于定义标签的字典,像这样:

示例:

exports.defineTags = function(dictionary) {
    // define tags here
};

The Dictionary(字典)

字典提供了以下方法:

  • defineTag(title, opts): 用于定义标签。第一个参数是标签的名称(例如,paramoverview)。第二个参数是一个包含标签选项的对象。可以包含以下任一选项;每个选项的默认值都是false

    • canHaveType (boolean): 如果标签文本可以包含一个类型表达式,那么设置为true(如 @param {string} name - Description 中的 {string})。
    • canHaveName (boolean):如果标签文本可以包含一个名称,那么设置为true(如 @param {string} name - Description中的 name )。
    • isNamespace (boolean): 如果该标签是应用doclet的长名称,作为命名空间,那么设置为true。例如,@module标签应设置该选项设置为true,并在标签上使用@module myModuleName的结果为长名称 module:myModuleName
    • mustHaveValue (boolean): 如果该标签必须有一个值,那么设置为true(如 @name TheName中的 TheName )。
    • mustNotHaveDescription (boolean): 如果该标签可能有一个值,但是不是必须有描述,那么设置为true(如 @tag {typeExpr} TheDescription中的 TheDescription )。
    • mustNotHaveValue (boolean):如果该标签必须没有值,那么设置为true
    • onTagged (function):当该标签被发现时,执行的回调函数。该函数传递两个参数:该doclet和该标签对象。
  • lookUp(tagName): 按名称检索标签对象。返回该标签对象,包括它的选项,如果标签没有定义,那么返回false
  • isNamespace(tagName):如果该标签是应用doclet的长名称,作为命名空间,那么返回true
  • normalise(tagName): 返回标签的规范名称。例如,@constant@const标签的同义词;如果你调用normalise('const'),那么返回结果是constant字符串。
  • normalize(tagName): normalise的同义词。在JSDoc3.3.0及更高版本中可用。

标签的onTagged 回调可以修改doclet或标签的内容。

定义一个 onTagged 回调

dictionary.defineTag('instance', {
    onTagged: function(doclet, tag) {
        doclet.scope = "instance";
    }
});

defineTag方法返回一个Tag对象,这个对象有一个synonym方法,这个方法可用于定义该标签的一个同义词。

定义标签同义词

dictionary.defineTag('exception', { /* options for exception tag */ })
    .synonym('throws');

Node Visitors(节点访问者)

在最底层,插件作者可以通过定义一个访问的每个节点的节点访问者来处理在抽象语法树(AST)中的每个节点。通过使用node-visitor插件,您可以修改注释并触发任意一段代码的解析事件。

插件可以通过导出一个包含visitNode 函数的 astNodeVisitor 对象来定义节点访问者,像这样:

示例:

exports.astNodeVisitor = {
    visitNode: function(node, e, parser, currentSourceName) {
        // do all sorts of crazy things here
    }
};

该函数在每个节点上调用,具有以下参数:

  • node:AST的节点。 AST节点是JavaScript对象,使用由Mozilla的解析器API定义的格式。您可以使用Esprima的解析器演示,查看为您的源代码创建的AST。
  • e:事件。如果该节点是一个解析器处理,事件对象将已经被填充,在symbolFound事件上用相同的东西描述。否则,这将是空对象在其上设置各种属性。
  • parser:本JSDoc解析器实例。
  • currentSourceName:该文件的名称被解析。

使事情发生

实现节点访问的首要原因是为了能够记录事情,那些不寻常的记录(创建类像函数调用),或者自动生成文档为未记录的代码。例如,一个插件可能看起来调用到_trigger方法,因为它知道这意味着一个事件被触发,然后生成文档因为这个事件。

为了使事情发生了,visitNode函数应该修改事件参数的属性。一般来说,目标是构建一个注释,然后得到一个事件触发。在分析器可以让所有的节点的访问都来看看节点之后,它会查看是否该事件对象有一个comment释属性和event属性。如果两个都有,在事件属性命名的事件被触发。该事件通常symbolFound or jsdocCommentFound,但理论上,一个插件可以定义自己的事件和处理它们。

与事件处理程序的插件,一个节点访问插件可以停止后面的插件,运行通过在事件对象上设置stopPropagation属性(e.stopPropagation = true)。一个插件可以通过设置的preventDefault属性停止事件触发(e.preventDefault = true)。

Reporting Errors(报告错误)

如果你的插件需要报告错误,使用在jsdoc/util/logger模块中的下列方法之一:

  • logger.warn:发出警告给用户,可能出现的问题。
  • logger.error:报告错误,从该插件可以恢复。
  • logger.fatal:报告错误,应引起JSDoc停止运行。

使用这些方法创建更好的用户体验,不是简单地抛出一个错误。

注意:请不要使用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!');
        }
    }
}