├── .circleci └── config.yml ├── .editorconfig ├── .eslintrc.js ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── bug_report_cn.md │ ├── feature_request.md │ └── feature_request_cn.md ├── .gitignore ├── LICENSE ├── README.md ├── babel.config.js ├── commitlint.config.js ├── docs ├── .vuepress │ ├── config.js │ └── public │ │ └── favicon.ico ├── README.md ├── example │ ├── README.md │ ├── custom.md │ ├── demo.md │ └── vuepress.md └── zh │ ├── README.md │ └── example │ ├── README.md │ ├── custom.md │ ├── demo.md │ └── vuepress.md ├── package.json ├── rollup.config.js ├── src └── index.js └── test ├── .eslintrc.js ├── Error.vue ├── MyComponent.vue ├── __snapshots__ └── index.test.js.snap ├── fragments ├── at-path.md ├── code-block.md ├── custom-re.md ├── custom-root.md ├── error.md ├── multiple-times.md ├── not-found.md ├── not-match.md └── relative-path.md └── index.test.js /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Javascript Node CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details 4 | # 5 | version: 2 6 | 7 | defaults: &defaults 8 | docker: 9 | - image: circleci/node:latest 10 | working_directory: ~/project/repo 11 | 12 | jobs: 13 | install: 14 | <<: *defaults 15 | steps: 16 | - checkout 17 | - restore_cache: 18 | keys: 19 | - v1-dependencies-{{ checksum "package.json" }} 20 | - v1-dependencies- 21 | - run: yarn install 22 | - save_cache: 23 | paths: 24 | - node_modules 25 | key: v1-dependencies-{{ checksum "package.json" }} 26 | - persist_to_workspace: 27 | root: ~/project 28 | paths: 29 | - repo 30 | 31 | test: 32 | <<: *defaults 33 | steps: 34 | - attach_workspace: 35 | at: ~/project 36 | - run: yarn test && npx codecov 37 | 38 | deploy: 39 | <<: *defaults 40 | steps: 41 | - attach_workspace: 42 | at: ~/project 43 | - add_ssh_keys: 44 | fingerprints: 45 | - f9:11:16:e1:69:73:76:5d:46:11:4e:c1:36:2b:77:8a 46 | - run: ssh-keyscan -H github.com >> ~/.ssh/known_hosts 47 | - run: yarn docs:build 48 | - run: npx gh-pages -u "BuptStEve " -m "[ci skip]" -d docs/.vuepress/dist 49 | 50 | workflows: 51 | version: 2 52 | install-and-test: 53 | jobs: 54 | - install 55 | - test: 56 | requires: 57 | - install 58 | 59 | install-and-deploy: 60 | jobs: 61 | - install 62 | - deploy: 63 | requires: 64 | - install 65 | filters: 66 | branches: 67 | only: master 68 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: 'standard', 3 | parser: 'babel-eslint', 4 | rules: { 5 | 'indent': [2, 4], 6 | 'promise/param-names': 0, 7 | 'comma-dangle': [2, 'always-multiline'], 8 | }, 9 | } 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: 'bug: your bug...' 5 | labels: bug 6 | assignees: BuptStEve 7 | 8 | --- 9 | 10 | **Version** 11 | Version [e.g. 0.1.0] 12 | 13 | **Describe the bug** 14 | A clear and concise description of what the bug is. If applicable, add screenshots to help explain your problem. 15 | 16 | **To Reproduce** 17 | Steps to reproduce the behavior: 18 | 1. Go to '...' 19 | 2. Click on '....' 20 | 3. Scroll down to '....' 21 | 4. See error 22 | 23 | If it's convenient: 24 | 25 | * Add an online address to reproduce: 26 | * codepen: https://codepen.io/ 27 | * jsfiddle: https://jsfiddle.net/ 28 | * codesandbox: https://codesandbox.io/ 29 | * Add a repository to reproduce:https://github.com/new 30 | 31 | **Expected behavior** 32 | A clear and concise description of what you expected to happen. 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report_cn.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 报告 Bug 3 | about: 发现了一个 bug! 4 | title: 'bug: your bug...' 5 | labels: bug 6 | assignees: BuptStEve 7 | 8 | --- 9 | 10 | **版本** 11 | Version [e.g. 0.1.0] 12 | 13 | **描述一下 bug** 14 | 简洁清晰地描述一下 bug。如果方便的话,添加一些截图描述你的问题。 15 | 16 | **复现 bug** 17 | 复现的步骤: 18 | 19 | 1. 首先 '...' 20 | 2. 点击了 '...' 21 | 3. 滚动到了 '...' 22 | 4. 看到了错误 23 | 24 | 如果方便的话: 25 | 26 | * 复现 bug 的在线地址: 27 | * codepen: https://codepen.io/ 28 | * jsfiddle: https://jsfiddle.net/ 29 | * codesandbox: https://codesandbox.io/ 30 | * 复现 bug 的仓库地址:https://github.com/new 31 | 32 | **预期行为** 33 | 简洁清晰地描述一下预期行为。 34 | 35 | **附加上下文** 36 | 添加一些问题的相关上下文。 37 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: 'feat: your feature...' 5 | labels: enhancement 6 | assignees: BuptStEve 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request_cn.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 添加 Feature 3 | about: 新特性支持 4 | title: 'feat: your feature...' 5 | labels: enhancement 6 | assignees: BuptStEve 7 | 8 | --- 9 | 10 | **你的功能请求是否与某些问题相关?请描述** 11 | 简洁清晰地描述一下当前有什么问题。如果方便的话,添加一些截图描述你的问题。 12 | 13 | **描述您想要的解决方案** 14 | 简洁清晰地描述一下你想要的特性是怎样的。 15 | 16 | **描述你考虑过的备选方案** 17 | 简洁清晰地描述一下你考虑过的其他备选方案,可能会有什么问题。 18 | 19 | **附加上下文** 20 | 添加一些问题的相关上下文。 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | *.log 3 | coverage 4 | .DS_Store 5 | node_modules 6 | docs/.vuepress/dist/ 7 | 8 | yarn.lock 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) StEve Young 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

