Navigation Menu

Skip to content

Commit

Permalink
big modify
Browse files Browse the repository at this point in the history
  • Loading branch information
Liu Lei committed Aug 30, 2016
1 parent 58a9ca5 commit 88fb01c
Show file tree
Hide file tree
Showing 15 changed files with 381 additions and 368 deletions.
3 changes: 2 additions & 1 deletion .gitignore
@@ -1,3 +1,4 @@
node_modules/*
.DS_store
.idea
.idea
.vscode
104 changes: 72 additions & 32 deletions README.md
Expand Up @@ -2,56 +2,79 @@

## 简介

工具可以通过schema文件生成数据库文档,通过路由文件、接口代码、注释等生成接口文档,每次commit自动更新文档,让人专注于代码编写。目前程序初次实现,还有很多功能需要完善,许多地方需要优化
工具可以自动化生成数据库文档,API接口文档,并通过修改git hooks,使项目的每次commit都会自动更新文档

## 安装

`npm i createDOC -g`

## 配置
- 在项目根目录使用`createDOC init`命令初始化,该命令会在当前目录创建`doc.json`文件。
- 生成`doc.json`文件后,需要详细配置数据库schemas存储路径(目前只支持关系型数据库),以及路由控制文件,以及子路由目录。
- API注释规则,遵循TJ大神dox规范,简化版规则如下
```js
/**
* API description
*
* @param {type} name/name=default_value description
* @return {String} description
* @example
* any example
*
* @other description
*/
```
*ps: 此工具为内部使用工具,如个人使用可下载源码,做简单修改即可*
## 使用

```sh
Usage: createDOC [options] [command]
Commands:

show 显示当前状态
Usage: createDOC [options] [command]

Commands:

init 初始化当前目录doc.json文件
show 显示配置文件状态
run 启动程序
modifyhook 修改项目下的hooks文件

modifyhook 修改项目下的hook文件
*

Options:

-h, --help output usage information
-V, --version output the version number
```

**使用方法:**
Examples:

1. 在开发项目根目录使用该命令工具,在项目根目录新建`doc.json`文件,指定`schema`存储目录,和`markdown`文件输出路径,文件样例如下。
2. 使用`createDOC -h`或者`createDOC -V(大写)`来确定`createDOC`是否安装成功。
3. 单独运行程序使用`createDOC run`命令。
4. 使用`createDOC modifyhook`命令修改本地钩子文件,之后无需任何操作,项目每次`commit`文档会自动更新。
5. 使用`createDOC show`命令随时查看输入输出路径,确保输入输出路径正确。
$ createDOC --help
$ createDOC -h
$ createDOC show
```

