sphinx-js

为什么

编写JavaScript库时, 如何向人们解释? 如果它是用户熟悉的域中的一个小项目, 那么JSDoc按字母顺序排列的例程列表就足够了. 但是在一个更大的项目中, 散布散文与API文档是有用的, 而无需复制和粘贴内容.

sphinx-js允许您使用业界领先的 Sphinx 文档工具和JS项目. 它提供了一些指令, 在以Python为中心的 autodoc 之后, 用于将JSDoc格式的文档拉入reStructuredText页面. 而且, 因为您可以在代码中继续使用JSDoc, 所以您仍然可以与其他JS工具兼容, 例如Google的Closure Compiler.

配置

  1. 使用npm安装JSDoc. jsdoc 必须在你的 $PATH 上, 所以你可能想要全局安装它:

    npm install -g jsdoc
    

    我们使用jsdoc 3.4.3,3.5.4, 很可能还有其他版本.

  2. 安装sphinx-js, 它会将Sphinx本身作为一个依赖项:

    pip install sphinx-js
    
  3. 通过运行 sphinx-quickstart 并回答问题, 在项目中创建一个文档文件夹:

    cd my-project
    sphinx-quickstart
    
      > Root path for the documentation [.]: docs
      > Separate source and build directories (y/n) [n]:
      > Name prefix for templates and static dir [_]:
      > Project name: My Project
      > Author name(s): Fred Fredson
      > Project version []: 1.0
      > Project release [1.0]:
      > Project language [en]:
      > Source file suffix [.rst]:
      > Name of your master document (without suffix) [index]:
      > Do you want to use the epub builder (y/n) [n]:
      > autodoc: automatically insert docstrings from modules (y/n) [n]:
      > doctest: automatically test code snippets in doctest blocks (y/n) [n]:
      > intersphinx: link between Sphinx documentation of different projects (y/n) [n]:
      > todo: write "todo" entries that can be shown or hidden on build (y/n) [n]:
      > coverage: checks for documentation coverage (y/n) [n]:
      > imgmath: include math, rendered as PNG or SVG images (y/n) [n]:
      > mathjax: include math, rendered in the browser by MathJax (y/n) [n]:
      > ifconfig: conditional inclusion of content based on config values (y/n) [n]:
      > viewcode: include links to the source code of documented Python objects (y/n) [n]:
      > githubpages: create .nojekyll file to publish the document on GitHub pages (y/n) [n]:
      > Create Makefile? (y/n) [y]:
      > Create Windows command file? (y/n) [y]:
    
  4. 在生成的 Sphinx conf.py 文件中, 将 sphinx_js 添加到 extensions:

    extensions = ['sphinx_js']
    
  5. 如果您的JS源代码在项目的根目录中的任何位置, 请在 conf.py 中自行添加 js_source_path = '../somewhere/else' . JS源代码树的根目录应该是相对于 conf.py 文件的设置指向的位置. (当项目的根目录下有一个 docs 文件夹并且你的源代码直接存在于根目录中时, 默认的 ../ 效果很好. )

  6. 如果您有特殊的jsdoc配置, 请将 jsdoc_config_path = '../conf.json' (例如)添加到 conf.py 中.

  7. 如果您只记录JS而没有其他语言, 则可以在conf.py中将“主域”设置为JS:

    primary_domain = 'js'
    

    然后你可以省略下面指令中的所有 “js:” 前缀.

使用

简而言之, 编写一个充满reStructuredText文件的文件夹, 使用以下指令来获取JSDoc文档, 然后告诉Sphinx通过在docs目录中运行 make html 来渲染它. 如果您之前从未使用过Sphinx或编写过reStructuredText, 那么这里是 我们在其教程中停止的地方 . 为了快速入门, 现在只需向index.rst添加内容即可.

自动功能

首先, 使用标准JSDoc格式记录您的JS代码:

/**
 * Return the ratio of the inline text length of the links in an element to
 * the inline text length of the entire element.
 *
 * @param {Node} node - Types or not: either works.
 * @throws {PartyError|Hearty} Multiple types work fine.
 * @returns {Number} Types and descriptions are both supported.
 */
function linkDensity(node) {
    const length = node.flavors.get('paragraphish').inlineLength;
    const lengthWithoutLinks = inlineTextLength(node.element,
                                                element => element.tagName !== 'A');
    return (length - lengthWithoutLinks) / length;
}

然后, 使用sphinx-js指令引用您的文档. 我们的指令与Sphinx标准的autodoc指令非常相似. 你只能指定一个函数的名字……

