☰
documentation.js Node API 完全指南:用 lint、build 与 formats 在 JavaScript 代码中生成文档
2026/10/12 3:45:03 网站建设 项目流程
  • 文档
  • CLI

【免费下载链接】documentation

:book: documentation for modern JavaScript

项目地址:https://gitcode.com/gh_mirrors/do/documentation
点击查看免费下载

导读:documentation.js不仅提供documentation命令行工具,还暴露了一套完整的 Node API,让开发者可以在自己的脚本、构建工具(如 gulp/grunt 插件)或自定义集成中直接完成"解析 JSDoc → 校验文档 → 生成 Markdown/JSON/HTML"的完整流水线。阅读本文后,你将掌握lint、build、formats三大 API 的签名、参数语义与返回值,并能基于源码理解其底层执行链路,写出可复用的文档生成与校验脚本。

docs/NODE_API.md是 documentation.js 通过"自我文档化"(self-hosted)生成的 Node API 参考:仓库的doc脚本执行node ./bin/documentation.js build src/index.js -f md --access=public > docs/NODE_API.md(见 package.json),即用自己解析自己的入口模块。因此本文所有 API 签名、参数与示例均与 src/index.js 中的真实实现一一对应,可直接作为开发参考。

一、总体设计:两阶段管道模型

从 Node API 的角度看,documentation.js 的生成流程被清晰地拆成两个阶段:

  1. 解析阶段:documentation.build/documentation.buildSync接收入口文件(entry points),产出"已解析的 JSDoc 注释列表"(一组结构化的 comment 对象,附带推断出的类型、参数、成员关系等信息);
  2. 输出阶段:documentation.formats.md、documentation.formats.json、documentation.formats.html等格式方法接收这批 comments,产出字符串(Markdown / JSON)或 Vinyl 风格对象(HTML)等最终结果。

此外documentation.lint是一个独立的校验入口,用于检查文档中非标准或错误的信息。这一"解析 + 输出"的管道模型在 src/index.js 中体现得非常清晰:build走buildInternal,lint走lintInternal,两者共用configure(配置合并)与expandInputs(输入展开)的前置流程,但后续的 comment 处理管道(pipeline)不同。

Node API 的典型适用场景(与 docs/USAGE_NODE.md 描述一致):

  • 构建集成,例如基于 documentation.js 定制 gulp 或 grunt 插件;
  • 复用其 AST 解析或其他组件(如expandInputs、util.createFormatters、util.LinkerStack);
  • 编写自定义的文档生成、校验或统计分析工具("mad science")。

二、lint:校验文档的非标准与错误信息

2.1 签名与参数

documentation.lint(indexes, args) => Promise
  • indexes:string | Array<string>,要处理的文件列表,也接受 glob 模式。
  • args:Object,可配置项,完整列表如下:
参数类型默认值说明
externalArray<string>—字符串正则 / glob 匹配模式,用于定义哪些外部模块会被白名单放行并纳入生成的文档
shallowbooleanfalse是否跳过依赖解析(shallow 模式),只处理显式指定的文件
inferPrivatestring—合法的正则表达式字符串,根据命名结构推断代码元素是否为私有。例如设置inferPrivate: '^_'会自动把_myMethod这类命名的方法视为私有
extensionstring \| Array<string>—将额外文件扩展名当作 JavaScript 解析,扩展默认集合js、es6、jsx

2.2 返回值与用法示例

lint返回一个 Promise,resolve 为一个"可能为空"的 lint 信息字符串,设计用于人类可读输出。官方示例:

documentation.lint('file.js').then(lintOutput => { if (lintOutput) { console.log(lintOutput); process.exit(1); } else { process.exit(0); } });

即:若有 lint 输出则打印并返回非零退出码,否则以 0 退出,非常适合接入 CI 校验。

2.3 底层实现:lint 管道到底检查什么