markdown-it-vuese

2 | 3 |

4 | 5 | Build Status 6 | 7 | 8 | Coverage Status 9 | 10 | 11 | dependencies 12 | 13 | 14 | Downloads per month 15 | Version 16 | License 17 | 18 |

19 | 20 | English | 简体中文 21 | 22 | > [Vuese][1] plugin for [markdown-it][2] markdown parser. 23 | 24 | With this plugin, you can use [Vuese][1] to automatically generate documents while importing existing `*.vue` files via following syntax. 25 | 26 | ```md 27 | <[vuese](@/filePath) 28 | ``` 29 | 30 | > The default value of @ is `process.cwd()`. 31 | 32 | Please click here to see the demo 33 | 34 | ## Install 35 | 36 | ```bash 37 | $ npm i -S markdown-it-vuese 38 | # OR 39 | $ yarn add markdown-it-vuese 40 | ``` 41 | 42 | ## Usage 43 | 44 | ```js 45 | const md = require('markdown-it')() 46 | .use(require('markdown-it-vuese') [, options]) 47 | ``` 48 | 49 | ## Options 50 | 51 | ```js 52 | const md = require('markdown-it')() 53 | .use(require('markdown-it-vuese'), { 54 | root: 'some path', 55 | vueseRe: /your regexp/, 56 | useParser: parserRes => parserRes.name, 57 | useRender: (vueseRender) => { 58 | const renderRes = vueseRender.render() 59 | const markdownRes = vueseRender.renderMarkdown() 60 | 61 | return 'something' 62 | }, 63 | useAll: ({ ... }) => { 64 | return 'something' 65 | }, 66 | }) 67 | ``` 68 | 69 | ### root 70 | * Type: `String` 71 | * Default: `process.cwd()` 72 | 73 | Root Directory, this value will replace the @ in file path. 74 | 75 | ### vueseRe 76 | * Type: `RegExp` 77 | * Default: `/<\[vuese\]\((.+)\)/i` 78 | 79 | Regular expression, you can customize it as you like. 80 | 81 | ### ruleName 82 | * Type: `String` 83 | * Default: `vuese` 84 | 85 | Rule name, it will be used by [markdown-it][2], so be careful not to duplicate [existing rules][9]. 86 | 87 | Use it with `vueseRe`, we can use different rules in the same document to render different results. 88 | 89 | ```js 90 | const vuese = require('markdown-it-vuese') 91 | 92 | const md = require('markdown-it')() 93 | // default 94 | // <[vuese](filePath) 95 | .use(vuese) 96 | // <[vuese-h3](filePath) 97 | // No title, `Props` and other attributes should be changed from `

` to `