.. js:autofunction:: someFunction

…一个格式很好的文档块将显示在您的文档中.

如果要记录可选参数, 也可以输入自己的显式参数列表:

.. js:autofunction:: someFunction(foo, bar[, baz])

参数属性和解构参数也可以使用 标准JSDoc语法:

/**
 * Export an image from the given canvas and save it to the disk.
 *
 * @param {Object} options Output options
 * @param {string} options.format The output format (``jpeg``,  ``png``, or
 *     ``webp``)
 * @param {number} options.quality The output quality when format is
 *     ``jpeg`` or ``webp`` (from ``0.00`` to ``1.00``)
 */
function saveCanvas({ format, quality }) {
    // ...
}

提取默认参数值也很有效. 这些行为符合预期, 但有一些注意事项:

/**
 * You must declare the params, even if you have nothing else to say, so
 * JSDoc will extract the default values.
 *
 * @param [num]
 * @param [str]
 * @param [bool]
 * @param [nil]
 */
function defaultsDocumentedInCode(num=5, str="true", bool=true, nil=null) {}

/**
 * JSDoc guesses types for things like "42". If you have a string-typed
 * default value that looks like a number or boolean, you'll need to
 * specify its type explicitly. Conversely, if you have a more complex
 * value like an arrow function, specify a non-string type on it so it
 * isn't interpreted as a string. Finally, if you have a disjoint type like
 * {string|Array} specify string first if you want your default to be
 * interpreted as a string.
 *
 * @param {function} [func=() => 5]
 * @param [str=some string]
 * @param {string} [strNum=42]
 * @param {string|Array} [strBool=true]
 * @param [num=5]
 * @param [nil=null]
 */
function defaultsDocumentedInDoclet(func, strNum, strBool, num, nil) {}

您甚至可以添加其他内容. 如果这样做, 它将出现在任何提取的文档下面:

.. js:autofunction:: someFunction

    Here are some things that will appear...

    * Below
    * The
    * Extracted
    * Docs

    Enjoy!

js:autofunction 有一个选项, :short-name: , 它对于链接的API很方便, 它们的实现细节你想要看不见. 当你在类方法上使用它时, 文档中不会提到包含类, 函数将在其索引中的短名称下出现, 并且交叉引用也必须使用短名称(:func:`someFunction `):

.. js:autofunction:: someClass#someFunction
   :short-name:

autofunction 也可用于使用 @callback标签 定义的回调.

有一些实验支持滥用 autofunction 来记录 @typedef tags, 虽然结果将被设计为一个函数, 并且 @property 标签会在 “Arguments” 标题下误导. 不过, 在我们能够做到正确之前, 它总比没有好.

autoclass

我们提供了一个 js:autoclass 指令, 它使用类注释和构造函数注释的连接来记录一个类. 它共享 js:autofunction 的所有功能, 甚至采用相同的 :short-name: 标志, 这对于内部类可以派上用场. 使用它的最简单方法是调用它的 :members: 选项, 它自动记录你所有类的所有公共方法和属性:

.. js:autoclass:: SomeEs6Class(constructor, args, if, you[, wish])
   :members:

您可以通过说…添加私人会员:

.. js:autoclass:: SomeEs6Class
   :members:
   :private-members:

隐私由JSDoc @private 标签决定.

:exclude-members: 按名称排除某些成员:

.. js:autoclass:: SomeEs6Class
   :members:
   :exclude-members: Foo, bar, baz

或者明确列出您想要的成员. 我们会尊重您的订购.

.. js:autoclass:: SomeEs6Class
   :members: Qux, qum

显式列出成员时, 可以包含 * 以包含所有未提及的成员. 这对于控制某些元素的排序很有用, 而不必包含详尽的列表.

.. js:autoclass:: SomeEs6Class
   :members: importMethod, *, uncommonlyUsedMethod

最后, 如果你想要完全控制, 可以通过嵌入 js:autofunctionjs:autoattribute 来一次拉一个类成员.

.. js:autoclass:: SomeEs6Class

   .. js:autofunction:: SomeEs6Class#someMethod

   Additional content can go here and appears below the in-code comments,
   allowing you to intersperse long prose passages and examples that you
   don't want in your code.

autoattribute

这对于记录公共属性很有用:

class Fnode {
    constructor(element) {
        /**
         * The raw DOM element this wrapper describes
         */
        this.element = element;
    }
}

然后, 在文档中……:

.. autoclass:: Fnode

   .. autoattribute:: Fnode#element

