├── .editorconfig ├── .eslintignore ├── .eslintrc.cjs ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── __test__ └── index.spec.js ├── babel.config.js ├── docs ├── .vitepress │ ├── config.js │ ├── jsdoc2md.config.json │ └── jsdoc2vitepress.config.json └── index.md ├── jest.config.mjs ├── lib ├── index.js ├── index.js.map ├── init-docs.js ├── init-docs.js.map ├── jsdoc-to-md.js ├── jsdoc-to-md.js.map ├── md-to-vitepress.js └── md-to-vitepress.js.map ├── package-lock.json ├── package.json ├── src ├── index.ts ├── init-docs.ts ├── jsdoc-to-md.ts └── md-to-vitepress.ts ├── tsconfig.json └── types ├── config.d.ts ├── index.d.ts ├── jsdoc2md.d.ts ├── md2vitepress.d.ts └── src ├── index.d.ts ├── jsdoc2md.d.ts └── md2vitepress.d.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [{package.json,.*rc,*.yml,*.md,*.js,*.ts}] 12 | indent_style = space 13 | indent_size = 2 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/* 2 | node_modules 3 | test/* 4 | coverage/* 5 | lib/* 6 | docs/dist/* -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | plugins: [ 5 | '@typescript-eslint', 6 | ], 7 | extends: [ 8 | 'eslint-config-tencent', 9 | 'plugin:@typescript-eslint/eslint-recommended', 10 | 'plugin:@typescript-eslint/recommended', 11 | ], 12 | env: { 13 | node: true, 14 | jest: true, 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /build 5 | /coverage 6 | 7 | # local env files 8 | .env.local 9 | .env.*.local 10 | 11 | # Log files 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw* 24 | 25 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 1.0.0 (2022-11-25) 2 | 3 | ## Features 4 | 5 | Generates vitepress API documentation from jsdoc annotated source code. 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Luciozhang 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 | [![NPM version](https://img.shields.io/npm/v/jsdoc2vitepress.svg)](https://www.npmjs.com/package/jsdoc2vitepress) [![NPM downloads](https://img.shields.io/npm/dm/jsdoc2vitepress.svg)](https://www.npmjs.com/package/jsdoc2vitepress) [![NPM License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/luciozhang/jsdoc2vitepress/blob/master/LICENSE) 2 | 3 | Generates vitepress API documentation from [jsdoc](https://jsdoc.app/) annotated source code. 4 | 5 | What you need is to **write comments that conform to the jsdoc specification**, and `jsdoc2vitepress` will help you **generate API documentation by VitePress**. 6 | 7 | # Install 8 | 9 | ```shell 10 | npm install -D jsdoc2vitepress 11 | ``` 12 | 13 | # Usage 14 | 15 | ## Init docs directory 16 | 17 | ```shell 18 | jsdoc2vitepress init 19 | ``` 20 | 21 | ##### What will happen? 22 | 23 | In local Directory 24 | 25 | ![md目录](https://blog-1256819047.cos.ap-guangzhou.myqcloud.com/img/md-dir.png) 26 | 27 | ## Start VitePress 28 | 29 | Generates vitepress API documentation from jsdoc annotated source code and run Vitepress 30 | 31 | ```shell 32 | jsdoc2vitepress start 33 | ``` 34 | 35 | ##### What will happen? 36 | 37 | In console 38 | 39 | ![init&start](https://blog-1256819047.cos.ap-guangzhou.myqcloud.com/img/%E4%BC%81%E4%B8%9A%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_272765e2-b4c7-4a59-b7a8-8d4b9ec67a0e.png) 40 | 41 | In local Directory 42 | 43 | ![md目录](https://blog-1256819047.cos.ap-guangzhou.myqcloud.com/img/md-dir.png) 44 | 45 | In Once of the Markdown 46 | 47 | ![MD内容](https://blog-1256819047.cos.ap-guangzhou.myqcloud.com/img/%E4%BC%81%E4%B8%9A%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_7cfb6714-8217-4073-98b2-8003f9e6056b.png) 48 | 49 | ## Build VitePress 50 | 51 | Generates vitepress API documentation from jsdoc annotated source code and build Vitepress 52 | 53 | ```shell 54 | jsdoc2vitepress build 55 | ``` 56 | 57 | ##### What will happen? 58 | 59 | In console 60 | 61 | ![构建网站](https://blog-1256819047.cos.ap-guangzhou.myqcloud.com/img/%E4%BC%81%E4%B8%9A%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_8c94d14a-b220-44be-9d6a-8729a807dceb.png) 62 | 63 | In local Directory 64 | 65 | ![vitepress-dist](https://blog-1256819047.cos.ap-guangzhou.myqcloud.com/img/%E4%BC%81%E4%B8%9A%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_069d259b-15da-43f5-b10c-08f65bd53feb.png) 66 | 67 | Website 68 | 69 | ![文档网站](https://blog-1256819047.cos.ap-guangzhou.myqcloud.com/img/%E4%BC%81%E4%B8%9A%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_4812bc13-36b3-4b7d-b665-980bdcde46fc.png) 70 | 71 | # How it work 72 | 73 | JS/TS annotated source code -> Markdown ->VitePress website 74 | 75 | ![总体流程](https://blog-1256819047.cos.ap-guangzhou.myqcloud.com/img/%E4%BC%81%E4%B8%9A%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_512aa61a-aab5-48bc-8676-f01bf9430605.png) 76 | 77 | See More detail in [注释生成文档太难看?试试用注释生成vitepress文档](https://juejin.cn/post/7169855361196195853) 78 | 79 | 80 | # License 81 | MIT 82 | 83 | Copyright (c) 2022-present, luciozhang -------------------------------------------------------------------------------- /__test__/index.spec.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luciozhang/jsdoc2vitepress/48275ec9a9687db9f261de80e0fcd151e76e81b9/__test__/index.spec.js -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { presets: ['@babel/preset-env'] }; 2 | -------------------------------------------------------------------------------- /docs/.vitepress/config.js: -------------------------------------------------------------------------------- 1 | import { getSideBar } from 'vitepress-plugin-autobar'; 2 | 3 | module.exports = { 4 | title: 'xxx', // 设置网站标题 5 | description: 'xxx xxx', 6 | base: '/', // 设置站点根路径 7 | outDir: './dist', // 设置输出目录 8 | repo: '', // 添加 git 链接 9 | markdown: { 10 | toc: { includeLevel: [2, 3] }, 11 | }, 12 | themeConfig: { 13 | // 添加导航栏 14 | nav: [ 15 | { 16 | text: 'xxx', 17 | link: '', 18 | target:'_self', 19 | }, 20 | ], 21 | sidebar: getSideBar('./docs', { 22 | ignoreMDFiles: ['index'], 23 | }), 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /docs/.vitepress/jsdoc2md.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "source": { 3 | "includePattern": ".+\\.ts(__docs_-|x)?$", 4 | "excludePattern": ".+\\.(test|spec).ts" 5 | }, 6 | "plugins": [ 7 | "plugins/markdown", 8 | "node_modules/jsdoc-babel" 9 | ], 10 | "babel": { 11 | "extensions": [ 12 | "ts", 13 | "tsx" 14 | ], 15 | "ignore": [ 16 | "**/*.(test|spec).ts" 17 | ], 18 | "babelrc": false, 19 | "presets": [ 20 | [ 21 | "@babel/preset-env", 22 | { 23 | "targets": { 24 | "node": true 25 | } 26 | } 27 | ], 28 | "@babel/preset-typescript" 29 | ], 30 | "plugins": [ 31 | "@babel/proposal-class-properties", 32 | "@babel/plugin-proposal-object-rest-spread" 33 | ] 34 | } 35 | } -------------------------------------------------------------------------------- /docs/.vitepress/jsdoc2vitepress.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "markdownDirs": [ 3 | { 4 | "root": "./src", 5 | "output": "./docs/02.工具库", 6 | "ingoreList": [] 7 | } 8 | ] 9 | } -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | 4 | hero: 5 | name: xxx 6 | text: xxx xxx 7 | tagline: xx xx xx 8 | actions: 9 | - theme: brand 10 | text: Get Started 11 | link: /01.概述/快速开始 12 | - theme: alt 13 | text: View on Git 14 | link: 15 | --- -------------------------------------------------------------------------------- /jest.config.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * For a detailed explanation regarding each configuration property, visit: 3 | * https://jestjs.io/docs/configuration 4 | */ 5 | 6 | export default { 7 | clearMocks: true, 8 | collectCoverage: true, 9 | coverageDirectory: 'coverage', 10 | transformIgnorePatterns: [ 11 | '/node_modules/(?!lodash-es)', 12 | ], 13 | moduleNameMapper: { 14 | '^lodash-es$': 'lodash', 15 | }, 16 | transform: { 17 | '^.+\\.(js|jsx)$': 'babel-jest', 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | "use strict"; 3 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 4 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 5 | return new (P || (P = Promise))(function (resolve, reject) { 6 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 7 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 8 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 9 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 10 | }); 11 | }; 12 | Object.defineProperty(exports, "__esModule", { value: true }); 13 | const commander_1 = require("commander"); 14 | const init_docs_1 = require("./init-docs"); 15 | const jsdoc_to_md_1 = require("./jsdoc-to-md"); 16 | const md_to_vitepress_1 = require("./md-to-vitepress"); 17 | const program = new commander_1.Command(); 18 | program 19 | .name('jsdoc2vitepress') 20 | .description('Generates vitepress API documentation from jsdoc annotated source code.') 21 | .version('1.0.0'); 22 | program 23 | .command('init') 24 | .description('init vitepress directory.') 25 | .action(() => __awaiter(void 0, void 0, void 0, function* () { 26 | yield (0, init_docs_1.initDocs)(); 27 | })); 28 | program 29 | .command('start') 30 | .description('Generates vitepress API documentation from jsdoc annotated source code and run Vitepress') 31 | .action(() => __awaiter(void 0, void 0, void 0, function* () { 32 | yield (0, jsdoc_to_md_1.jsdocToMd)(); 33 | yield new Promise(resolve => setTimeout(resolve, 5000)); 34 | yield (0, md_to_vitepress_1.startVitePress)(); 35 | })); 36 | program 37 | .command('build') 38 | .description('Generates vitepress API documentation from jsdoc annotated source code and build Vitepress') 39 | .action(() => __awaiter(void 0, void 0, void 0, function* () { 40 | yield (0, jsdoc_to_md_1.jsdocToMd)(); 41 | yield new Promise(resolve => setTimeout(resolve, 5000)); 42 | yield (0, md_to_vitepress_1.buildVitePress)(); 43 | })); 44 | program.parse(); 45 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /lib/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;AAEA,yCAAoC;AACpC,2CAAuC;AACvC,+CAA0C;AAC1C,uDAAmE;AAEnE,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,iBAAiB,CAAC;KACvB,WAAW,CAAC,yEAAyE,CAAC;KACtF,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,2BAA2B,CAAC;KACxC,MAAM,CAAC,GAAS,EAAE;IACjB,MAAM,IAAA,oBAAQ,GAAE,CAAC;AACnB,CAAC,CAAA,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,0FAA0F,CAAC;KACvG,MAAM,CAAC,GAAS,EAAE;IACjB,MAAM,IAAA,uBAAS,GAAE,CAAC;IAClB,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;IACxD,MAAM,IAAA,gCAAc,GAAE,CAAC;AACzB,CAAC,CAAA,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,4FAA4F,CAAC;KACzG,MAAM,CAAC,GAAS,EAAE;IACjB,MAAM,IAAA,uBAAS,GAAE,CAAC;IAClB,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;IACxD,MAAM,IAAA,gCAAc,GAAE,CAAC;AACzB,CAAC,CAAA,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"} -------------------------------------------------------------------------------- /lib/init-docs.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | var __importDefault = (this && this.__importDefault) || function (mod) { 12 | return (mod && mod.__esModule) ? mod : { "default": mod }; 13 | }; 14 | Object.defineProperty(exports, "__esModule", { value: true }); 15 | exports.initDocs = void 0; 16 | const ora_1 = __importDefault(require("ora")); 17 | const fs_extra_1 = __importDefault(require("fs-extra")); 18 | const promise_1 = __importDefault(require("git-clone/promise")); 19 | const path_1 = __importDefault(require("path")); 20 | /** 21 | * @module init-docs 22 | * @description init docs directory 23 | */ 24 | /** 25 | * @exports initDocs "jsdoc2vitepress init" init docs directory 26 | * @returns {Promise} Return promise to check if init success 27 | */ 28 | const initDocs = () => __awaiter(void 0, void 0, void 0, function* () { 29 | const loading = (0, ora_1.default)('Init docs directory'); 30 | try { 31 | const templateGitUrl = 'https://github.com/luciozhang/jsdoc2vitepress-template.git'; 32 | const docsDir = path_1.default.resolve(process.cwd(), 'docs'); 33 | yield (0, promise_1.default)(templateGitUrl, docsDir, { checkout: 'master', shallow: true }); 34 | fs_extra_1.default.removeSync(path_1.default.join(docsDir, '.git')); 35 | loading.succeed('Init docs directory success'); 36 | } 37 | catch (error) { 38 | loading.fail(`Init docs directory fail: ${error}\nPlease delete local 'docs' directory and retry.`); 39 | } 40 | }); 41 | exports.initDocs = initDocs; 42 | //# sourceMappingURL=init-docs.js.map -------------------------------------------------------------------------------- /lib/init-docs.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"init-docs.js","sourceRoot":"","sources":["../src/init-docs.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,8CAAsB;AACtB,wDAA0B;AAC1B,gEAAyC;AACzC,gDAAwB;AAExB;;;GAGG;AAEH;;;GAGG;AACI,MAAM,QAAQ,GAAG,GAAS,EAAE;IACjC,MAAM,OAAO,GAAG,IAAA,aAAG,EAAC,qBAAqB,CAAC,CAAC;IAC3C,IAAI;QACF,MAAM,cAAc,GAAG,4DAA4D,CAAC;QACpF,MAAM,OAAO,GAAG,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;QACpD,MAAM,IAAA,iBAAQ,EAAC,cAAc,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/E,kBAAE,CAAC,UAAU,CAAC,cAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QAC1C,OAAO,CAAC,OAAO,CAAC,6BAA6B,CAAC,CAAC;KAChD;IAAC,OAAO,KAAK,EAAE;QACd,OAAO,CAAC,IAAI,CAAC,6BAA6B,KAAK,mDAAmD,CAAC,CAAC;KACrG;AACH,CAAC,CAAA,CAAC;AAXW,QAAA,QAAQ,YAWnB"} -------------------------------------------------------------------------------- /lib/jsdoc-to-md.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | var __importDefault = (this && this.__importDefault) || function (mod) { 12 | return (mod && mod.__esModule) ? mod : { "default": mod }; 13 | }; 14 | Object.defineProperty(exports, "__esModule", { value: true }); 15 | exports.jsdocToMd = void 0; 16 | const fs_extra_1 = __importDefault(require("fs-extra")); 17 | const path_1 = __importDefault(require("path")); 18 | const jsdoc_to_markdown_1 = __importDefault(require("jsdoc-to-markdown")); 19 | const ora_1 = __importDefault(require("ora")); 20 | const configJ2VPath = path_1.default.resolve(process.cwd(), 'docs', '.vitepress', 'jsdoc2vitepress.config.json'); 21 | const configJ2MPath = path_1.default.resolve(process.cwd(), 'docs', '.vitepress', 'jsdoc2md.config.json'); 22 | /** 23 | * @module jsdoc-to-md 24 | * @description Generates Markdown API documentation from jsdoc annotated source code. 25 | */ 26 | /** 27 | * @exports jsdocToMd Generates Markdown 28 | * @returns {Promise} Return promise to check if generate success 29 | */ 30 | const jsdocToMd = () => __awaiter(void 0, void 0, void 0, function* () { 31 | const loading = (0, ora_1.default)('Generates Markdown'); 32 | try { 33 | const { markdownDirs } = yield fs_extra_1.default.readJSON(configJ2VPath); 34 | yield Promise.all(markdownDirs.map((sourceObject) => __awaiter(void 0, void 0, void 0, function* () { 35 | const { root, output, ingoreList } = sourceObject; 36 | yield makeMarkDownForFiles(root, output, ingoreList); 37 | }))); 38 | loading.succeed('Generates Markdown success'); 39 | } 40 | catch (error) { 41 | loading.fail(`Generates Markdown fail: ${error}`); 42 | } 43 | }); 44 | exports.jsdocToMd = jsdocToMd; 45 | const makeMarkDownForFiles = (root, output, ingoreList) => __awaiter(void 0, void 0, void 0, function* () { 46 | const fileList = yield fs_extra_1.default.readdir(root); 47 | yield Promise.all(fileList.map((fileName) => __awaiter(void 0, void 0, void 0, function* () { 48 | if (ingoreList.indexOf(fileName) === -1) { 49 | yield makeMarkDownDoc(fileName, root, output); 50 | } 51 | }))); 52 | }); 53 | const makeMarkDownDoc = (sourceName, sourceRootPath, outputPath) => __awaiter(void 0, void 0, void 0, function* () { 54 | let sourcePath = `${sourceRootPath}/${sourceName}`; 55 | const outputName = sourceName.replace('.js', '').replace('.ts', ''); 56 | const loading = (0, ora_1.default)(`Generates Markdown for ${sourcePath}`); 57 | try { 58 | // 处理js文件的路径,需要区分是文件或目录,目录会将目录下所有文件生成为一个md 59 | const stat = fs_extra_1.default.lstatSync(sourcePath); 60 | if (stat.isDirectory()) { 61 | sourcePath = `${sourcePath}/*`; 62 | } 63 | const mdStr = yield jsdoc_to_markdown_1.default.render({ 64 | 'example-lang': 'javascript', 65 | files: path_1.default.resolve(process.cwd(), sourcePath), 66 | 'name-format': 'backticks', 67 | 'heading-depth': 2, 68 | 'module-index-format': 'none', 69 | configure: path_1.default.resolve(process.cwd(), configJ2MPath), 70 | }); 71 | if (mdStr) { 72 | fs_extra_1.default.outputFile(path_1.default.resolve(process.cwd(), `${outputPath}/${outputName}.md`), mdStr); 73 | loading.succeed('Generates Markdown success in ' + `${outputPath}/${outputName}.md`); 74 | } 75 | } 76 | catch (error) { 77 | loading.fail(`Generates Markdown fail for ${sourcePath}: ${error}`); 78 | } 79 | }); 80 | //# sourceMappingURL=jsdoc-to-md.js.map -------------------------------------------------------------------------------- /lib/jsdoc-to-md.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"jsdoc-to-md.js","sourceRoot":"","sources":["../src/jsdoc-to-md.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /lib/md-to-vitepress.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | var __importDefault = (this && this.__importDefault) || function (mod) { 12 | return (mod && mod.__esModule) ? mod : { "default": mod }; 13 | }; 14 | Object.defineProperty(exports, "__esModule", { value: true }); 15 | exports.buildVitePress = exports.startVitePress = void 0; 16 | const shelljs_1 = __importDefault(require("shelljs")); 17 | /** 18 | * @module md-to-vitepress 19 | * @description Generates VitePress API documentation from jsdoc annotated source code. 20 | */ 21 | /** 22 | * @exports startVitePress Run VitePress server 23 | * @returns {Promise} Return promise to check if run success 24 | */ 25 | const startVitePress = () => __awaiter(void 0, void 0, void 0, function* () { 26 | shelljs_1.default.exec('node_modules/.bin//vitepress dev docs'); 27 | }); 28 | exports.startVitePress = startVitePress; 29 | /** 30 | * @exports buildVitePress build VitePress server 31 | * @returns {Promise} Return promise to check if build success 32 | */ 33 | const buildVitePress = () => __awaiter(void 0, void 0, void 0, function* () { 34 | shelljs_1.default.exec('node_modules/.bin/vitepress build docs'); 35 | }); 36 | exports.buildVitePress = buildVitePress; 37 | //# sourceMappingURL=md-to-vitepress.js.map -------------------------------------------------------------------------------- /lib/md-to-vitepress.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"md-to-vitepress.js","sourceRoot":"","sources":["../src/md-to-vitepress.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,sDAA4B;AAC5B;;;GAGG;AAEH;;;GAGG;AACI,MAAM,cAAc,GAAG,GAAS,EAAE;IACvC,iBAAK,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;AACtD,CAAC,CAAA,CAAC;AAFW,QAAA,cAAc,kBAEzB;AAEF;;;GAGG;AACI,MAAM,cAAc,GAAG,GAAS,EAAE;IACvC,iBAAK,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;AACvD,CAAC,CAAA,CAAC;AAFW,QAAA,cAAc,kBAEzB"} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jsdoc2vitepress", 3 | "version": "1.0.4", 4 | "description": "Generates vitepress API documentation from jsdoc annotated source code.", 5 | "repository": "https://github.com/luciozhang/jsdoc2vitepress", 6 | "main": "lib/index.js", 7 | "bin": { 8 | "jsdoc2vitepress": "lib/index.js" 9 | }, 10 | "scripts": { 11 | "lint": "eslint --ext .ts,.js .", 12 | "lint:fix": "eslint --fix --ext .ts,.js .", 13 | "build": "tsc", 14 | "test": "jest" 15 | }, 16 | "keywords": [ 17 | "jsdoc", 18 | "vitepress", 19 | "api", 20 | "doc", 21 | "annotated", 22 | "markdowm", 23 | "注释生成文档" 24 | ], 25 | "author": "luciozhang", 26 | "license": "MIT", 27 | "devDependencies": { 28 | "@types/fs-extra": "^9.0.13", 29 | "@types/git-clone": "^0.2.0", 30 | "@types/jsdoc-to-markdown": "^7.0.3", 31 | "@types/node": "^18.11.9", 32 | "@types/shelljs": "^0.8.11", 33 | "@typescript-eslint/eslint-plugin": "^5.10.0", 34 | "@typescript-eslint/parser": "^5.10.0", 35 | "babel-jest": "^29.3.1", 36 | "eslint-config-tencent": "^1.0.4", 37 | "jest": "^29.3.1", 38 | "jsdoc-babel": "^0.5.0" 39 | }, 40 | "dependencies": { 41 | "@babel/plugin-proposal-class-properties": "^7.18.6", 42 | "@babel/plugin-proposal-object-rest-spread": "^7.20.2", 43 | "@babel/preset-env": "^7.20.2", 44 | "@babel/preset-typescript": "^7.18.6", 45 | "@vue/babel-preset-app": "^5.0.8", 46 | "commander": "^9.4.1", 47 | "fs-extra": "^10.1.0", 48 | "git-clone": "^0.2.0", 49 | "jsdoc-to-markdown": "^7.1.1", 50 | "ora": "^5.4.1", 51 | "shelljs": "^0.8.5", 52 | "vitepress": "^1.0.0-draft.8", 53 | "vitepress-plugin-autobar": "^1.0.7" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { Command } from 'commander'; 4 | import { initDocs } from './init-docs'; 5 | import { jsdocToMd } from './jsdoc-to-md'; 6 | import { startVitePress, buildVitePress } from './md-to-vitepress'; 7 | 8 | const program = new Command(); 9 | 10 | program 11 | .name('jsdoc2vitepress') 12 | .description('Generates vitepress API documentation from jsdoc annotated source code.') 13 | .version('1.0.0'); 14 | 15 | program 16 | .command('init') 17 | .description('init vitepress directory.') 18 | .action(async () => { 19 | await initDocs(); 20 | }); 21 | 22 | program 23 | .command('start') 24 | .description('Generates vitepress API documentation from jsdoc annotated source code and run Vitepress') 25 | .action(async () => { 26 | await jsdocToMd(); 27 | await new Promise(resolve => setTimeout(resolve, 5000)); 28 | await startVitePress(); 29 | }); 30 | 31 | program 32 | .command('build') 33 | .description('Generates vitepress API documentation from jsdoc annotated source code and build Vitepress') 34 | .action(async () => { 35 | await jsdocToMd(); 36 | await new Promise(resolve => setTimeout(resolve, 5000)); 37 | await buildVitePress(); 38 | }); 39 | 40 | program.parse(); 41 | -------------------------------------------------------------------------------- /src/init-docs.ts: -------------------------------------------------------------------------------- 1 | import ora from 'ora'; 2 | import fs from 'fs-extra'; 3 | import gitclone from 'git-clone/promise'; 4 | import path from 'path'; 5 | 6 | /** 7 | * @module init-docs 8 | * @description init docs directory 9 | */ 10 | 11 | /** 12 | * @exports initDocs "jsdoc2vitepress init" init docs directory 13 | * @returns {Promise} Return promise to check if init success 14 | */ 15 | export const initDocs = async () => { 16 | const loading = ora('Init docs directory'); 17 | try { 18 | const templateGitUrl = 'https://github.com/luciozhang/jsdoc2vitepress-template.git'; 19 | const docsDir = path.resolve(process.cwd(), 'docs'); 20 | await gitclone(templateGitUrl, docsDir, { checkout: 'master', shallow: true }); 21 | fs.removeSync(path.join(docsDir, '.git')); 22 | loading.succeed('Init docs directory success'); 23 | } catch (error) { 24 | loading.fail(`Init docs directory fail: ${error}\nPlease delete local 'docs' directory and retry.`); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /src/jsdoc-to-md.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs-extra'; 2 | import path from 'path'; 3 | import jsdoc2md from 'jsdoc-to-markdown'; 4 | import ora from 'ora'; 5 | 6 | const configJ2VPath = path.resolve(process.cwd(), 'docs', '.vitepress', 'jsdoc2vitepress.config.json'); 7 | const configJ2MPath = path.resolve(process.cwd(), 'docs', '.vitepress', 'jsdoc2md.config.json'); 8 | 9 | /** 10 | * @module jsdoc-to-md 11 | * @description Generates Markdown API documentation from jsdoc annotated source code. 12 | */ 13 | 14 | /** 15 | * @exports jsdocToMd Generates Markdown 16 | * @returns {Promise} Return promise to check if generate success 17 | */ 18 | export const jsdocToMd = async () => { 19 | const loading = ora('Generates Markdown'); 20 | try { 21 | const { markdownDirs } = await fs.readJSON(configJ2VPath); 22 | 23 | await Promise.all(markdownDirs.map(async (sourceObject: any) => { 24 | const { root, output, ingoreList } = sourceObject; 25 | await makeMarkDownForFiles(root, output, ingoreList); 26 | })); 27 | loading.succeed('Generates Markdown success'); 28 | } catch (error) { 29 | loading.fail(`Generates Markdown fail: ${error}`); 30 | } 31 | }; 32 | 33 | const makeMarkDownForFiles = async (root: string, output: string, ingoreList: Array) => { 34 | const fileList = await fs.readdir(root); 35 | await Promise.all(fileList.map(async (fileName) => { 36 | if (ingoreList.indexOf(fileName) === -1) { 37 | await makeMarkDownDoc(fileName, root, output); 38 | } 39 | })); 40 | }; 41 | 42 | const makeMarkDownDoc = async (sourceName: string, sourceRootPath: string, outputPath: string) => { 43 | let sourcePath = `${sourceRootPath}/${sourceName}`; 44 | const outputName = sourceName.replace('.js', '').replace('.ts', ''); 45 | 46 | const loading = ora(`Generates Markdown for ${sourcePath}`); 47 | try { 48 | // 处理js文件的路径,需要区分是文件或目录,目录会将目录下所有文件生成为一个md 49 | const stat = fs.lstatSync(sourcePath); 50 | if (stat.isDirectory()) { 51 | sourcePath = `${sourcePath}/*`; 52 | } 53 | 54 | const mdStr = await jsdoc2md.render({ 55 | 'example-lang': 'javascript', 56 | files: path.resolve(process.cwd(), sourcePath), 57 | 'name-format': 'backticks', 58 | 'heading-depth': 2, 59 | 'module-index-format': 'none', 60 | configure: path.resolve(process.cwd(), configJ2MPath), 61 | }); 62 | if (mdStr) { 63 | fs.outputFile(path.resolve(process.cwd(), `${outputPath}/${outputName}.md`), mdStr); 64 | loading.succeed('Generates Markdown success in ' + `${outputPath}/${outputName}.md`); 65 | } 66 | } catch (error) { 67 | loading.fail(`Generates Markdown fail for ${sourcePath}: ${error}`); 68 | } 69 | }; 70 | 71 | -------------------------------------------------------------------------------- /src/md-to-vitepress.ts: -------------------------------------------------------------------------------- 1 | import shell from 'shelljs'; 2 | /** 3 | * @module md-to-vitepress 4 | * @description Generates VitePress API documentation from jsdoc annotated source code. 5 | */ 6 | 7 | /** 8 | * @exports startVitePress Run VitePress server 9 | * @returns {Promise} Return promise to check if run success 10 | */ 11 | export const startVitePress = async () => { 12 | shell.exec('node_modules/.bin//vitepress dev docs'); 13 | }; 14 | 15 | /** 16 | * @exports buildVitePress build VitePress server 17 | * @returns {Promise} Return promise to check if build success 18 | */ 19 | export const buildVitePress = async () => { 20 | shell.exec('node_modules/.bin/vitepress build docs'); 21 | }; 22 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "sourceMap": true, 9 | "outDir": "./lib", 10 | }, 11 | "include": [".eslintrc.js", "src/**/*", "docs-template"], 12 | "exclude": ["node_modules", "lib/**/*"], 13 | } 14 | -------------------------------------------------------------------------------- /types/config.d.ts: -------------------------------------------------------------------------------- 1 | export declare const MD_FILES: { 2 | root: string; 3 | output: string; 4 | ingoreList: never[]; 5 | }[]; 6 | export declare const JSDOC2MD_CONFIG = './__tools__/js-doc-maker/jsdoc2md.json'; 7 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author luciozhang 3 | * @description Generates vitepress API documentation from jsdoc annotated source code 4 | */ 5 | export {}; 6 | -------------------------------------------------------------------------------- /types/jsdoc2md.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author luciozhang 3 | * @description js代码由注释生成markdown文件 4 | */ 5 | export {}; 6 | -------------------------------------------------------------------------------- /types/md2vitepress.d.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luciozhang/jsdoc2vitepress/48275ec9a9687db9f261de80e0fcd151e76e81b9/types/md2vitepress.d.ts -------------------------------------------------------------------------------- /types/src/index.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author luciozhang 3 | * @description Generates vitepress API documentation from jsdoc annotated source code 4 | */ 5 | export {}; 6 | -------------------------------------------------------------------------------- /types/src/jsdoc2md.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author luciozhang 3 | * @description js代码由注释生成markdown文件 4 | */ 5 | export {}; 6 | -------------------------------------------------------------------------------- /types/src/md2vitepress.d.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luciozhang/jsdoc2vitepress/48275ec9a9687db9f261de80e0fcd151e76e81b9/types/src/md2vitepress.d.ts --------------------------------------------------------------------------------