` 98 | .use(vuese, { 99 | vueseRe: /<\[vuese-h3\]\((.+)\)/i, 100 | ruleName: 'vuese-h3', 101 | useRender: (vueseRender) => { 102 | const renderRes = vueseRender.render() 103 | const genMd = key => `### ${key}\n${renderRes[key]}\n` 104 | 105 | return Object.keys(renderRes).map(genMd).join('') 106 | }, 107 | }) 108 | ``` 109 | 110 | ### useParser 111 | * Type: `Function` 112 | * Default: `null` 113 | 114 | It takes [@vuese/parser `ParserResult`][7] as a parameter. 115 | 116 | If `useParser` exists, it returns the result directly after running, otherwise try running `useRender`. 117 | 118 | ### useRender 119 | * Type: `Function` 120 | * Default: `null` 121 | 122 | It takes [@vuese/markdown-render `Render Class`][8] as a parameter. 123 | 124 | If `useRender` exists, it returns the result directly after running, otherwise try running `useAll`. 125 | 126 | For example, you can call the following methods to generate objects and markdown documents, respectively. 127 | 128 | * `render`: will generate `renderRes` 129 | * `renderMarkdown`: will generate `markdownRes` 130 | 131 | ### useAll 132 | * Type: `Function` 133 | * Default: `null` 134 | 135 | It takes an object as parameters with there attributes: `content`(source file content), `parserRes`, `renderRes`, `markdownRes`. 136 | 137 | Return `markdownRes.content` by default, if `useAll` does not exist. 138 | 139 | ```js 140 | const md = require('markdown-it')() 141 | .use(require('markdown-it-vuese'), { 142 | useAll: ({ 143 | content, 144 | parserRes, 145 | renderRes, 146 | markdownRes, 147 | }) => { 148 | return 'something' 149 | }, 150 | }) 151 | ``` 152 | 153 | ### parserOptions 154 | * Type: `Object` 155 | * Default: `{}` 156 | 157 | It passes [@vuese/parser options][5] 158 | 159 | ### renderOptions 160 | * Type: `Object` 161 | * Default: `{}` 162 | 163 | It passes [@vuese/markdown-render options][6] 164 | 165 | ## License 166 | 167 | [MIT](http://opensource.org/licenses/MIT) 168 | 169 | Copyright (c) [StEve Young](https://github.com/BuptStEve) 170 | 171 | [1]: https://github.com/vuese/vuese 172 | [2]: https://github.com/markdown-it/markdown-it 173 | [3]: https://vuese.org/parser/ 174 | [4]: https://vuese.org/markdown-render/ 175 | [5]: https://vuese.org/parser/#parseroptions 176 | [6]: https://vuese.org/markdown-render/#renderoptions 177 | [7]: https://vuese.org/parser/#parserresult 178 | [8]: https://vuese.org/markdown-render/#render-class 179 | [9]: https://markdown-it.github.io/markdown-it/#Renderer.prototype.rules 180 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | test: { 4 | presets: [ 5 | [ 6 | '@babel/preset-env', 7 | { targets: { 'node': 'current' } }, 8 | ], 9 | ], 10 | }, 11 | production: { 12 | presets: [ 13 | [ 14 | '@babel/preset-env', 15 | { modules: false }, 16 | ], 17 | ], 18 | plugins: [ 19 | '@babel/plugin-proposal-object-rest-spread', 20 | ], 21 | }, 22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // https://www.npmjs.com/package/@commitlint/config-conventional 3 | extends: ['@commitlint/config-conventional'], 4 | rules: {}, 5 | } 6 | -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | const vuese = require('../../src/') 2 | const { name, description } = require('../../package.json') 3 | 4 | const ecosystemItems = [ 5 | { text: '📝vuepress-plugin-demo-code', link: 'https://buptsteve.github.io/vuepress-plugin-demo-code/' }, 6 | ] 7 | 8 | const exampleChildren = [ 9 | '', 10 | ['demo', 'Vuese Demo'], 11 | 'vuepress', 12 | 'custom', 13 | ] 14 | 15 | module.exports = { 16 | base: '/' + name + '/', 17 | locales: { 18 | '/': { lang: 'en-US', title: name, description }, 19 | '/zh/': { 20 | lang: 'zh-CN', 21 | title: name, 22 | description: '📖 基于 markdown-it 的 Vuese 插件', 23 | }, 24 | }, 25 | head: [ 26 | ['link', { rel: 'icon', href: `/favicon.ico` }], 27 | ], 28 | markdown: { 29 | extendMarkdown: (md) => { 30 | md.use(vuese) 31 | md.use(vuese, { 32 | vueseRe: /<\[vuese-h3\]\((.+)\)/i, 33 | ruleName: 'vuese-h3', 34 | useRender: (vueseRender) => { 35 | const renderRes = vueseRender.render() 36 | const genMd = key => `### ${key}\n${renderRes[key]}\n` 37 | 38 | return Object.keys(renderRes).map(genMd).join('') 39 | }, 40 | }) 41 | 42 | md.use(require('markdown-it-include'), { 43 | root: './docs/', 44 | includeRe: /<\[include\]\((.+)\)/i, 45 | }) 46 | }, 47 | }, 48 | evergreen: true, 49 | serviceWorker: true, 50 | themeConfig: { 51 | repo: 'BuptStEve/' + name, 52 | docsDir: 'docs', 53 | editLinks: true, 54 | sidebarDepth: 2, 55 | locales: { 56 | '/': { 57 | selectText: '🌍Languages', 58 | label: 'English', 59 | editLinkText: 'Edit this page on GitHub', 60 | serviceWorker: { 61 | updatePopup: { 62 | message: 'New content is available.', 63 | buttonText: 'Refresh', 64 | }, 65 | }, 66 | nav: [ 67 | { text: '🌱Guide', link: '/' }, 68 | { text: '😎Example', link: '/example/' }, 69 | { text: '🔥Ecosystem', items: ecosystemItems }, 70 | ], 71 | sidebar: { 72 | '/example/': [{ 73 | title: '😎Example', 74 | collapsable: false, 75 | children: exampleChildren, 76 | }], 77 | '/': [['', '🌱Guide']], 78 | }, 79 | }, 80 | '/zh/': { 81 | selectText: '🌍选择语言', 82 | label: '简体中文', 83 | editLinkText: '在 GitHub 上编辑此页', 84 | serviceWorker: { 85 | updatePopup: { 86 | message: '文档有更新。', 87 | buttonText: '刷新', 88 | }, 89 | }, 90 | nav: [ 91 | { text: '🌱指南', link: '/zh/' }, 92 | { text: '😎示例', link: '/zh/example/' }, 93 | { text: '🔥生态系统', items: ecosystemItems }, 94 | ], 95 | sidebar: { 96 | '/zh/example/': [{ 97 | title: '😎示例', 98 | collapsable: false, 99 | children: exampleChildren, 100 | }], 101 | '/zh/': [['', '🌱Guide']], 102 | }, 103 | }, 104 | }, 105 | }, 106 | } 107 | -------------------------------------------------------------------------------- /docs/.vuepress/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BuptStEve/markdown-it-vuese/4d61b8e6dc19317bbfa1e6682a244b79585b9bd3/docs/.vuepress/public/favicon.ico -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | <[include](../README.md) 2 | -------------------------------------------------------------------------------- /docs/example/README.md: -------------------------------------------------------------------------------- 1 | # Example 2 | 3 | ## Usage Example 4 | 5 | ```md 6 | <[vuese](@/test/MyComponent.vue) 7 | ``` 8 | 9 | ## Demo 10 | Because Vuese is generated by default from `