从源码看,lintInternal执行的管道为lintComments → inferName → inferAccess → inferAugments → inferKind → inferParams → inferProperties → inferReturn → inferMembership → inferType → nest(见 src/index.js),核心规则位于 src/lint.js:

  • 类型命名规范化检查:CANONICAL映射表定义了一批"非标准"的类型写法,例如String应写成string、Boolean应写成boolean、Undefined应写成undefined、array应写成Array、date应写成Date、object应写成Object。命中时会产出type X found, Y is standard类警告;
  • 类型结构的递归检查:checkCanonical会递归进入elements与applications,覆盖泛型、联合类型等嵌套场景;
  • 参数名推断比对:显式声明的@param foo若与从代码推断出的参数列表不匹配,会产生警告(对应测试夹具tests/fixture/lint/lint.output 中大量An explicit parameter named foo was specified but didn't match inferred information a, b的输出)。

formatLint将错误信息汇总到vfile并通过vfile-reporter渲染为带行号的终端报告。测试用例tests/index.js 验证了对合法注释调用lint返回空字符串;tests/bin.js 则验证了命令行documentation lint在坏文件上会输出警告、在好文件上无输出、在语法错误文件上以非零码退出等行为。

三、build:生成结构化的文档数据

3.1 签名与参数

documentation.build(indexes, args) => Promise<Array<Object>>

indexes与lint相同(string | Array<string>,也支持对象形式{ source, file },见 src/input/shallow.js)。args可配置项如下:

参数类型默认值说明
externalArray<string>—外部模块白名单正则 / glob 模式
shallowbooleanfalse是否跳过依赖解析,只处理指定文件
sortOrderArray<string \| Object>[]定义文档的排序顺序,可选值见下文
accessArray<string>[](实际默认['public', 'undefined', 'protected'])输出到文档的访问级别集合
hljsObject—highlight.js 可选参数
hljs.highlightAutobooleanfalse是否让 highlight.js 自动检测代码语言
hljs.languagesArray—供 highlight.js 选择的语言集合
inferPrivatestring—推断私有成员的正则字符串
extensionstring \| Array<string>—额外按 JavaScript 解析的扩展名

3.2 返回值与用法示例

返回 Promise,resolve 为"带推断属性的已解析注释数组",即文档生成或任何其他代码数据分析所需的一切。官方示例:

var documentation = require('documentation'); documentation.build(['index.js'], { // only output comments with an explicit @public tag access: ['public'], sortOrder: ['kind', 'alpha'] }).then(res => { // res is an array of parsed comments with inferred properties // and more: everything you need to build documentation or // any other kind of code data. });

3.3 底层实现:build 的执行链路

build的完整链路(见 src/index.js):

  1. 配置合并:configure调用mergeConfig,将程序参数、配置文件(--config指定的 yml/json)以及最近的package.json中的name、homepage、version、description合并为project-*前缀配置(见 src/merge_config.js);
  2. 输入展开:expandInputs依据config.shallow或config.documentExported决定走 src/input/shallow.js(不解析依赖,支持{ source, file }对象输入,可在无文件系统的浏览器环境运行)还是 src/input/dependency.js(基于 module-deps 的依赖解析,需要文件系统);
  3. 访问级别默认值:若未显式提供config.access,默认设为['public', 'undefined', 'protected'];
  4. 解析与推断管道:对每个输入文件调用parseJavaScript(src/parsers/javascript.js),随后逐个执行inferName、inferAccess、inferAugments、inferImplements、inferKind、nest、inferParams、inferProperties、inferReturn、inferMembership、inferType等推断器,若启用了 GitHub 链接推断还会执行github,最后garbageCollect清理无效节点;
  5. 排序与访问过滤:sort(extractedComments, config)排序后经hierarchy构建嵌套结构,再由filterAccess(src/filter_access.js)按访问级别过滤——@private注释会被剔除,除非访问级别列表显式包含private。

关于buildSync:docs/USAGE_NODE.md 中提到了documentation.buildSync,它接收{ source, file }对象数组作为入口(例如source: '/** hi this is a doc\n@name myDoc */', file: 'direct.js'),是同步变体,适合不依赖文件系统的内存输入场景。

从源码结构看,返回的 comment 对象包含:description(remark 风格的 Markdown AST,type: 'root'加children)、tags、loc(源码位置)、augments、examples、implements、params、properties、returns、sees、throws、todos、yields、name、members(按events/global/inner/instance/static分组的嵌套成员)、path、namespace等字段。这些字段的初始结构在 src/parse.js 中定义,完整结构可参考快照tests/snapshots/index.js.snap。

JSDoc 标签规范化的关键实现位于 src/parse.js:文档中对@param、@returns、@property、@throws、@example、@augments等标签会扁平化为params、returns、properties等数组字段;同时支持大量同义词映射,例如@virtual⇢@abstract、@extends⇢@augments、@constructor⇢@class、@const⇢@constant、@defaultvalue⇢@default、@desc⇢@description、@arg/@argument⇢@param、@prop⇢@property、@return⇢@returns、@exception⇢@throws、@emits⇢@fires、@func/@method⇢@function、@var⇢@member等;@access/@public/@protected/@private则被扁平化为access属性(默认视为public)。

3.4 排序:sortOrder 的取值语义

sortOrder的可选值与 CLI 中的--sort-order一致(见 src/sort.js):

  • source:按源码位置(context.sortKey)排序,默认值;
  • alpha:按名称(name)字母序;
  • kind:按注释种类(kind)排序;
  • access:按访问级别排序;
  • memberof:按所属模块(memberof)排序。

另外 src/sort.js 支持基于toc配置的显式排序:documentation.yml中toc条目可以是名称字符串(按索引排到固定位置)或带name/description/file/children的对象(kind会被设为note,可作为叙述性章节插入文档)。

四、formats:模块化的输出格式

formats是 documentation.js 的格式命名空间(见 src/index.js),包含html、md、remark、json四个方法。它们都是"接收 comments 与 config、返回 Promise"的模块化方法,输入为解析后的注释数组,输出为字符串化的 JSON、Markdown 字符串或 HTML 的 Vinyl 对象等。

4.1 formats.html:生成 HTML

formats.html(comments, config) => Promise<Array<Object>>
参数类型默认值说明
commentsArray<Comment>—解析后的注释数组(来自build)
config.themestring'default_theme'用作 HTML 主题的模块名称

官方示例:

var documentation = require('documentation'); documentation.build(['index.js']) .then(documentation.formats.html);

实现细节(src/output/html.js):html会再次调用mergeConfig合并配置;若指定了config.theme,则通过动态import()加载该主题模块并调用其默认导出(主题模块签名为(comments, config) => Promise<Array<Object>>),否则加载内置主题 src/default_theme/index.js。返回的是一组 Vinyl 对象(含index.html等文件),通常配合-o输出目录使用。在 Windows 平台上,绝对主题路径会被加上file:///前缀以避免ERR_UNSUPPORTED_ESM_URL_SCHEME错误。主题定制可参考 docs/THEMING.md。

4.2 formats.markdown:生成 Markdown

formats.markdown(comments, args) => Promise<string>

comments为解析后的注释数组,args为可定制输出的选项对象。

官方示例:

var documentation = require('documentation'); var fs = require('fs'); documentation.build(['index.js']) .then(documentation.formats.md) .then(output => { // output is a string of Markdown data fs.writeFileSync('./output.md', output); });

实现细节(src/output/markdown.js):markdown内部先把 comments 交给markdownAST(src/output/markdown_ast.js)生成 remark 兼容的 AST——包括开头的<!-- Generated by documentation.js. ... -->注释、可选的 "Table of Contents" 标题(config.markdownToc,默认开启;markdownTocMaxDepth默认 6)、GitHub 源码链接、类型 / 参数 / 属性 / 示例 / Throws / Returns / Meta 等章节;随后用remark().use(remarkGfm).stringify(ast)渲染为最终字符串。remark-gfm的引入意味着 Markdown 输出支持 GFM 扩展(如表格),这由tests/bin.js 中 "build GFM (e.g. markdown tables)" 的测试验证。

markdownAST还负责代码高亮配置(config.hljs透传给highlight.js,highlightAuto开启时自动检测示例代码语言)、链接重路由(rerouteLinks+LinkerStack,可将{@link}等引用链接到目标注释的锚点)。

4.3 formats.json:生成 JSON

formats.json(comments) => Promise<string>

comments为解析后的注释数组,返回 Promise,resolve 为 JSON 字符串。

官方示例:

var documentation = require('documentation'); var fs = require('fs'); documentation.build(['index.js']) .then(documentation.formats.json) .then(output => { // output is a string of JSON data fs.writeFileSync('./output.json', output); });

实现细节(src/output/json.js):json在序列化前会遍历注释树,删除errors字段以及context.sortKey(这些属于过程性数据,不适合出现在输出中),然后用JSON.stringify(comments, null, 2)生成带缩进的字符串。快照tests/snapshots/index.js.snap 展示了build结果经formats.json序列化后的完整 JSON 结构示例。

4.4 formats.remark:输出中间 AST

除了文档 docs/NODE_API.md 中列出的三个格式外,源码 src/index.js 还暴露了formats.remark:它返回markdownAST生成的 AST 并JSON.stringify(res, null, 2),适合需要拿到结构化文档树做二次加工(如自定义渲染器、统计分析)的场景。

五、从参数到行为:几个值得注意的语义

  • external白名单:声明为Array<string>,用"字符串正则 / glob 匹配模式"定义哪些外部模块会被白名单放行并纳入文档。默认情况下外部模块会被过滤(module_filters.js的internalOnly),只有匹配白名单的才会进入生成结果;
  • shallow与依赖解析:shallow: true会完全绕过依赖解析(甚至对 JavaScript 代码本身也不解析依赖),只处理显式传入的文件。测试用例tests/index.js 验证了expandInputs在深浅两种模式下都能正确展开输入;
  • inferPrivate的命名推断:传入合法正则(如'^_')后,命名匹配该正则的成员会被推断为私有并在后续访问过滤中被剔除;
  • extension扩展解析范围:默认解析扩展名集合为['.mjs', '.js', '.jsx', '.es5', '.es6', '.vue', '.ts', '.tsx'](见 src/config.js),extension参数在此之上追加新的扩展名。测试tests/bin.js 验证了通过--requireExtension=otherextension --parseExtension=otherextension解析自定义扩展名的行为;
  • access过滤语义:src/filter_access.js 表明kind === 'note'的叙述性节点始终保留,其余节点仅当!comment.ignore且访问级别在列表中时保留。CLI 帮助(docs/USAGE.md)中--access的可选值为public、private、protected、undefined;
  • hljs代码高亮:hljs.highlightAuto开启后,markdownAST会用highlight.js自动检测示例代码的语言,避免所有示例都被标记为javascript;hljs.languages限制可检测的语言集合。

六、实战:用 Node API 构建一个文档生成脚本

结合以上 API,一个完整的"解析 → 输出"脚本可以这样组织:

var documentation = require('documentation'); var fs = require('fs'); // 1. 解析入口文件,生成结构化注释数据 documentation.build(['index.js'], { access: ['public', 'protected', 'undefined'], sortOrder: ['kind', 'source'], shallow: false }) .then(function (comments) { // 2. 同时输出 Markdown 与 JSON return Promise.all([ documentation.formats.md(comments), documentation.formats.json(comments) ]); }) .then(function (results) { fs.writeFileSync('./docs/API.md', results[0]); fs.writeFileSync('./docs/API.json', results[1]); console.log('documentation generated'); }) .catch(function (err) { console.error(err); process.exit(1); }); // 3. 独立做文档校验(可用于 CI) documentation.lint('index.js').then(function (output) { if (output) { console.error(output); process.exit(1); } });

若要完全脱离文件系统(例如在浏览器或纯内存场景运行),可以像 docs/USAGE_NODE.md 的示例那样直接传入源码字符串:

var documentation = require('documentation'); var docs = documentation.buildSync([{ source: '/** hi this is a doc\n@name myDoc */', file: 'direct.js' }]); documentation.formats.md(docs, {}, function(err, res) { console.log(res); });

这里buildSync直接接收{ source, file }对象作为入口,source是待解析的 JSDoc 源码字符串,file是逻辑文件名(用于错误定位与链接推断)。

七、与 CLI 的对应关系

Node API 的参数与 CLI 选项一一对应(完整 CLI 帮助见 docs/USAGE.md):

Node API 参数CLI 选项说明
access--access, -a访问级别过滤,CLI 默认包含public、protected、undefined
shallow--shallow关闭依赖解析
external--external外部模块白名单
inferPrivate--infer-private命名推断私有的正则
extension--require-extension, --re/--parse-extension, --pe额外解析 / require 的扩展名
sortOrder--sort-order排序方式(source/alpha/kind/memberof)
hljs配置文件中的hljs键代码高亮配置(如highlightAuto)

二者的核心区别在于:CLI 是一次性面向终端用户的黑盒命令,而 Node API 把"解析"与"输出"拆成可组合的 Promise 链,便于嵌入构建系统、接入 CI 或做深度定制。

八、延伸阅读

  • docs/USAGE_NODE.md:Node 库使用的快速上手与buildSync内存输入示例;
  • docs/CONFIG.md:documentation.yml配置(toc排序、叙述性章节、file引用、children分组)的完整说明;
  • src/index.js:lint、build、formats的最终实现与导出;
  • src/parse.js:JSDoc 标签解析、同义词归一化与扁平化规则;
  • src/lint.js:lint 规则(类型命名规范化、参数推断比对);
  • src/output/markdown_ast.js:Markdown AST 的章节组装逻辑;
  • tests/index.js 与tests/bin.js:Node API 与 CLI 的测试用例,可作为行为契约参考。
  • 文档
  • CLI

【免费下载链接】documentation

:book: documentation for modern JavaScript

项目地址:https://gitcode.com/gh_mirrors/do/documentation
点击查看免费下载
上一篇:Beads 与 Factory.ai Droid 集成指南:通过 `bd setup factory` 托管 AGENTS.md 指引
下一篇:CookLikeHOC 肥肠鸡完整复刻指南:从鸡块预处理到糊辣油淋面的出品全流程

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询