Showing
8 changed files
with
128 additions
and
50 deletions
| ... | @@ -9,7 +9,7 @@ if (!target) { | ... | @@ -9,7 +9,7 @@ if (!target) { |
| 9 | process.exit(1); | 9 | process.exit(1); |
| 10 | } | 10 | } |
| 11 | 11 | ||
| 12 | -const mdview = new (require('../lib/mdview')), | 12 | +const mdview = new (require('../lib/mdviewer')), |
| 13 | path = require('path'); | 13 | path = require('path'); |
| 14 | 14 | ||
| 15 | const filename = path.resolve(process.cwd(), target); | 15 | const filename = path.resolve(process.cwd(), target); | ... | ... |
| ... | @@ -10,11 +10,11 @@ const configure = customize({ | ... | @@ -10,11 +10,11 @@ const configure = customize({ |
| 10 | "bind_port": 8200, | 10 | "bind_port": 8200, |
| 11 | }, | 11 | }, |
| 12 | "md": { | 12 | "md": { |
| 13 | - "base_path": "md", | 13 | + "base_path": {}, |
| 14 | "default_md": "readme.md", | 14 | "default_md": "readme.md", |
| 15 | "theme": "metro-lake", | 15 | "theme": "metro-lake", |
| 16 | "toc": true | 16 | "toc": true |
| 17 | - } | 17 | + }, |
| 18 | }); | 18 | }); |
| 19 | 19 | ||
| 20 | //绑定到全局变量 | 20 | //绑定到全局变量 | ... | ... |
lib/md-action.js
0 → 100644
| 1 | +/** | ||
| 2 | + * 处理接口api的action路由 | ||
| 3 | + */ | ||
| 4 | +/* global global */ | ||
| 5 | +/* global process */ | ||
| 6 | +"use strict"; | ||
| 7 | + | ||
| 8 | +const _ = require('lodash'), | ||
| 9 | + path = require('path'), | ||
| 10 | + express = require('express'), | ||
| 11 | + router = express.Router(), | ||
| 12 | + config = global.config | ||
| 13 | +; | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * markdown文件查看 | ||
| 17 | + * @param alias_name 路由别名 | ||
| 18 | + * @param md_path markdown文档路径 | ||
| 19 | + * @return {*} | ||
| 20 | + * @constructor | ||
| 21 | + */ | ||
| 22 | +function MdAction (alias_name, md_path) { | ||
| 23 | + let alias; | ||
| 24 | + | ||
| 25 | + switch (!!alias_name) { | ||
| 26 | + case false: // 没有定义别名,默认为根 | ||
| 27 | + alias = ''; | ||
| 28 | + break; | ||
| 29 | + case /\/.+/.test(alias_name): // 带根路径别名,直接用 | ||
| 30 | + alias = alias_name; | ||
| 31 | + break; | ||
| 32 | + case /[^\/].+/.test(alias_name): // 不带根路径别名,补充根路径 | ||
| 33 | + alias = '/' + alias_name; | ||
| 34 | + break; | ||
| 35 | + default: // 只传入根路径,和别名空一样处理 | ||
| 36 | + alias = '' | ||
| 37 | + | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + let doc_path = path.resolve(process.cwd(), md_path || ''); | ||
| 41 | + | ||
| 42 | + const MD_REGEXP = new RegExp(`^${alias}\\/([\\/\\w]*)`); | ||
| 43 | + | ||
| 44 | + //根据别名处理文档目录所在的markdown文件 | ||
| 45 | + const viewer = new (require('./view-markdown'))(doc_path, config.md); | ||
| 46 | + router.get(/(.*)/, function request (req, res, next) { | ||
| 47 | + let url = req.url, urls = url.match(MD_REGEXP) || [], query = req.query; | ||
| 48 | + if (!urls.length) { | ||
| 49 | + return next(); | ||
| 50 | + } | ||
| 51 | + let ext = path.parse(url).ext; | ||
| 52 | + if (ext && ext !== '.md') { | ||
| 53 | + return next(); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + res.send(viewer.render(urls[1], query.t)); | ||
| 57 | + }); | ||
| 58 | + //加载文档目录为静态页,别名为空时指向根路径 | ||
| 59 | + router.use(alias || '/', express.static(doc_path)); | ||
| 60 | + | ||
| 61 | + return router; | ||
| 62 | +} | ||
| 63 | + | ||
| 64 | +module.exports = MdAction; |
| ... | @@ -33,12 +33,10 @@ function MarkdownIt (opts) { | ... | @@ -33,12 +33,10 @@ function MarkdownIt (opts) { |
| 33 | try { | 33 | try { |
| 34 | content = fs.readFileSync(filename).toString(); | 34 | content = fs.readFileSync(filename).toString(); |
| 35 | result.html = md.render(content); | 35 | result.html = md.render(content); |
| 36 | + result.status = 200; | ||
| 36 | } catch (e) { | 37 | } catch (e) { |
| 37 | - console.error('convert md to html error', e); | 38 | + // console.error('convert md to html error', e); |
| 38 | - result.html = md.render(` | 39 | + result.status = 404; |
| 39 | -# 404 | ||
| 40 | -*文件找不到!* | ||
| 41 | -`) | ||
| 42 | } | 40 | } |
| 43 | 41 | ||
| 44 | try { | 42 | try { |
| ... | @@ -46,10 +44,30 @@ function MarkdownIt (opts) { | ... | @@ -46,10 +44,30 @@ function MarkdownIt (opts) { |
| 46 | result.tokens = md.parse(content, {}); | 44 | result.tokens = md.parse(content, {}); |
| 47 | } | 45 | } |
| 48 | } catch (e) { | 46 | } catch (e) { |
| 49 | - console.error('parse md error', e) | 47 | + // console.warn('parse md error', e) |
| 50 | } | 48 | } |
| 51 | 49 | ||
| 52 | return result; | 50 | return result; |
| 51 | + }; | ||
| 52 | + | ||
| 53 | + /** | ||
| 54 | + * 返回渲染文本 | ||
| 55 | + * @param src | ||
| 56 | + * @param env | ||
| 57 | + * @return {*} | ||
| 58 | + */ | ||
| 59 | + this.render = function (src, env) { | ||
| 60 | + return md.render(src, env) | ||
| 61 | + }; | ||
| 62 | + | ||
| 63 | + /** | ||
| 64 | + * 返回解析文本 | ||
| 65 | + * @param src | ||
| 66 | + * @param env | ||
| 67 | + * @return {*} | ||
| 68 | + */ | ||
| 69 | + this.parse = function (src, env) { | ||
| 70 | + return md.parse(src, env) | ||
| 53 | } | 71 | } |
| 54 | } | 72 | } |
| 55 | 73 | ... | ... |
| ... | @@ -5,29 +5,43 @@ | ... | @@ -5,29 +5,43 @@ |
| 5 | 5 | ||
| 6 | const path = require('path'); | 6 | const path = require('path'); |
| 7 | 7 | ||
| 8 | + | ||
| 8 | class ViewMarkdown { | 9 | class ViewMarkdown { |
| 9 | - constructor (options) { | 10 | + constructor (doc_path, options) { |
| 10 | this.options = options || {}; | 11 | this.options = options || {}; |
| 11 | - if (!this.options.base_path) { | 12 | + if (!doc_path) { |
| 12 | - throw new Error('no base path for markdown') | 13 | + throw new Error('document path for markdown not found') |
| 13 | } | 14 | } |
| 15 | + | ||
| 16 | + this.doc_path = doc_path; | ||
| 17 | + this.mdviewer = new (require('./mdviewer'))({parseTokens: true, toc: this.options.toc}); | ||
| 14 | } | 18 | } |
| 15 | 19 | ||
| 20 | + /** | ||
| 21 | + * 渲染文件 | ||
| 22 | + * @param filename 文件名,绝对路径 | ||
| 23 | + * @param theme 主题 | ||
| 24 | + * @return {string} | ||
| 25 | + */ | ||
| 16 | render (filename, theme) { | 26 | render (filename, theme) { |
| 17 | const options = this.options; | 27 | const options = this.options; |
| 18 | //默认md | 28 | //默认md |
| 19 | if (!filename || filename.match(/.+\/$/)) { | 29 | if (!filename || filename.match(/.+\/$/)) { |
| 20 | - filename = (filename || '') + options.default_md || 'readme.md' | 30 | + filename = (filename || '') + (options.default_md || 'readme.md') |
| 21 | } | 31 | } |
| 22 | - let file = path.resolve(options.base_path, filename); | 32 | + let file = path.resolve(this.doc_path, filename); |
| 23 | if (!path.parse(file).ext) { | 33 | if (!path.parse(file).ext) { |
| 24 | //追加后缀 | 34 | //追加后缀 |
| 25 | file += '.md' | 35 | file += '.md' |
| 26 | } | 36 | } |
| 27 | - const mdview = new (require('./mdview'))({parseTokens: true, toc: options.toc}); | 37 | + let result = this.mdviewer.renderFile(file); |
| 28 | - let result = mdview.renderFile(file); | ||
| 29 | let tittle = result.tokens && result.tokens[1] && result.tokens[1].content || filename; | 38 | let tittle = result.tokens && result.tokens[1] && result.tokens[1].content || filename; |
| 30 | theme = theme || options.theme; | 39 | theme = theme || options.theme; |
| 40 | + let content = result.status === 404 ? this.mdviewer.render(` | ||
| 41 | +# 404 | ||
| 42 | +> **${filename}不存在** | ||
| 43 | +`) | ||
| 44 | + : result.html; | ||
| 31 | return ` | 45 | return ` |
| 32 | <!DOCTYPE html> | 46 | <!DOCTYPE html> |
| 33 | <html> | 47 | <html> |
| ... | @@ -40,7 +54,7 @@ class ViewMarkdown { | ... | @@ -40,7 +54,7 @@ class ViewMarkdown { |
| 40 | </head> | 54 | </head> |
| 41 | <body> | 55 | <body> |
| 42 | <div class='markdown ${theme}'> | 56 | <div class='markdown ${theme}'> |
| 43 | - ${result.html} | 57 | + ${content} |
| 44 | </div> | 58 | </div> |
| 45 | </body | 59 | </body |
| 46 | </html> | 60 | </html> |
| ... | @@ -48,4 +62,4 @@ class ViewMarkdown { | ... | @@ -48,4 +62,4 @@ class ViewMarkdown { |
| 48 | } | 62 | } |
| 49 | } | 63 | } |
| 50 | 64 | ||
| 51 | -module.exports = ViewMarkdown | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 65 | +module.exports = ViewMarkdown; | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -3,24 +3,19 @@ const app = express(); | ... | @@ -3,24 +3,19 @@ const app = express(); |
| 3 | 3 | ||
| 4 | const config = require('./init/config'); | 4 | const config = require('./init/config'); |
| 5 | 5 | ||
| 6 | -const path = require('path'); | 6 | +//markdown主题 |
| 7 | +app.use(express.static(__dirname + '/themes')); | ||
| 7 | 8 | ||
| 8 | -const MARKDOWN_FILE_BASE = path.resolve(process.cwd(), config.md.base_path); | ||
| 9 | 9 | ||
| 10 | -app.use(express.static(__dirname + '/themes')); | 10 | +const MdAction = require('./lib/md-action'); |
| 11 | -app.use(express.static(MARKDOWN_FILE_BASE)); | ||
| 12 | 11 | ||
| 13 | -function viewMarkdown (req, res, next) { | 12 | +let base_path = config.md.base_path || {}; |
| 14 | - let url = req.url, urls = url.match(/^\/([\/\w]+)/) || [], query = req.query; | 13 | +Object.keys(base_path).forEach(p => { |
| 15 | - let ext = path.parse(url).ext; | 14 | + app.use('/', new MdAction(p, base_path[p])) |
| 16 | - if (ext && ext !== 'md') { | 15 | +}); |
| 17 | - return next(); | ||
| 18 | - } | ||
| 19 | - const viewer = new (require('./lib/view-markdown'))(config.md); | ||
| 20 | - res.send(viewer.render(urls[1], query.t)); | ||
| 21 | -} | ||
| 22 | 16 | ||
| 23 | -app.get('/*', viewMarkdown); | 17 | +//默认 |
| 18 | +app.use('/', new MdAction('/', 'md')); | ||
| 24 | 19 | ||
| 25 | const PORT = config.system.bind_port; | 20 | const PORT = config.system.bind_port; |
| 26 | app.listen(PORT); | 21 | app.listen(PORT); | ... | ... |
| ... | @@ -60,28 +60,15 @@ | ... | @@ -60,28 +60,15 @@ |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | .metro-lake h2 { | 62 | .metro-lake h2 { |
| 63 | + width: max-content; | ||
| 64 | + margin: 0.8rem auto; | ||
| 63 | font-size: 1.4rem; | 65 | font-size: 1.4rem; |
| 64 | border-bottom: 1px solid #bbb; | 66 | border-bottom: 1px solid #bbb; |
| 65 | - line-height: 1.6rem; | 67 | + /*line-height: 1.6rem;*/ |
| 66 | - padding-bottom: 0.8rem; | 68 | + padding-bottom: 0.5rem; |
| 67 | text-align: center; | 69 | text-align: center; |
| 68 | } | 70 | } |
| 69 | 71 | ||
| 70 | -.metro-lake h2:before { | ||
| 71 | - content: '══'; | ||
| 72 | - font-weight: 100; | ||
| 73 | - letter-spacing: -1px; | ||
| 74 | - padding-right: 1rem; | ||
| 75 | - color: #888 | ||
| 76 | -} | ||
| 77 | -.metro-lake h2:after { | ||
| 78 | - content: '══'; | ||
| 79 | - font-weight: 100; | ||
| 80 | - letter-spacing: -1px; | ||
| 81 | - padding-left: 1rem; | ||
| 82 | - color: #888 | ||
| 83 | -} | ||
| 84 | - | ||
| 85 | .metro-lake blockquote h2:before { | 72 | .metro-lake blockquote h2:before { |
| 86 | content: ''; | 73 | content: ''; |
| 87 | padding-right: 0; | 74 | padding-right: 0; | ... | ... |
-
Please register or login to post a comment