## 示例说明
doc.json示例
```json
{
"schemas":"/Users/mac/Desktop/testssss/models/",
//schema文件目录,目前所有schema文件都需要存在此目录的根目录,暂时 TODO:不支持子目录
"markdown": {
"path": "/Users/mac/Desktop/",
"file": "dbDocument.md"
{
"db": {
"schemas":"/Users/mac/Desktop/testssss/schemas",
"markdown": {
"path": "/Users/mac/Desktop/testssss/doc1",
"file": "db.md"
}
},
"api": {
"controller": "/Users/mac/Desktop/testssss/router.js",
"routes": "/Users/mac/Desktop/testssss/models",
"markdown": {
"path": "/Users/mac/Desktop/testssss/doc",
"file": "api.md"
}
}
//markdown文档输出目录和文件名
}
}
```
## 注意
1. 尽量全局安装。
2. schema文件格式,
1. 如果文件存在`tableName`属性,表名称为`tableName`的值,否则表名称设置为当前文件名。
2. 字段属性和值的关系必须严格遵守`key:{}`的格式,`:{``: {`是必须存在的标示,用于切割内容。
3. 单行注释使用`//这是注释`
4. 多行注释使用`/* 这是注释*/`,切勿出现多行`//`的情况。
5. 示例如下(注:只需要上述4条件满足,其他诸如示例前两行的`sequelize`官方格式为非必须,同时字段属性写法也无限制)。
3. 包版本更新后需要重新使用`createDOC modifyhook`命令设置本地钩子。
```javascript
schema.js示例
```js
module.exports = function(sequelize, DataTypes) {
return sequelize.define('test_zk_absence', {
//这是id
Expand Down Expand Up @@ -87,9 +110,26 @@ module.exports = function(sequelize, DataTypes) {
});
};
```
api注释示例
```js
/**
* 获取多个课程
* @param {Number} examinationId 考试类型
* @param {Number} subjectId 科目类型
* @param {Number} statusId=3 状态类型
* @param {String} startDate 更新开始时间
* @param {String} endDate 更新结束时间
* @param {String} keyword 关键词
* @param {Number} page 页码
* @return {Array} ok
* @example [1,2,3,3,4]
*/
getCourses(req, params) {
... ...
}
```
## TODO
1. 代码逻辑优化,适应力更强。
2. 代码速度、质量优化。
3. 增加路由、代码、注释文档生成功能。

[github地址](https://github.com/a1511870876/buildDOC)
159 changes: 135 additions & 24 deletions common/asyncfunc.js
Expand Up @@ -2,10 +2,12 @@ const Promise = require('bluebird'),
fs = Promise.promisifyAll(require('fs')),
path = require('path'),
co = require('co'),
handlebars = require('handlebars');
handlebars = require('handlebars'),
mkdirp = require('mkdirp'),
dox = require('dox');

const craeteDb = require('./../src/createDbDOC'),
createRouter = require('./../src/createRouterDOC'),
const craeteDbDoc = require('./../src/createDbDOC'),
createApiDoc = require('./../src/createApiDOC'),
func = require('./func'),
config = require('./config');

Expand Down Expand Up @@ -51,37 +53,82 @@ function* newDoc(inputInfos) {
}
var content = yield fs.readFileAsync(process.cwd() + '/doc.json', 'utf-8');
console.log('');
console.log('======= doc.json ========');
console.log(config.colors.rainbow('======= doc.json ========'));
console.log(content);
console.log('==== 请继续配置详细路径 ====');
console.log(config.colors.rainbow('==== 请继续配置详细路径 ===='));
console.log('');
break;
default:
break;
}
}
}
//初始化覆盖doc.json,处理函数
function* mkdirs(str, path) {
var pathname = config.colors.red(path);
if (Array.isArray(path)) {
if (path.length === 2) {
pathname = config.colors.red(path[0]) + ' 和 ' + config.colors.red(path[1]);
} else {
return;
}
}
process.stdout.write(config.colors.red(str) + '输出目录' + pathname + '不存在,是否创建 (y/n):');
process.stdin.resume();
process.stdin.setEncoding('utf-8');
process.stdin.on('data', (chunk) => {
co(function* () {
chunk = chunk.replace(/[\s\n]/, '');
if (chunk !== 'y' && chunk !== 'Y' && chunk !== 'n' && chunk !== 'N') {
console.log(config.colors.red('您输入的命令是: ' + chunk));
console.warn(config.colors.red('请输入正确指令:y/n'));
process.exit();
}
process.stdin.pause();
if (chunk === 'y' || chunk === 'Y') {
if (Array.isArray(path)) {
yield mkdir(path[0]);
console.log(config.colors.red(path[0]) + '创建成功');
yield mkdir(path[1]);
console.log(config.colors.red(path[1]) + '创建成功');
process.exit();
}
yield mkdir(path)
console.log(config.colors.red(path) + '创建成功');
process.exit();
} else if (chunk === 'n' || chunk === 'N') {
process.exit();
}
});
});
}

function* modifyHook(file) {
try {
const inputFile = process.cwd() + '/.git/hooks/prepare-commit-msg';
const content = yield fs.readFileAsync(file);
yield fs.writeFileAsync(inputFile, content);
console.log('修改 ' + inputFile + ' 成功。');
console.log('修改 ' + config.colors.red(inputFile) + ' 成功。');
} catch (err) {
console.warn(err);
}
}

function exists(file) {
return new Promise((resolve, reject) => {
fs.exists(file, function (exists) {
fs.exists(file, (exists) => {
if (!exists) resolve(exists);
resolve(exists);
});
});
}
function mkdir(path) {
return new Promise((resolve, reject) => {
mkdirp(path, (err) => {
if (err) reject(err);
else resolve()
})
})
}
exports.initAction = function* () {
try {
var docPath = yield exists(process.cwd() + '/doc.json');
Expand Down Expand Up @@ -113,20 +160,28 @@ exports.showAction = function* () {
const apiController = yield exists(doc.api.controller);
const apiMarkdownPath = yield exists(doc.api.markdown.path);
const apiRouters = yield exists(doc.api.routes);
console.log(`
======= √只表示路径存在,不代表路径配置正确 =======
======= X只表示路径不存在 =======

${docPath ? '√' : 'X'} doc.json -> ${process.cwd()}/doc.json
db:
${dbSchemas ? '√' : 'X'} 输入 <- ${doc.db.schemas}
${dbMarkdownPath ? '√' : 'X'} 输出 -> ${doc.db.markdown.path}${doc.db.markdown.file}
api:
${apiController ? '√' : 'X'} 控制 <- ${doc.api.controller}
${apiMarkdownPath ? '√' : 'X'} 输入 <- ${doc.api.routes}
${apiRouters ? '√' : 'X'} 输出 -> ${doc.api.markdown.path}${doc.api.markdown.file}`)
console.log(config.colors.rainbow(config.showDescription));
console.log(config.colors.red(`
${docPath ? '√' : 'X'}`) + ` doc.json -> ${process.cwd()}/doc.json
`);
console.log(' db:');
console.log(config.colors.red(`${dbSchemas ? '√' : 'X'}`) + ` 输入 <- ${doc.db.schemas}`);
console.log(config.colors.red(`${dbMarkdownPath ? '√' : 'X'}`) + ` 输出 -> ${doc.db.markdown.path}${doc.db.markdown.file}`);
console.log(' api:');
console.log(config.colors.red(`${apiController ? '√' : 'X'}`) + ` 控制 <- ${doc.api.controller}`)
console.log(config.colors.red(`${apiMarkdownPath ? '√' : 'X'}`) + ` 输入 <- ${doc.api.routes}`)
console.log(config.colors.red(`${apiRouters ? '√' : 'X'}`) + ` 输出 -> ${doc.api.markdown.path}${doc.api.markdown.file}`);
console.log('');
if (!dbMarkdownPath && apiMarkdownPath) {
yield mkdirs('db ', doc.db.markdown.path);
}
if (!apiMarkdownPath && dbMarkdownPath) {
yield mkdirs('api ', doc.api.markdown.path);
}
if (!apiMarkdownPath && !dbMarkdownPath) {
yield mkdirs('db 和 api ', [doc.db.markdown.path, doc.api.markdown.path]);
}
return;
} else {
console.warn(config.nofile);
Expand All @@ -145,11 +200,11 @@ exports.runAction = function* () {
// 处理db文档
doc.db.markdown.path = func.checkPath(doc.db.markdown.path);
doc.db.schemas = func.checkPath(doc.db.schemas);
yield craeteDb.createDOC(doc.db.schemas, doc.db.markdown);
//yield craeteDbDoc.createDOC(doc.db.schemas, doc.db.markdown);
// 处理api文档
doc.api.markdown.path = func.checkPath(doc.api.markdown.path);
doc.api.routes = func.checkPath(doc.api.routes);
yield createRouter.createDOC(doc.api.controller, doc.api.routes, doc.api.markdown);
yield createApiDoc.createDOC(doc.api.controller, doc.api.routes, doc.api.markdown);
} else {
console.warn(config.nofile);
return;
Expand All @@ -165,7 +220,7 @@ exports.modifyhookAction = function* () {
const commitSamplePath = yield exists(process.cwd() + '/.git/hooks/prepare-commit-msg.sample');
const commitPath = yield exists(process.cwd() + '/.git/hooks/prepare-commit-msg');
if (!commitPath && !commitSamplePath) {
console.log(config.nohook)
console.log(config.colors.red(nfig.nohook));
} else if (commitSamplePath) {
yield fs.renameAsync(process.cwd() + '/.git/hooks/prepare-commit-msg.sample',
process.cwd() + '/.git/hooks/prepare-commit-msg');
Expand Down Expand Up @@ -224,5 +279,61 @@ exports.getRoutes = function* (file) {
return data;
};

exports.buildDoxObjs = function* (routes, files) {
var doxObjs = [];
var count = 0;
for (var file of files) {
var code = yield fs.readFileAsync(file, 'utf-8');
doxObjs = doxObjs.concat(dox.parseComments(code));
count++;
if (count === files.length) {
return filterObj(routes, doxObjs);
}
}
}

function filterObj(routes, doxObjs) {
var pureObjArr = {};
doxObjs.map((obj) => {
var key = '';
var value = {};
if (obj.ctx) {
var params = [];
key = obj.ctx.name.replace(/[\*]/, '');
value.type = obj.ctx.type;
value.description = obj.description.full;
if (obj.tags && Array.isArray(obj.tags)) {
for (var tag of obj.tags) {
if (tag.type === 'param') {
var param = {};
if (/\=/.test(tag.name)) {
var name = tag.name.split('=');
tag.name = name[0];
tag.defaultValue = name[1];
}
param.name = tag.name || '';
param.defaultValue = tag.defaultValue || '';
param.description = tag.description || '';
param.type = (tag.types && Array.isArray(tag.types)) ? tag.types.join(' ') : '';
params.push(param)
value.param = params;
} else if (tag.type === 'example') {
value.example = tag.html || '';
} else if (tag.type === 'return') {
var returnValue = {};
returnValue.description = tag.description || '';
returnValue.type = (tag.types && Array.isArray(tag.types)) ? tag.types.join(' ') : '';
value.returnValue = returnValue;
} else {
var other = tag.type;
value[other] = tag.string || '';
}
}
}
pureObjArr[key] = Object.assign(value, routes[key]);
}
});
return pureObjArr;
}


0 comments on commit 88fb01c

Please sign in to comment.