这也是记录ES6风格的getter和setter的方法, 因为它省略了函数的尾随 () . 假定的做法是通常的JSDoc:只记录你的 getter/setter 对中的一个:

class Bing {
    /** The bong of the bing */
    get bong() {
        return this._bong;
    }

    set bong(newBong) {
        this._bong = newBong * 2;
    }
}

然后, 在文档中……:

.. autoattribute:: Bing#bong

用路径名避免歧义

如果在不同文件中有相同名称的对象, 请使用路径名来消除它们的歧义. 这是一个特别长的例子:

.. js:autofunction:: ./some/dir/some/file.SomeClass#someInstanceMethod.staticMethod~innerMember

您可以从 JSDoc namepaths 中识别分隔符 #. . 他们在这里工作相同.

为简明起见, 您可以使用任何唯一的后缀, 只要它包含完整的路径段即可. 假设它们在源树中是唯一的, 这些都将等同于上述内容:

innerMember
staticMethod~innerMember
SomeClass#someInstanceMethod.staticMethod~innerMember
some/file.SomeClass#someInstanceMethod.staticMethod~innerMember

注意事项:

  • 我们使用简单的文件路径而不是JSDoc的 module: 前缀.

  • 我们使用简单的反斜杠转义, 而不是在路径中途切换转义方案; JSDoc本身 也是如此. 需要转义的字符是 #.~(/, 虽然你不需要在前导 .../ 中逃脱点. 一条非常可怕的路径可能是…::

    some/path\ with\ spaces/file.topLevelObject#instanceMember.staticMember\(with\(parens
    
  • 相对路径相对于config中指定的 js_source_path. 绝对路径是不允许的.

