到目前为止,还没有很好的工具来文档化大型 JavaScript 项目。 JSDoc 长期以来一直是唯一的竞争者,它具有一些不错的属性
- 一组定义明确的标签,用于描述常见结构
- 诸如 Closure Compiler 之类的工具,它与这些标签挂钩
但输出始终是项目中所有内容的字母顺序列表。JSDoc 混淆并展平了您的函数,让新用户推断它们之间的关系,并在脑海中将它们分类成可理解的组。虽然您可以在小型库中使用这种方法,但它在大型库中会失败得很惨,比如 Fathom,它有复杂的全新概念需要解释。对于 Fathom 的手册,我想要的是能够以逻辑方式组织它,用提取的文档穿插解释性文字,并添加完整的章节,这些章节纯粹是概念概述,但又与其他工作相关联。1
Python 世界长期以来一直青睐 Sphinx,这是一种成熟的文档工具,支持多种语言和输出格式,以及一流的索引、词汇表生成、搜索和交叉引用。人们用它写了整本书。通过插件,它支持从 Graphviz 图表到 YouTube 视频的所有内容。但是,它的 JavaScript 支持始终缺乏从代码中提取文档的能力。
现在 sphinx-js 添加了这种能力,让 JavaScript 开发者获得两全其美。
sphinx-js 使用标准的 JSDoc 注释和标签——您无需对源代码进行任何奇怪的操作。(事实上,它将解析和提取委托给 JSDoc 本身,让它能够顺利地应对未来的更改。)您只需要让 Sphinx 在项目根目录中初始化一个 docs
文件夹,将 sphinx-js 作为插件激活,然后就可以使用简单的 reStructuredText 写文档,直到您想调用一些提取的文档,您就使用 sphinx-js 的一个特殊指令,该指令模仿以 Python 为中心的 autodoc 的成熟示例。最简单的示例如下
.. autofunction:: linkDensity
这将找到这个函数……
/**
* 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 - The node whose density to measure
* @throws {EldritchHorrorError|BoredomError} If the expected laws of the
* universe change, raise EldritchHorrorError. If we're getting bored of
* said laws, raise BoredomError.
* @returns {Number} A ratio of link length to overall text length: 0..1
*/
function linkDensity(node) {
...
}
…并吐出一个格式良好的块,如下所示
当您想做一些事情,比如添加一系列长示例时,Sphinx 的灵活性就显现出来了。与其在 linkDensity
周围的源代码中杂乱无章,不如将这些额外的材料放到组成手册的 reStructuredText 文件中
.. autofunction:: linkDensity
Anything you type here will be appended to the function's description right
after its return value. It's a great place for lengthy examples!
还有一种 sphinx-js 指令用于类,无论是 ECMAScript 2015 的糖衣品种还是经典的函数作为构造函数的类型,装饰着 @class
。它可以可选地遍历类成员,在遍历过程中进行文档化。您可以控制排序,打开或关闭私有成员,甚至可以通过名称包含或排除特定成员——所有这些都是 Sphinx 对 Python 代码支持的经过深思熟虑的极端情况。以下是一个现实世界的示例,它展示了几个真正的公共方法,同时隐藏了一些框架专用的“朋友”方法
.. autoclass:: Ruleset(rule[, rule, ...])
:members: against, rules
除了完善的 Python 约定之外,sphinx-js 还支持对同名 JS 实体的引用,这些实体在其他情况下会发生冲突:例如,一个 foo
是一个对象的静态方法,另一个 foo
是同一个对象的实例方法。它使用 JSDoc 的 namepaths 的变体来实现这一点。例如……
someObject#foo
是实例方法。someObject.foo
是静态方法。- 而
someObject~foo
是一个内部成员,这是第三种可能的重叠类型。
因为 JSDoc 仍然在幕后进行分析,所以我们可以利用它对这些 JS 细微差别的理解。
当然,JS 是一种深度嵌套的语言,所以事情可能很快就会变得非常复杂。谁愿意键入完整的路径来文档化 innerMember
?
some/file.SomeClass#someInstanceMethod.staticMethod~innerMember
太糟糕了!幸运的是,sphinx-js 使用后缀树索引所有这样的对象路径,所以您可以使用任何唯一地引用对象的的后缀。您可能只需要说 innerMember
。或者,如果您的代码库中有两个名为“innerMember”的对象,您可以通过说 staticMethod~innerMember
等来消除歧义,一直向左移动,直到您有一个唯一的命中。这提供了简洁性,并且作为奖励,它让您无需在代码库中移动时修改文档。
凭借 Sphinx 的成熟性和强大功能,以及 JSDoc 无处不在的语法约定和经过验证的分析机制的支持,sphinx-js 是文档化任何大型 JS 项目的绝佳方式。要开始使用,请参阅 自述文件。或者,对于大型示例,请参阅 Fathom 文档。一个特别有用的页面是 规则和规则集参考,它将教程段落与提取的类和函数文档穿插在一起;它的 源代码 可在右上角链接后找到,所有此类页面均如此。
我期待您的成功案例和 错误报告——以及丰富、易于组织的 JS 文档的即将到来的增长!
1JSDoc 有 教程,但它们只是单个 HTML 页面。它们没有特别的能力与其他文档交叉链接,也没有能力调用提取的注释。
关于 Erik Rose
Erik 通过 DXR(Mozilla 代码库的搜索和静态分析)、Fathom(从网页中提取语义)、解析器、新语言和一大堆 Python 库等项目,打破了人类认知和机器执行之间的障碍。
15 条评论