`. See [demo in the next section](./demo.md) 11 | 12 | ## Source Code 13 | 14 | <<< @/test/MyComponent.vue 15 | -------------------------------------------------------------------------------- /docs/example/custom.md: -------------------------------------------------------------------------------- 1 | # Custom Rendering 2 | 3 | Using Vuese's default rendering results directly in the document may not be suitable for all scenarios. 4 | 5 | ## Requirements 6 | 7 | No title, `Props` and other attributes should be changed from `

` to `

`. 8 | 9 | ## Config 10 | 11 | ```js 12 | const md = require('markdown-it')() 13 | .use(require('markdown-it-vuese'), { 14 | vueseRe: /<\[vuese-h3\]\((.+)\)/i, 15 | ruleName: 'vuese-h3', 16 | useRender: (vueseRender) => { 17 | const renderRes = vueseRender.render() 18 | const genMd = key => `### ${key}\n${renderRes[key]}\n` 19 | 20 | return Object.keys(renderRes).map(genMd).join('') 21 | }, 22 | }) 23 | ``` 24 | 25 | ## Markdown 26 | 27 | ```md 28 | <[vuese-h3](@/test/MyComponent.vue) 29 | ``` 30 | 31 | ::: tip 32 | Notice that we add a new vuese rule. 33 | ::: 34 | 35 | ## Result 36 | 37 | <[vuese-h3](@/test/MyComponent.vue) 38 | -------------------------------------------------------------------------------- /docs/example/demo.md: -------------------------------------------------------------------------------- 1 | <[vuese](@/test/MyComponent.vue) 2 | -------------------------------------------------------------------------------- /docs/example/vuepress.md: -------------------------------------------------------------------------------- 1 | # Using in Vuepress 2 | 3 | According to the different versions, there are two ways. 4 | 5 | ## 0.x 6 | 7 | ```js 8 | module.exports = { 9 | markdown: { 10 | config: (md) => { 11 | md.use(require('markdown-it-vuese'), { /* options */ }) 12 | } 13 | } 14 | } 15 | ``` 16 | 17 | For details [markdown.config](https://v0.vuepress.vuejs.org/config/#markdown-config) 18 | 19 | ## 1.x 20 | 21 | ```js 22 | module.exports = { 23 | markdown: { 24 | extendMarkdown: (md) => { 25 | md.use(require('markdown-it-vuese'), { /* options */ }) 26 | } 27 | } 28 | } 29 | ``` 30 | 31 | For details [markdown.extendMarkdown](https://vuepress.vuejs.org/config/#markdown-extendmarkdown) 32 | -------------------------------------------------------------------------------- /docs/zh/README.md: -------------------------------------------------------------------------------- 1 |

markdown-it-vuese

2 | 3 |

4 | 5 | Build Status 6 | 7 | 8 | Coverage Status 9 | 10 | 11 | dependencies 12 | 13 | 14 | Downloads per month 15 | Version 16 | License 17 | 18 |

19 | 20 | [English](../) | 简体中文 21 | 22 | > [Vuese][1] plugin for [markdown-it][2] markdown parser. 23 | 24 | 借助这个插件,你可以通过下述的语法在导入已经存在的 `*.vue` 文件的同时,使用 [Vuese][1] 自动生成文档。 25 | 26 | ```md 27 | <[vuese](@/filePath) 28 | ``` 29 | 30 | > 此处的 @ 默认值是 `process.cwd()` 31 | 32 | [实际效果请点击这里](./example/demo.md) 33 | 34 | ## Install 35 | 36 | ```bash 37 | $ npm i -S markdown-it-vuese 38 | # OR 39 | $ yarn add markdown-it-vuese 40 | ``` 41 | 42 | ## Usage 43 | 44 | ```js 45 | const md = require('markdown-it')() 46 | .use(require('markdown-it-vuese') [, options]) 47 | ``` 48 | 49 | ## Options 50 | 51 | ```js 52 | const md = require('markdown-it')() 53 | .use(require('markdown-it-vuese'), { 54 | root: 'some path', 55 | vueseRe: /your regexp/, 56 | useParser: parserRes => parserRes.name, 57 | useRender: (vueseRender) => { 58 | const renderRes = vueseRender.render() 59 | const markdownRes = vueseRender.renderMarkdown() 60 | 61 | return 'something' 62 | }, 63 | useAll: ({ ... }) => { 64 | return 'something' 65 | }, 66 | }) 67 | ``` 68 | 69 | ### root 70 | * 类型:`String` 71 | * 默认值:`process.cwd()` 72 | 73 | 根路径,路径中填写的 `@` 会被其替换。 74 | 75 | ### vueseRe 76 | * 类型:`RegExp` 77 | * 默认值:`/<\[vuese\]\((.+)\)/i` 78 | 79 | 匹配正则,不满意默认匹配规则可以自定义。 80 | 81 | ### ruleName 82 | * 类型:`String` 83 | * 默认值:`vuese` 84 | 85 | 注册的规则名,这个名称将被 [markdown-it][2] 使用,所以注意别和[已有规则][9]重复。 86 | 87 | 可以结合 vueseRe 改写规则名,实现在同一份文档中使用不同规则,渲染出不同的结果。 88 | 89 | ```js 90 | const md = require('markdown-it')() 91 | // 默认渲染结果 92 | .use(require('markdown-it-vuese')) 93 | // <[vuese-h3](filePath) 94 | // 自定义新规则,不需要标题,并将 Props 等属性从