在幕后, sphinx-js 会将所有分隔符更改为点, 以便……

  • Sphinx的“缩短”语法有效: :func:`~InwardRhs.atMost` 只打印 atMost(). (现在, 你应该总是使用点而不是其他名称路径分隔符: #〜. )

  • Sphinx索引信息更多, 称方法属于他们的类.

通过设置主域来保存击键

要保存一些击键, 你可以在conf.py中设置 primary_domain ='js' 然后说(例如) autofunction 而不是 js:autofunction.

TypeScript支持

sphinx-js中有实验性的TypeScript支持. 通过设置配置变量 js_language ='typescript' 来启用它. 然后, 安装TypeDoc(版本0.11.1已知可以工作), 而不是安装JSDoc:

npm install -g typedoc

您将注意到的主要区别是函数文档中的其他 type 字段.

配置参考

js_language

根据您使用的语言, 使用 ‘javascript’ 或 ‘typescript’. 默认为 ‘javascript’.

js_source_path

扫描(非递归)JS文件的目录列表, 相对于Sphinx的conf.py文件. 如果只有一个字符串, 则可以是字符串. 如果有多个, 则必须指定 root_for_relative_js_paths.

jsdoc_config_path

jsdoc或typedoc配置文件的conf.py相对路径, 如果要指定自己的jsdoc选项(如递归和自定义文件名匹配), 这将非常有用.

root_for_relative_js_paths

如果要指定自己的jsdoc选项(例如递归和自定义文件名匹配), 则jsdoc或typedoc配置文件的conf.py相对路径很有用.

示例

使用大多数sphinx-js功能的一个很好的例子是Fathom文档. 一个特别多汁的页面是 https://mozilla.github.io/fathom/ruleset.html. 单击 “查看页面源” 链接以查看原始指令.

ReadTheDocs 是Sphinx文档的规范托管平台, 现在支持sphinx-js作为选择加入测试版. 把它放在你的repo根目录下的 .readthedocs.yml 文件中:

requirements_file: docs/requirements.txt
build:
  image: latest

然后把你想要的sphinx-js版本放在 docs/requirements.txt 中. 例如…:

sphinx-js==2.5

或者, 如果您愿意, Fathom repo带有 Travis CI配置部署脚本 用于使用sphinx-js构建文档并将它们发布到GitHub Pages. 随意借用它们.

注意事项

  • 我们不理解内联JSDoc结构, 如 {@link foo};你现在必须使用Sphinx风格的等价物, 比如 :js:func:`foo` (或者只是 :func:`foo` 如果你设置 primary_domain ='js' 在conf.py.

  • 到目前为止, 我们理解并转换JSDoc块标签 @param, @returns, throws, @example (没有可选的 <caption>) , @deprecated, @see 和他们的同义词. 其他人将 进入以太.

测试

运行 python setup.py test . 运行 tox 来测试Python版本.

版本历史

2.7.1
  • 修复Windows上UTF-8有时会发生的崩溃. #67.

  • 始终对jsdoc的工作目录使用conf.py的目录. #78. (Thomas Khyn)

2.7
  • 添加实验性TypeScript支持. (Wim Yedema)

2.6
  • 添加对 @deprecated@see 的支持. (David Li)

  • 注意并记录JS variadic params很好. (David Li)

  • 将linter添加到代码库.

2.5
  • 使用记录的 @params 来帮助填写函数的正式参数列表. 这使我们不会错过使用解构的params. (flozz)

  • 缺少jsdoc时改进错误报告.

  • 将提取的默认值添加到生成的正式参数列表中. (flozz and erikrose)

2.4
  • 支持 @example 标签. (lidavidm)

  • 在Windows下工作. 以前, 我们几乎找不到任何文件. (flozz)

  • 正确展开多行JSDoc标记, 即使它们具有Windows行结尾. (Wim Yedema)

  • 删除对Python 3.3的支持, 因为Sphinx也已经这样做了.

  • 在Sphinx> = 1.7.1下使用Recommonmark(用于Markdown支持)时修复构建时崩溃. (jamrizzi)

2.3.1
  • 在Windows上找到jsdoc命令, 它具有不同的名称. 然后修补进程通信, 使其不挂起.

2.3
  • 添加在 autoclass:members: 选项中说 “*” 的能力, 意思是 “和我没有明确列出的所有成员”.

2.2
  • @callback 标签添加 autofunction 支持. (krassowski)

  • @typedef 标签添加实验 autofunction 支持. (KRASSOWSKI)

  • 为jsdoc找不到任何JS文件时添加一条很好的错误消息.

  • 更紧密地固定六个, 以便 python_2_unicode_compatible 肯定会出现.

2.1
  • js_source_path 中允许多个文件夹. 这对于逐步将大型项目(一次一个文件夹)迁移到jsdoc非常有用. 引入 root_for_relative_js_paths 以在多个源路径面前保持相对路径的明确性.

  • 聚合PathTaken错误, 并立即报告所有错误. 这意味着您在清理大型项目时不必重复运行JSDoc.

  • 修复了在3.6之前的Python 3版本上崩溃的字节vs字符串问题. (jhkennedy)

  • 容忍文件扩展名不是 “. js” 的JS文件. 之前, 当与摄取此类文件的自定义jsdoc配置结合使用时, 会生成不正确的对象路径名, 从而导致虚假的“找不到对象…的错误的JSDoc文档”.

2.0.1
  • 通过首先将大型JSDoc输出写入临时文件来修复虚假语法错误. (jhkennedy)

2.0
  • 处理模棱两可的对象路径. 具有相同JSDoc长名称的符号(例如在不同文件中称为 “foo” 的两个顶级事物)将不再具有另一个阴影. 引入用于引用对象的明确路径约定. 添加一个真正的解析器来解析它们, 而不是我们之前使用的肮脏技巧. 向后兼容性稍微破坏, 因为模糊引用现在是一个致命的错误, 而不是悄悄地引用JSDoc碰巧遇到的最后一个定义.

  • 将所有内容索引到后缀树中, 以便您可以使用任何唯一的路径后缀来引用对象.

  • 有一个真正的解析器的其他后果:

    • 停止支持 “-” 作为名称路径分隔符.

    • 不再虚假地将名称路径中的转义分隔符转换为点.

    • 否则正确处理路径和逃逸. 例如, 我们现在可以处理包含 “(” 的符号.

  • 在尝试收集标记为 @class 的普通旧对象的构造函数params时修复KeyError.

1.5.2
  • 修复crasher, 同时警告未找到指定的长名称.

1.5.1
  • :members: 选项添加到 autoclass 中.

1.5
  • autoclass 中添加 :members: 选项.

  • 添加 :private-members::exclude-members: 选项.

  • 重要的重构允许指令类相互通信.

1.4
  • 添加 jsdoc_config_path 选项.

1.3.1
  • 容忍包含在源代码中的@args和其他信息字段行.

  • 在Sphinx发出的警告和错误中引用源注释的文件和行.

1.3
  • 添加 autoattribute 指令.

1.2
  • 始终做完全重建;当JS代码发生变化但RST没有变更时, 不要让页面过时.

  • 使Python-3兼容.

  • 添加基本​​的 autoclass 指令.

1.1
  • 添加 :short-name: 选项.

1.0
  • 初始版本, 只有 js:autofunction