3

对于一个成熟的项目而言,一定需要一个注释文档生成工具,我们有很多可选的开源项目,如jsdocyuidocjs 等等,拥有这些强大的工具我们完全可以胜任任何注释方面的管理了么?

一个成熟的开发者都会知道不管怎么样的项目都会在不同的开发条件下有一些特定条件的需求,所以我今天要讲的就是如何自制自己的注释文档生成工具。

以 jsdoc-zero(https://github.com/kahn1990/jsdoc-zero)为例,基于流行的 jsdoc 规范。

组件的选择

命令行工具

首先我们需要一个命令行工具来方便的执行命令,这里我们选择 colors 组件,如果不喜欢使用 commander 且有能力的人完全可以通过 child_process 组件自己封装执行命令函数。

打印组件

如果一直用 console 是不是颜色太单调了呢,没关系,我们有 colors 或者 chalk 组件可以选择,它会扩展我们的 console 命令,用来在命令行中显示其他颜色。

图片描述

图片描述

文件相关工具

既然是生成文档,不可避免的会生成文件夹,所以有 mkdirp 可以方便快速的帮助我们生成文件夹。

解析工具

既然是基于 jsdoc 规范,那么一个用来识别文件注释的工具就不可少了,这里我们选择 tj 大神的 dox,另外几乎所有这类工具都默认支持 markdown 文件,所以我们还需要 marked 来支持 markdown。

html 模板

动态生成 html 文件我们需要一个好的模板引擎,大家怎么选择呢?jade 还是 ejs?

这里我很悲催的跳了 swig 的坑,可能一些同学没有听说过这个模板引擎,但它确实很优秀。

underscore

最后的最后,我们需要一个处理数据的工具函数,我选择 underscore,一是我对他比较熟悉,也写过一些源码解析的文章,二是我对比了下 lodash,lodash 与 underscore 的一些细节思想确实不同,但从工具使用的角度来讲,我们所使用的一些方法有大部分重叠。

工具的结构

我们在开始之前一定要先确定项目的大体结构,这是每个项目的必备过程。

图片描述

这里我们这样设定,bin 用于放命令相关方法,lib 放主要方法,其他的看字面意思就知道做什么的了,不敖述了。

具体方法

先从命令开始

我们先从如何写命令开始,首先我们先引入需要的组件

var command       = require('commander'),
    path          = require('path'),
    colors        = require("colors"),
    _             = require('underscore'),
    underscoreStr = require('underscore.string'),
    chalk         = require('chalk'),
    mkdirp        = require('mkdirp'),
    fs            = require('fs'),
    merge         = require('../lib/merge'),
    dox           = require('../lib/default');

然后将 underscore.string 扩展到 underscore 上面:

merge(_, {str: underscoreStr});

之后:

command
    .version(
        console.log(`
        name: ${chalk.green(loadConfigFiled.name)}
        version: ${chalk.yellow(loadConfigFiled.version)}
        `)
    )
    .usage('<keywords>')
    .command('build')
    .description('开始生成文档')
    .option('-d \<folder\>', '输入文件夹')
    .option('-o \<folder\>', '输出文件夹');                                // 命令行工具版本展示

console.log('------------------------------------------------------------'.rainbow);
/**
 * 展示帮助信息函数
 */
var showHelp = function () {
    process.stdout.write(command.helpInformation());
    command.emit('--help or -h');
    process.exit(1);
};

command.on('--help', function () {
    console.log('\tCommands:\n'.green);
    console.log('\t\t\$ build       创建文档\n');
    console.log('\tExamples:\n'.green);
    console.log('\t\t\$ doxmate build \-o \<folder\> \-d [\<folder\>,...]\n');
    process.exit(1);
});                                                                                   // 命令行帮助

command.parse(process.argv);

这是用来显示命令相关的内容,那么如何执行命令呢,我们需要:

var cmd = command.args[0];  

来获取我们在命令行输出的内容,如我输入jdz build,则 cmd==>build

然后对 cmd 参数进行相关判断:

switch (cmd) {
    case 'build':
        if (!judgeCmdExistence(cmd)) showHelp();

        testBuildCommand(process.argv.slice(3));
        //process.exit(1);
        loadConfigFiled.source.exclude = _.map(loadConfigFiled.source.exclude, function (item) {
            return _.str.strRight(path.resolve(item),loadConfigFiled.projectHomePath).substring(1);
        });
        dox(loadConfigFiled, function (err) {
            if (err) {
                console.log(chalk.blue.bgRed.bold('\n\t生成文档失败' + err));
                process.exit(1);
            }
        });
        break;
    default:
        console.error(colors.inverse('\n\t提示:不能找到命令 ' + cmd + ' !'));
        return showHelp();
}

之后退出进程 process.exit(0);。具体的相关内容查看 jsdoc-zero/bin/dox

重点来了

文档生成工具的重点除了文档解析之外就是生成文件了,所以我们可以看下 jsdoc-zero/lib/default.js
大体上分为三个步骤:

  1. 建立文件索引

  2. 匹配相关文件夹和过滤相关文件夹

  3. 众多路径问题的处理

其他的我想大家这么聪明一看就可以 hold,然后可以根据自己的具体项目,更改相关方法定制自己的文档注释生成工具了。

PS:为什么“重点来了”这么短、这么水?怎么说呢,楼主这几天身体不怎么舒服,千言万语不知从何说起(jsdoc-zero/lib/default.js 虽然只有短短的几百行,内部方法也没多少,但是各个的路径处理太蛋疼了),具体参考 https://github.com/kahn1990/jsdoc-zero 或者 https://www.npmjs.com/package/jsdoc-zero

其他参考


kangkk
1.7k 声望69 粉丝

没什么想说的。