改成

95 | .use(require('markdown-it-vuese'), { 96 | vueseRe: /<\[vuese-h3\]\((.+)\)/i, 97 | ruleName: 'vuese-h3', 98 | useRender: (vueseRender) => { 99 | const renderRes = vueseRender.render() 100 | const genMd = key => `### ${key}\n${renderRes[key]}\n` 101 | 102 | return Object.keys(renderRes).map(genMd).join('') 103 | }, 104 | }) 105 | ``` 106 | 107 | ### useParser 108 | * 类型:`Function` 109 | * 默认值:`null` 110 | 111 | 接受 [@vuese/parser 解析后的结果][7]。 112 | 113 | 若 `useParser` 存在,则直接运行后返回结果,否则尝试运行 `useRender`。 114 | 115 | ### useRender 116 | * 类型:`Function` 117 | * 默认值:`null` 118 | 119 | 接受 [@vuese/markdown-render 初始化后的渲染实例][8]。 120 | 121 | 若 `useRender` 存在,则直接运行后返回结果,否则尝试运行 `useAll`。 122 | 123 | 例如可以调用以下方法分别生成对象和 markdown 文档 124 | 125 | * `render`: 将生成 `renderRes` 126 | * `renderMarkdown`: 将生成 `markdownRes` 127 | 128 | ### useAll 129 | * 类型:`Function` 130 | * 默认值:`null` 131 | 132 | 以对象形式接受以下参数 `content`(源文件内容), `parserRes`, `renderRes`, `markdownRes`。若不存在则默认返回 `markdownRes.content`。 133 | 134 | ```js 135 | const md = require('markdown-it')() 136 | .use(require('markdown-it-vuese'), { 137 | useAll: ({ 138 | content, 139 | parserRes, 140 | renderRes, 141 | markdownRes, 142 | }) => { 143 | return 'something' 144 | }, 145 | }) 146 | ``` 147 | 148 | ### parserOptions 149 | * 类型:`Object` 150 | * 默认值:`{}` 151 | 152 | 透传 [@vuese/parser 的参数][5] 153 | 154 | ### renderOptions 155 | * 类型:`Object` 156 | * 默认值:`{}` 157 | 158 | 透传 [@vuese/markdown-render 的参数][6] 159 | 160 | ## License 161 | 162 | [MIT](http://opensource.org/licenses/MIT) 163 | 164 | Copyright (c) [StEve Young](https://github.com/BuptStEve) 165 | 166 | [1]: https://github.com/vuese/vuese 167 | [2]: https://github.com/markdown-it/markdown-it 168 | [3]: https://vuese.org/parser/ 169 | [4]: https://vuese.org/markdown-render/ 170 | [5]: https://vuese.org/zh/parser/#parseroptions 171 | [6]: https://vuese.org/zh/markdown-render/#renderoptions 172 | [7]: https://vuese.org/zh/parser/#parserresult 173 | [8]: https://vuese.org/zh/markdown-render/#render-%E7%B1%BB 174 | [9]: https://markdown-it.github.io/markdown-it/#Renderer.prototype.rules 175 | -------------------------------------------------------------------------------- /docs/zh/example/README.md: -------------------------------------------------------------------------------- 1 | # 示例 2 | 3 | ## 使用示例 4 | 5 | ```md 6 | <[vuese](@/test/MyComponent.vue) 7 | ``` 8 | 9 | ## 实现效果 10 | 由于 Vuese 默认从 `

` 开始生成,请看[下一节的 demo](./demo.md) 11 | 12 | ## 原始文件 13 | 14 | <<< @/test/MyComponent.vue 15 | -------------------------------------------------------------------------------- /docs/zh/example/custom.md: -------------------------------------------------------------------------------- 1 | # 自定义渲染 2 | 3 | 在文档中直接使用 Vuese 的默认渲染结果,可能无法适应全部的场景。 4 | 5 | ## 需求 6 | 7 | 不需要标题,并且想将 `Props` 等属性从 `

` 改成 `

