-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
qizhang.yang
committed
Aug 6, 2018
0 parents
commit 7c19ad7
Showing
18 changed files
with
2,584 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
# enjoy doc | ||
|
||
通过本地文件,网络地址等快速生成文档 | ||
|
||
## 目的 | ||
|
||
公司的项目中有很多开发相关的文档,之前习惯放gitlab的wiki,效率和体验都不是很好,于是做了这个小工具,目的就是为了方便的组织和查看本地文档。 | ||
|
||
## 功能 | ||
|
||
- 使用markdown格式 | ||
- 支持自定义目录 | ||
- 支持*绝对路径*,*文件内容*,*网络地址*三种文件形式 | ||
|
||
目前的问题: | ||
|
||
- 不支持页内hash导航 | ||
|
||
## 安装 | ||
|
||
本地安装 | ||
|
||
```bash | ||
npm install enjoy-doc | ||
``` | ||
|
||
也可以全局 | ||
|
||
```bash | ||
npm install enjoy-doc -g | ||
``` | ||
|
||
## 使用 | ||
|
||
定义一个导出文档文件的模块 | ||
|
||
```javascript | ||
/** | ||
* docs.js | ||
*/ | ||
|
||
const path = require('path'); | ||
|
||
const base = '../js/mlrn/'; | ||
const getFilePath = p => path.join(__dirname, base, p); | ||
|
||
module.exports = { | ||
title: 'MED-RN文档', | ||
nav: [ | ||
{ | ||
text: '首页', | ||
file: '# MED-RN文档', | ||
route: '', | ||
}, | ||
{ | ||
text: '展示组件', | ||
children: [ | ||
{ | ||
text: 'Header (头部)', | ||
file: getFilePath('ui/Header/index.md'), | ||
route: 'ui-Header', | ||
}, | ||
{ | ||
text: 'FooterButton (底部按钮)', | ||
file: getFilePath('ui/FooterButton/index.md'), | ||
route: 'ui-FooterButton', | ||
}, | ||
{ | ||
text: 'Divider (页面分隔线)', | ||
file: getFilePath('ui/Divider/index.md'), | ||
route: 'ui-Divider', | ||
}, | ||
{ | ||
text: 'EmptyView (空白展示)', | ||
file: getFilePath('ui/EmptyView/index.md'), | ||
route: 'ui-EmptyView', | ||
}, | ||
{ | ||
text: 'Image (图片)', | ||
file: getFilePath('ui/Image/index.md'), | ||
route: 'ui-Image', | ||
}, | ||
{ | ||
text: 'InlineImage (文本图片)', | ||
file: getFilePath('ui/InlineImage/index.md'), | ||
route: 'ui-InlineImage', | ||
}, | ||
{ | ||
text: 'AnimationImageView (帧动画播放)', | ||
file: getFilePath('ui/AnimationImageView/index.md'), | ||
route: 'ui-AnimationImageView', | ||
}, | ||
], | ||
}, | ||
{ | ||
text: '表单组件', | ||
children: [ | ||
{ | ||
text: 'InputItem (文本输入)', | ||
file: getFilePath('ui/InputItem/index.md'), | ||
route: 'ui-InputItem', | ||
}, | ||
{ | ||
text: 'Radio (单选框)', | ||
file: getFilePath('ui/Radio/index.md'), | ||
route: 'ui-Radio', | ||
}, | ||
{ | ||
text: 'SearchInputWithClear (搜索框)', | ||
file: getFilePath('ui/SearchInputWithClear/index.md'), | ||
route: 'ui-SearchInputWithClear', | ||
}, | ||
{ | ||
text: 'SidePickerView (侧边选择器)', | ||
file: getFilePath('ui/SidePickerView/index.md'), | ||
route: 'ui-SidePickerView', | ||
}, | ||
], | ||
}, | ||
// ... | ||
], | ||
}; | ||
|
||
``` | ||
|
||
添加一个命令 | ||
|
||
```json | ||
"doc": "enjoy-doc ./docs.js --port=4000" | ||
``` | ||
|
||
然后使用命令打开 | ||
|
||
```bash | ||
npm run doc | ||
``` | ||
|
||
### 命令参数 | ||
|
||
```bash | ||
enjoy-doc file --port=4000 | ||
``` | ||
|
||
- `file` 配置文件 | ||
- `--port` 运行的端口 | ||
|
||
## 配置说明 | ||
|
||
- `title`: 标题 | ||
- `nav`: 导航路径 | ||
|
||
nav配置: | ||
|
||
- `text`: 标题,必填 | ||
- `file`: 文件,支持传入*绝对路径*,*文件内容*,*网络地址*三种 | ||
- `route`: 路由的唯一名称,可选,如果不传,则不可选中 | ||
- `children`: 子导航配置,同nav | ||
|
||
## TODO | ||
|
||
- 支持文档内的hash导航 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
/** | ||
* app.js | ||
*/ | ||
|
||
const express = require('express'); | ||
const app = express(); | ||
const http = require('http'); | ||
const https = require('https'); | ||
const server = http.Server(app); | ||
const io = require('socket.io')(server); | ||
const path = require('path'); | ||
const fs = require('fs'); | ||
const opn = require('opn'); | ||
|
||
const docConfig = require(path.resolve(process.argv[2])); | ||
|
||
const args = (function () { | ||
const restArgv = process.argv.splice(3); | ||
return restArgv.reduce((prev, item) => { | ||
const pairs = item.split('='); | ||
prev[pairs[0].replace(/-+/g, '')] = pairs[1] || 1; | ||
return prev; | ||
}, {}); | ||
})(); | ||
|
||
const routeMap = (function () { | ||
const map = new Map(); | ||
function find(children) { | ||
if (!children) return; | ||
|
||
children.forEach((item) => { | ||
if (item.route !== undefined) { | ||
map.set(item.route || '__empty', item); | ||
} | ||
if (item.children) { | ||
find(item.children); | ||
} | ||
}); | ||
} | ||
|
||
find(docConfig.nav); | ||
return map; | ||
})(); | ||
|
||
function covertMDFile(filePath, fileData) { | ||
return fileData.replace(/[^!]?\[(.(?!\\\]))*]\(([^)]*)\)/, function () { | ||
const str = arguments[0]; | ||
const match = arguments[2]; | ||
if (/http(s)?/.test(match)) { | ||
return str; | ||
} | ||
const linkPath = path.join(filePath, '..', match); | ||
let route = ''; | ||
routeMap.forEach((item) => { | ||
if (item.file === linkPath) { | ||
route = item.route; | ||
} | ||
}); | ||
|
||
// use hash | ||
return route ? str.replace(match, '#' + route) : str; | ||
}); | ||
} | ||
|
||
app.locals = { | ||
version: require('./package.json').version, | ||
} | ||
|
||
app.use(express.static(path.join(__dirname, './public'))); | ||
app.set('view engine', 'ejs'); | ||
app.set('views', path.join(__dirname, './views')); | ||
|
||
app.get('/', (req, res) => { | ||
res.render('index', { config: docConfig, port: PORT }); | ||
}); | ||
|
||
app.get('/doc', (req, res, next) => { | ||
const config = routeMap.get(req.query.route || '__empty'); | ||
if (!config) { | ||
return res.sendStatus(404); | ||
} | ||
|
||
// 来自远程 | ||
if (/http(s)?:/gi.test(config.file)) { | ||
const { URL } = require('url'); | ||
let client = http; | ||
if (config.file.startsWith('https')) { | ||
client = https; | ||
} | ||
client.get(new URL(config.file), (_req) => { | ||
_req.pipe(res) | ||
}).on('error', (e) => { | ||
next(e); | ||
}); | ||
return; | ||
} | ||
|
||
if (!fs.existsSync(config.file)) { | ||
return res.send(config.file); | ||
} | ||
|
||
fs.readFile(config.file, (err, data) => { | ||
if (err) { | ||
return next(err); | ||
} | ||
res.send(covertMDFile(config.file, data.toString())); | ||
}); | ||
}); | ||
|
||
app.get('/imgproxy', (req, res, next) => { | ||
const { src, route } = req.query; | ||
const config = routeMap.get(req.query.route); | ||
const imgPath = path.join(config.file, '..', src); | ||
res.sendFile(imgPath); | ||
}); | ||
|
||
app.use(function errorHandler(err, req, res, next) { | ||
console.log(err); | ||
res.sendStatus(500); | ||
}); | ||
|
||
const PORT = args.port || 3000; | ||
server.listen(PORT, () => { | ||
console.log(`Server run port ${PORT}`); | ||
setTimeout(() => { | ||
io.clients((error, clients) => { | ||
if (clients.length === 0) { | ||
opn(`http://localhost:${PORT}`); | ||
} | ||
}); | ||
}, 2000); | ||
}); | ||
|
||
io.on('connection', socket => { | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#!/usr/bin/env node | ||
|
||
const { spawn } = require('child_process'); | ||
const path = require('path'); | ||
const fs = require('fs'); | ||
|
||
const argv = process.argv; | ||
|
||
let childProcess; | ||
|
||
function run() { | ||
if (childProcess) { | ||
childProcess.kill(); | ||
} | ||
childProcess = spawn('node', [path.resolve(__dirname, './app')].concat(argv.slice(2)), { stdio: 'inherit' }); | ||
|
||
childProcess.on('error', () => { | ||
console.log('Error occurred, restart...'); | ||
run(); | ||
}); | ||
} | ||
|
||
fs.watchFile(process.argv[2], (curr, prev) => { | ||
console.log('Reload docs...'); | ||
run(); | ||
}); | ||
|
||
run(); | ||
|
Oops, something went wrong.