JSDoc 插件扩展 #
插件系统概述 #
JSDoc 提供了强大的插件系统,允许开发者扩展和定制文档生成功能。
text
┌─────────────────────────────────────────────────────────────┐
│ JSDoc 插件系统 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 内置插件 │ │ 第三方插件 │ │ 自定义插件 │ │
│ │ │ │ │ │ │ │
│ │ • markdown │ │ • docdash │ │ • 标签插件 │ │
│ │ • summare │ │ • better- │ │ • 处理插件 │ │
│ │ • sourcetag │ │ docs │ │ • 模板插件 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
内置插件 #
plugins/markdown #
支持 Markdown 格式:
javascript
// jsdoc.json
{
"plugins": ["plugins/markdown"]
}
配置选项:
javascript
{
"plugins": ["plugins/markdown"],
"markdown": {
"hardwrap": true, // 硬换行
"idInHeadings": true // 标题添加 ID
}
}
使用示例:
javascript
/**
* 用户服务
*
* 提供用户相关的操作:
* - 创建用户
* - 更新用户
* - 删除用户
*
* @module UserService
*/
/**
* 创建用户
*
* **注意**:用户名必须唯一
*
* @param {Object} data - 用户数据
* @returns {Promise<User>}
*
* @example
* ```javascript
* const user = await createUser({
* name: 'John',
* email: 'john@example.com'
* });
* ```
*/
async function createUser(data) {}
plugins/summare #
自动生成描述摘要:
javascript
// jsdoc.json
{
"plugins": ["plugins/summare"]
}
效果:
javascript
/**
* 计算两个数字的和。该函数接受两个数字参数,返回它们的和。
* @param {number} a - 第一个数字
* @param {number} b - 第二个数字
* @returns {number} 两数之和
*/
// 自动提取第一句作为摘要
// 摘要: 计算两个数字的和。
plugins/sourcetag #
支持 @source 标签:
javascript
// jsdoc.json
{
"plugins": ["plugins/sourcetag"]
}
使用示例:
javascript
/**
* @source https://github.com/user/repo/blob/main/src/utils.js#L10-L20
*/
function utility() {}
plugins/testdoc #
支持测试文档:
javascript
// jsdoc.json
{
"plugins": ["plugins/testdoc"]
}
plugins/overloadHelper #
支持函数重载:
javascript
// jsdoc.json
{
"plugins": ["plugins/overloadHelper"]
}
使用示例:
javascript
/**
* @overload
* @param {string} input
* @returns {string}
*/
/**
* @overload
* @param {number} input
* @returns {number}
*/
/**
* 处理输入
* @param {string|number} input
* @returns {string|number}
*/
function process(input) {
return input;
}
第三方插件 #
docdash 模板 #
流行的文档模板:
bash
npm install docdash --save-dev
javascript
// jsdoc.json
{
"opts": {
"template": "node_modules/docdash"
},
"docdash": {
"static": true,
"sort": true,
"search": true,
"collapse": true,
"wrap": true,
"typedefs": true,
"navLevel": 2,
"private": false,
"removeQuotes": "none",
"scripts": [],
"menu": {
"GitHub": {
"href": "https://github.com/user/repo",
"target": "_blank"
}
}
}
}
better-docs 模板 #
功能丰富的文档模板:
bash
npm install better-docs --save-dev
javascript
// jsdoc.json
{
"opts": {
"template": "node_modules/better-docs"
},
"plugins": [
"node_modules/better-docs/category"
],
"better-docs": {
"name": "My Project",
"logo": "./logo.png",
"navigation": [
{
"label": "GitHub",
"href": "https://github.com/user/repo"
}
]
}
}
使用分类标签:
javascript
/**
* @category User
*/
function getUser() {}
/**
* @category User
*/
function createUser() {}
/**
* @category Auth
*/
function login() {}
jsdoc-plugin-typescript #
TypeScript 支持:
bash
npm install jsdoc-plugin-typescript --save-dev
javascript
// jsdoc.json
{
"plugins": [
"node_modules/jsdoc-plugin-typescript"
],
"source": {
"includePattern": ".+\\.ts$"
}
}
tui-jsdoc-template #
美观的文档模板:
bash
npm install tui-jsdoc-template --save-dev
javascript
// jsdoc.json
{
"opts": {
"template": "node_modules/tui-jsdoc-template"
},
"templates": {
"logo": {
"url": "./logo.png",
"width": "150px"
},
"name": "My API",
"footerText": "© 2024 My Company"
}
}
自定义插件开发 #
插件结构 #
javascript
// my-plugin.js
/**
* JSDoc 插件模块
* @module my-plugin
*/
// 1. 定义事件处理器
exports.eventHandlers = {
// 处理解析完成事件
parseComplete: function(e) {
console.log('Parsing complete!');
}
};
// 2. 定义标签
exports.defineTags = function(dictionary) {
dictionary.defineTag('category', {
mustHaveValue: true,
onTagged: function(doclet, tag) {
doclet.category = tag.value;
}
});
};
// 3. 定义节点访问器
exports.astNodeVisitor = {
visitNode: function(node, e, parser, currentSourceName) {
// 处理 AST 节点
}
};
// 4. 定义文档处理器
exports.handlers = {
newDoclet: function(e) {
// 处理新的 doclet
}
};
定义自定义标签 #
javascript
// plugins/customTags.js
exports.defineTags = function(dictionary) {
// @category 标签
dictionary.defineTag('category', {
mustHaveValue: true,
onTagged: function(doclet, tag) {
doclet.category = tag.value;
}
});
// @security 标签
dictionary.defineTag('security', {
mustHaveValue: true,
onTagged: function(doclet, tag) {
if (!doclet.security) {
doclet.security = [];
}
doclet.security.push(tag.value);
}
});
// @author 标签扩展
dictionary.defineTag('author', {
mustHaveValue: true,
onTagged: function(doclet, tag) {
if (!doclet.authors) {
doclet.authors = [];
}
doclet.authors.push({
name: tag.value.split('<')[0].trim(),
email: tag.value.match(/<(.+)>/)?.[1]
});
}
});
// @version 标签
dictionary.defineTag('version', {
mustHaveValue: true,
onTagged: function(doclet, tag) {
doclet.version = tag.value;
}
});
};
使用自定义标签:
javascript
/**
* 获取用户信息
* @category User
* @security authenticated
* @author John Doe <john@example.com>
* @version 1.0.0
* @param {number} id - 用户 ID
* @returns {Promise<User>}
*/
async function getUser(id) {}
处理 Doclet #
javascript
// plugins/docletProcessor.js
exports.handlers = {
// 处理新创建的 doclet
newDoclet: function(e) {
const doclet = e.doclet;
// 添加创建时间
if (!doclet.createdAt) {
doclet.createdAt = new Date().toISOString();
}
// 自动添加示例
if (doclet.kind === 'function' && !doclet.examples) {
doclet.examples = [`// TODO: Add example for ${doclet.name}`];
}
// 处理描述
if (doclet.description) {
doclet.description = doclet.description.trim();
}
},
// 处理解析完成
parseComplete: function(e) {
console.log(`Parsed ${e.doclets.length} doclets`);
},
// 处理文件开始
fileBegin: function(e) {
console.log(`Processing: ${e.filename}`);
},
// 处理文件结束
fileComplete: function(e) {
console.log(`Completed: ${e.filename}`);
}
};
AST 节点访问 #
javascript
// plugins/astVisitor.js
exports.astNodeVisitor = {
visitNode: function(node, e, parser, currentSourceName) {
// 处理函数声明
if (node.type === 'FunctionDeclaration') {
// 自动推断参数类型
node.params.forEach(param => {
if (param.type === 'Identifier') {
console.log(`Found parameter: ${param.name}`);
}
});
}
// 处理类声明
if (node.type === 'ClassDeclaration') {
console.log(`Found class: ${node.id?.name}`);
}
// 处理变量声明
if (node.type === 'VariableDeclaration') {
node.declarations.forEach(decl => {
if (decl.id.type === 'Identifier') {
console.log(`Found variable: ${decl.id.name}`);
}
});
}
}
};
完整插件示例 #
javascript
// plugins/apiDocs.js
/**
* API 文档增强插件
* @module apiDocs
*/
const path = require('path');
exports.defineTags = function(dictionary) {
dictionary.defineTag('endpoint', {
mustHaveValue: true,
onTagged: function(doclet, tag) {
doclet.endpoint = tag.value;
doclet.kind = 'api';
}
});
dictionary.defineTag('method', {
mustHaveValue: true,
onTagged: function(doclet, tag) {
doclet.httpMethod = tag.value.toUpperCase();
}
});
dictionary.defineTag('middleware', {
mustHaveValue: false,
onTagged: function(doclet, tag) {
doclet.middleware = tag.value || true;
}
});
dictionary.defineTag('auth', {
mustHaveValue: true,
onTagged: function(doclet, tag) {
doclet.auth = tag.value;
}
});
};
exports.handlers = {
newDoclet: function(e) {
const doclet = e.doclet;
// 为 API 端点添加默认值
if (doclet.endpoint) {
if (!doclet.httpMethod) {
doclet.httpMethod = 'GET';
}
// 生成完整 URL
if (doclet.meta?.path) {
const basePath = process.env.API_BASE_PATH || '/api';
doclet.fullPath = path.join(basePath, doclet.endpoint);
}
}
// 添加安全标记
if (doclet.auth) {
doclet.security = {
type: doclet.auth,
required: true
};
}
},
parseComplete: function(e) {
// 按 endpoint 分组
const endpoints = {};
e.doclets.forEach(doclet => {
if (doclet.endpoint) {
if (!endpoints[doclet.endpoint]) {
endpoints[doclet.endpoint] = [];
}
endpoints[doclet.endpoint].push(doclet);
}
});
console.log(`Generated docs for ${Object.keys(endpoints).length} endpoints`);
}
};
使用 API 插件:
javascript
/**
* 获取用户列表
* @endpoint /users
* @method GET
* @auth jwt
* @param {number} [page=1] - 页码
* @param {number} [limit=10] - 每页数量
* @returns {Promise<{ list: User[], total: number }>}
*/
router.get('/users', authMiddleware, getUsers);
/**
* 创建用户
* @endpoint /users
* @method POST
* @auth jwt
* @middleware validateUser
* @param {Object} user - 用户数据
* @returns {Promise<User>}
*/
router.post('/users', authMiddleware, validateUser, createUser);
插件配置 #
注册插件 #
javascript
// jsdoc.json
{
"plugins": [
"./plugins/customTags.js",
"./plugins/apiDocs.js"
]
}
插件选项 #
javascript
// jsdoc.json
{
"plugins": [
"./plugins/customTags.js"
],
"customTags": {
"categories": ["User", "Auth", "API"],
"securityLevels": ["public", "authenticated", "admin"]
}
}
在插件中读取配置:
javascript
// plugins/customTags.js
exports.handlers = {
parseBegin: function(e) {
const options = e.options.customTags || {};
console.log('Categories:', options.categories);
}
};
插件发布 #
包结构 #
text
jsdoc-plugin-myplugin/
├── package.json
├── index.js
├── README.md
└── LICENSE
package.json #
javascript
{
"name": "jsdoc-plugin-myplugin",
"version": "1.0.0",
"description": "A JSDoc plugin for ...",
"main": "index.js",
"keywords": [
"jsdoc",
"plugin"
],
"peerDependencies": {
"jsdoc": ">=3.6.0"
},
"license": "MIT"
}
index.js #
javascript
/**
* @module jsdoc-plugin-myplugin
*/
exports.defineTags = function(dictionary) {
// ...
};
exports.handlers = {
// ...
};
插件调试 #
启用调试模式 #
javascript
// jsdoc.json
{
"opts": {
"debug": true,
"verbose": true
}
}
日志输出 #
javascript
// plugins/debug.js
const util = require('util');
exports.handlers = {
newDoclet: function(e) {
console.log('Doclet:', util.inspect(e.doclet, { depth: 2 }));
}
};
错误处理 #
javascript
exports.handlers = {
newDoclet: function(e) {
try {
// 处理逻辑
} catch (error) {
console.error(`Error processing ${e.doclet.name}:`, error.message);
}
}
};
常用插件列表 #
| 插件 | 用途 | 安装 |
|---|---|---|
| docdash | 文档模板 | npm i docdash |
| better-docs | 增强模板 | npm i better-docs |
| tui-jsdoc-template | 美观模板 | npm i tui-jsdoc-template |
| jsdoc-plugin-typescript | TypeScript 支持 | npm i jsdoc-plugin-typescript |
| jsdoc-vuejs | Vue.js 支持 | npm i jsdoc-vuejs |
| jsdoc-react | React 支持 | npm i jsdoc-react |
| jsdoc-to-markdown | Markdown 输出 | npm i jsdoc-to-markdown |
下一步 #
现在你已经掌握了 JSDoc 插件扩展,接下来学习 最佳实践 了解如何编写高质量的文档!
最后更新:2026-03-29