` 8 | 9 | ## 配置 10 | 11 | ```js 12 | const md = require('markdown-it')() 13 | .use(require('markdown-it-vuese'), { 14 | vueseRe: /<\[vuese-h3\]\((.+)\)/i, 15 | ruleName: 'vuese-h3', 16 | useRender: (vueseRender) => { 17 | const renderRes = vueseRender.render() 18 | const genMd = key => `### ${key}\n${renderRes[key]}\n` 19 | 20 | return Object.keys(renderRes).map(genMd).join('') 21 | }, 22 | }) 23 | ``` 24 | 25 | ## 文档 26 | 27 | ```md 28 | <[vuese-h3](@/test/MyComponent.vue) 29 | ``` 30 | 31 | ::: tip 32 | 注意我们新增了一条 vuese 规则 33 | ::: 34 | 35 | ## 结果 36 | 37 | <[vuese-h3](@/test/MyComponent.vue) 38 | -------------------------------------------------------------------------------- /docs/zh/example/demo.md: -------------------------------------------------------------------------------- 1 | <[vuese](@/test/MyComponent.vue) 2 | -------------------------------------------------------------------------------- /docs/zh/example/vuepress.md: -------------------------------------------------------------------------------- 1 | # 在 Vuepress 中使用 2 | 3 | 根据版本的不同,有两种方式引入。 4 | 5 | ## 0.x 6 | 7 | ```js 8 | module.exports = { 9 | markdown: { 10 | config: (md) => { 11 | md.use(require('markdown-it-vuese'), { /* options */ }) 12 | } 13 | } 14 | } 15 | ``` 16 | 17 | 详情参阅 [markdown.config](https://v0.vuepress.vuejs.org/zh/config/#markdown-config) 18 | 19 | ## 1.x 20 | 21 | ```js 22 | module.exports = { 23 | markdown: { 24 | extendMarkdown: (md) => { 25 | md.use(require('markdown-it-vuese'), { /* options */ }) 26 | } 27 | } 28 | } 29 | ``` 30 | 31 | 详情参阅 [markdown.extendMarkdown](https://vuepress.vuejs.org/zh/config/#markdown-extendmarkdown) 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "markdown-it-vuese", 3 | "version": "0.4.0", 4 | "description": "📖 Vuese plugin for markdown-it markdown parser", 5 | "main": "dist/index.cjs.js", 6 | "files": [ 7 | "src/", 8 | "dist/" 9 | ], 10 | "scripts": { 11 | "cov": "open coverage/lcov-report/index.html", 12 | "docs": "vuepress dev docs", 13 | "docs:build": "vuepress build docs", 14 | "lint": "eslint --fix . docs/.vuepress/ --ignore-path .gitignore", 15 | "test": "cross-env NODE_ENV=test jest", 16 | "test:tdd": "cross-env NODE_ENV=test jest --watch", 17 | "prebuild": "rimraf dist/* & npm run test", 18 | "build": "cross-env NODE_ENV=production rollup -c", 19 | "next:pm": "npm --no-git-tag-version version preminor", 20 | "next:pr": "npm --no-git-tag-version version prerelease", 21 | "pub": "npm run build && npm publish", 22 | "pub:n": "npm run build && npm publish --tag next" 23 | }, 24 | "husky": { 25 | "hooks": { 26 | "pre-push": "npm test", 27 | "pre-commit": "lint-staged", 28 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" 29 | } 30 | }, 31 | "lint-staged": { 32 | "{src,test}/**/*.js": [ 33 | "eslint --fix", 34 | "git add" 35 | ] 36 | }, 37 | "jest": { 38 | "bail": true, 39 | "clearMocks": true, 40 | "transform": { 41 | "^.+\\.js$": "babel-jest" 42 | }, 43 | "collectCoverage": true, 44 | "collectCoverageFrom": [ 45 | "src/**" 46 | ] 47 | }, 48 | "dependencies": { 49 | "@vuese/markdown-render": "^2.1.0", 50 | "@vuese/parser": "^2.0.2" 51 | }, 52 | "devDependencies": { 53 | "@babel/core": "^7.3.4", 54 | "@babel/plugin-proposal-object-rest-spread": "^7.3.4", 55 | "@babel/preset-env": "^7.3.4", 56 | "@commitlint/cli": "^7.5.2", 57 | "@commitlint/config-conventional": "^7.5.0", 58 | "babel-core": "^7.0.0-bridge.0", 59 | "babel-eslint": "^10.0.1", 60 | "babel-jest": "^24.1.0", 61 | "codecov": "^3.2.0", 62 | "cross-env": "^5.2.0", 63 | "eslint": "^5.14.1", 64 | "eslint-config-standard": "^12.0.0", 65 | "eslint-plugin-import": "^2.16.0", 66 | "eslint-plugin-node": "^8.0.1", 67 | "eslint-plugin-promise": "^4.0.1", 68 | "eslint-plugin-standard": "^4.0.0", 69 | "fs-extra": "^7.0.1", 70 | "gh-pages": "^2.0.1", 71 | "husky": "^1.3.1", 72 | "jest": "^24.1.0", 73 | "lint-staged": "^8.1.4", 74 | "markdown-it": "^8.4.2", 75 | "markdown-it-custom-block": "^0.1.1", 76 | "markdown-it-include": "^1.1.0", 77 | "rimraf": "^2.6.3", 78 | "rollup": "^1.3.1", 79 | "rollup-plugin-babel": "^4.3.2", 80 | "rollup-plugin-commonjs": "^9.2.1", 81 | "rollup-plugin-eslint": "^5.0.0", 82 | "rollup-plugin-json": "^3.1.0", 83 | "rollup-plugin-node-resolve": "^4.0.1", 84 | "rollup-plugin-replace": "^2.1.0", 85 | "rollup-plugin-uglify": "^6.0.2", 86 | "vuepress": "^1.0.0-alpha.40" 87 | }, 88 | "peerDependencies": { 89 | "markdown-it": "^8.4.2" 90 | }, 91 | "keywords": [ 92 | "markdown-it-plugin", 93 | "markdown-it", 94 | "markdown", 95 | "vuepress", 96 | "vuese" 97 | ], 98 | "repository": { 99 | "type": "git", 100 | "url": "git+https://github.com/BuptStEve/markdown-it-vuese.git" 101 | }, 102 | "homepage": "https://buptsteve.github.io/markdown-it-vuese/", 103 | "author": "StEve Young", 104 | "license": "MIT" 105 | } 106 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel' 2 | import { eslint } from 'rollup-plugin-eslint' 3 | 4 | import pkg from './package.json' 5 | 6 | export default { 7 | input: 'src/index.js', 8 | output: [{ 9 | file: pkg.main, 10 | format: 'cjs', 11 | }], 12 | plugins: [ 13 | eslint(), 14 | babel(), 15 | ], 16 | external: [ 17 | 'fs', 18 | 'path', 19 | '@vuese/parser', 20 | '@vuese/markdown-render', 21 | ], 22 | } 23 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | const fs = require('fs') 4 | const path = require('path') 5 | const { parser: vueseParser } = require('@vuese/parser') 6 | const { Render: VueseRender } = require('@vuese/markdown-render') 7 | 8 | const isFn = fn => typeof fn === 'function' 9 | 10 | module.exports = (md, options = {}) => { 11 | const VUESE_RE = /<\[vuese\]\((.+)\)/i 12 | const { 13 | root = process.cwd(), 14 | vueseRe = VUESE_RE, 15 | ruleName = 'vuese', 16 | useAll = null, 17 | useParser = null, 18 | useRender = null, 19 | parserOptions = {}, 20 | renderOptions = {}, 21 | } = options 22 | 23 | md.block.ruler.before('fence', ruleName, getPathToken) 24 | md.renderer.rules[ruleName] = (tokens, idx, _, env) => { 25 | const { rawPath } = tokens[idx] 26 | const filePath = getFilePath(rawPath) 27 | const rawMd = getMdFromSfc(filePath) 28 | 29 | /* istanbul ignore next */ 30 | if (env.loader) { 31 | // for @vuepress/markdown-loader 32 | env.loader.addDependency(filePath) 33 | } 34 | 35 | // save attributes, like hoistedTags 36 | const tmpMd = Object.assign({}, md) 37 | const res = md.render(rawMd, env) 38 | 39 | // restore attributes 40 | Object.assign(md, tmpMd) 41 | 42 | return res.html || res 43 | } 44 | 45 | function getFilePath (rawPath) { 46 | const tmpPath = rawPath 47 | .replace(/^['|"]/, '') 48 | .replace(/['|"]$/, '') 49 | .replace(/^@/, root) 50 | 51 | return path.resolve(root, tmpPath) 52 | } 53 | 54 | function getPathToken (state, startLine) { 55 | const pos = state.bMarks[startLine] + state.tShift[startLine] 56 | const max = state.eMarks[startLine] 57 | const match = vueseRe.exec(state.src.slice(pos, max)) 58 | 59 | if (!match || match.length < 2) return false 60 | 61 | const rawPath = match[1].trim() 62 | const token = state.push(ruleName, 'div', 0) 63 | 64 | token.rawPath = rawPath 65 | state.line = startLine + 1 66 | 67 | return true 68 | } 69 | 70 | function getMdFromSfc (filePath) { 71 | if (!fs.existsSync(filePath)) return `Not found: ${filePath}` 72 | 73 | try { 74 | const content = fs.readFileSync(filePath, 'utf-8') 75 | const parserRes = vueseParser(content, parserOptions) 76 | 77 | if (isFn(useParser)) return useParser(parserRes) 78 | 79 | const vueseRender = new VueseRender(parserRes, renderOptions) 80 | 81 | if (isFn(useRender)) return useRender(vueseRender) 82 | 83 | const renderRes = vueseRender.render() 84 | const markdownRes = vueseRender.renderMarkdown() 85 | 86 | return isFn(useAll) 87 | ? useAll({ content, parserRes, renderRes, markdownRes }) 88 | : markdownRes.content 89 | } catch (e) { 90 | return e.message 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /test/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { jest: true } 3 | } 4 | -------------------------------------------------------------------------------- /test/Error.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 23 | -------------------------------------------------------------------------------- /test/MyComponent.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 34 | -------------------------------------------------------------------------------- /test/__snapshots__/index.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`markdown-it-vuese should render by useRender 1`] = ` 4 | "

