- 文档
- CLI
【免费下载链接】documentation
:book: documentation for modern JavaScript
导读:
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 的生成流程被清晰地拆成两个阶段:
- 解析阶段:
documentation.build/documentation.buildSync接收入口文件(entry points),产出"已解析的 JSDoc 注释列表"(一组结构化的 comment 对象,附带推断出的类型、参数、成员关系等信息); - 输出阶段:
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) => Promiseindexes:string | Array<string>,要处理的文件列表,也接受 glob 模式。args:Object,可配置项,完整列表如下:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
external | Array<string> | — | 字符串正则 / glob 匹配模式,用于定义哪些外部模块会被白名单放行并纳入生成的文档 |
shallow | boolean | false | 是否跳过依赖解析(shallow 模式),只处理显式指定的文件 |
inferPrivate | string | — | 合法的正则表达式字符串,根据命名结构推断代码元素是否为私有。例如设置inferPrivate: '^_'会自动把_myMethod这类命名的方法视为私有 |
extension | string \| 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可配置项如下:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
external | Array<string> | — | 外部模块白名单正则 / glob 模式 |
shallow | boolean | false | 是否跳过依赖解析,只处理指定文件 |
sortOrder | Array<string \| Object> | [] | 定义文档的排序顺序,可选值见下文 |
access | Array<string> | [](实际默认['public', 'undefined', 'protected']) | 输出到文档的访问级别集合 |
hljs | Object | — | highlight.js 可选参数 |
hljs.highlightAuto | boolean | false | 是否让 highlight.js 自动检测代码语言 |
hljs.languages | Array | — | 供 highlight.js 选择的语言集合 |
inferPrivate | string | — | 推断私有成员的正则字符串 |
extension | string \| 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):
- 配置合并:
configure调用mergeConfig,将程序参数、配置文件(--config指定的 yml/json)以及最近的package.json中的name、homepage、version、description合并为project-*前缀配置(见 src/merge_config.js); - 输入展开:
expandInputs依据config.shallow或config.documentExported决定走 src/input/shallow.js(不解析依赖,支持{ source, file }对象输入,可在无文件系统的浏览器环境运行)还是 src/input/dependency.js(基于 module-deps 的依赖解析,需要文件系统); - 访问级别默认值:若未显式提供
config.access,默认设为['public', 'undefined', 'protected']; - 解析与推断管道:对每个输入文件调用
parseJavaScript(src/parsers/javascript.js),随后逐个执行inferName、inferAccess、inferAugments、inferImplements、inferKind、nest、inferParams、inferProperties、inferReturn、inferMembership、inferType等推断器,若启用了 GitHub 链接推断还会执行github,最后garbageCollect清理无效节点; - 排序与访问过滤:
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>>| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
comments | Array<Comment> | — | 解析后的注释数组(来自build) |
config.theme | string | '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
相关推荐
documentation.js 完全指南:现代 JavaScript 的 JSDoc 文档生成系统
documentation.js 完全指南:现代 JavaScript 的 JSDoc 文档生成系统 导读 documentation.js (仓库内以 doc
文档CLIWSABuilds调试技巧:ADB连接与Android应用日志分析实战
WSABuilds调试技巧:ADB连接与Android应用日志分析实战 WSABuilds是一款能让你在Windows 10和Windows 11电脑上运行An
开发工具documentation.js 终极指南:现代 JavaScript 文档生成的完整解决方案
documentation.js 终极指南:现代 JavaScript 文档生成的完整解决方案 documentation.js 是一个专为现代 JavaScr
文档CLI
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考