props

5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
NameDescriptionTypeRequiredDefault
nameThe name of the form, up to 8 charactersString / Numbertrue-
25 |

slots

26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
NameDescriptionDefault Slot Content
headerForm header<th>title</th>
42 |

events

43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 |
Event NameDescriptionParameters
onclearFire when the form is clearedThe argument is a boolean value representing xxx
59 |

methods

60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |
MethodDescriptionParameters
clearUsed to manually clear the form-
" 76 | `; 77 | 78 | exports[`markdown-it-vuese should render full documentation 1`] = ` 79 | "

abc

80 |

MyComponent

81 |

This is a description of the component

82 |

Props

83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 |
NameDescriptionTypeRequiredDefault
nameThe name of the form, up to 8 charactersString / Numbertrue-
104 | 105 |

Events

106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 |
Event NameDescriptionParameters
onclearFire when the form is clearedThe argument is a boolean value representing xxx
123 | 124 |

Slots

125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 |
NameDescriptionDefault Slot Content
headerForm header<th>title</th>
142 | 143 |

Methods

144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 |
MethodDescriptionParameters
clearUsed to manually clear the form-
161 | 162 |

efg

" 163 | `; 164 | -------------------------------------------------------------------------------- /test/fragments/at-path.md: -------------------------------------------------------------------------------- 1 | abc 2 | 3 | <[Vuese](@/test/MyComponent.vue) 4 | 5 | efg 6 | -------------------------------------------------------------------------------- /test/fragments/code-block.md: -------------------------------------------------------------------------------- 1 | <[vuese](@/test/MyComponent.vue) 2 | -------------------------------------------------------------------------------- /test/fragments/custom-re.md: -------------------------------------------------------------------------------- 1 | +++my-rule('@/test/MyComponent.vue') 2 | -------------------------------------------------------------------------------- /test/fragments/custom-root.md: -------------------------------------------------------------------------------- 1 | <[vuese](@/MyComponent.vue) 2 | 3 | <[vuese](@/MyComponent.vue) 4 | -------------------------------------------------------------------------------- /test/fragments/error.md: -------------------------------------------------------------------------------- 1 | <[vuese](@/test/Error.vue) 2 | -------------------------------------------------------------------------------- /test/fragments/multiple-times.md: -------------------------------------------------------------------------------- 1 | <[vuese](@/test/MyComponent.vue) 2 | 3 | <[vuese](@/test/MyComponent.vue) 4 | -------------------------------------------------------------------------------- /test/fragments/not-found.md: -------------------------------------------------------------------------------- 1 | <[vuese](not-found.vue) 2 | -------------------------------------------------------------------------------- /test/fragments/not-match.md: -------------------------------------------------------------------------------- 1 | ```md 2 | <[vuese](not-match.vue) 3 | ``` 4 | -------------------------------------------------------------------------------- /test/fragments/relative-path.md: -------------------------------------------------------------------------------- 1 | <[vuese](./test/MyComponent.vue) 2 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs-extra' 2 | import Md from 'markdown-it' 3 | import path from 'path' 4 | import vuese from '../src/' 5 | 6 | describe('markdown-it-vuese', () => { 7 | const md = Md({ html: true }).use(vuese) 8 | 9 | describe('should', () => { 10 | it('render full documentation', async () => { 11 | const output = await renderOutput('at-path', md) 12 | 13 | expect(output).toMatchSnapshot() 14 | }) 15 | 16 | it('render by custom root', async () => { 17 | const md = Md().use(vuese, { 18 | root: process.cwd() + '/test', 19 | useParser: parserRes => parserRes.name, 20 | }) 21 | const output = await renderOutput('custom-root', md) 22 | 23 | expect(output).toBe(`

MyComponent

\n

MyComponent

`) 24 | }) 25 | 26 | it('render by useParser', async () => { 27 | const md = Md().use(vuese, { 28 | useParser: parserRes => parserRes.name, 29 | }) 30 | const output = await renderOutput('relative-path', md) 31 | 32 | expect(output).toBe(`

MyComponent

`) 33 | }) 34 | 35 | it('render by useRender', async () => { 36 | const md = Md().use(vuese, { 37 | useRender: (vueseRender) => { 38 | let content = '' 39 | const renderRes = vueseRender.render() 40 | 41 | Object.keys(renderRes).forEach((key) => { 42 | content += `### ${key}\n\n${renderRes[key]}\n` 43 | }) 44 | 45 | return content 46 | }, 47 | }) 48 | const output = await renderOutput('relative-path', md) 49 | 50 | expect(output).toMatchSnapshot() 51 | }) 52 | 53 | it('render by useAll', async () => { 54 | const md = Md().use(vuese, { 55 | useAll: ({ markdownRes }) => markdownRes.componentName, 56 | }) 57 | const output = await renderOutput('relative-path', md) 58 | 59 | expect(output).toBe(`

MyComponent

`) 60 | }) 61 | 62 | it('match by custom vueseRe', async () => { 63 | const md = Md().use(vuese, { 64 | vueseRe: /\+{3}my-rule\((.+)\)/im, 65 | useAll: ({ markdownRes }) => markdownRes.componentName, 66 | }) 67 | const output = await renderOutput('custom-re', md) 68 | 69 | expect(output).toBe(`

MyComponent

`) 70 | }) 71 | 72 | it('render parse error', async () => { 73 | const output = await renderOutput('error', md) 74 | 75 | expect(output).toBe(`

Unexpected token, expected "," (12:0)

`) 76 | }) 77 | 78 | it('render multiple times', async () => { 79 | const md = Md().use(vuese, { 80 | useAll: ({ markdownRes }) => markdownRes.componentName, 81 | }) 82 | const output = await renderOutput('multiple-times', md) 83 | 84 | expect(output).toBe(`

MyComponent

\n

MyComponent

`) 85 | }) 86 | }) 87 | 88 | describe('should not', () => { 89 | it('match fence', async () => { 90 | const output = await renderOutput('not-match', md) 91 | 92 | expect(output).toBe(`
<[vuese](not-match.vue)\n
`) 93 | }) 94 | 95 | it('match code block', async () => { 96 | const output = await renderOutput('code-block', md) 97 | 98 | expect(output).toBe(`
<[vuese](@/test/MyComponent.vue)\n
`) 99 | }) 100 | 101 | it('found', async () => { 102 | const output = await renderOutput('not-found', md) 103 | 104 | expect(output).toBe(`

Not found: ${process.cwd()}/not-found.vue

`) 105 | }) 106 | }) 107 | 108 | // helpers 109 | 110 | async function renderOutput (name, md) { 111 | const input = await readFile(name) 112 | return md.render(input).trim() 113 | } 114 | 115 | async function readFile (name) { 116 | const target = path.resolve(__dirname, `./fragments/${name}.md`) 117 | return fs.readFile(target, 'utf-8') 118 | } 119 | }) 120 | --------------------------------------------------------------------------------