diff --git a/documentation/.vuepress/config.js b/documentation/.vuepress/config.js new file mode 100644 index 0000000..5f0b4be --- /dev/null +++ b/documentation/.vuepress/config.js @@ -0,0 +1,44 @@ +const { sidebarTree } = require('../code/config'); + +module.exports = { + contentLoading: true, + dest: 'public', + title: 'vuepress-jsdoc', + description: 'vuepress-jsdoc documented with itself', + plugins: [ + [ + // require('vuepress-jsdoc') + require('../../dist/index.js').default, + { + folder: 'code', + jsDocConfigPath: './jsdoc.json', + source: './src', + dist: './documentation', + title: 'API' + } + ] + ], + locales: { + '/': { + title: 'vuepress-jsdoc', + description: 'A CLI to create jsdoc md files for vuepress' + } + }, + themeConfig: { + sidebarDepth: 4, + locales: { + '/': { + nav: [ + { + text: 'Home', + link: '/' + } + ], + // Add the generated sidebar + sidebar: { + ...sidebarTree('Readme') + } + } + } + } +}; diff --git a/documentation/README.md b/documentation/README.md new file mode 100644 index 0000000..c3738b8 --- /dev/null +++ b/documentation/README.md @@ -0,0 +1,5 @@ +--- +home: true +actionText: Get Started → +actionLink: /code/ +--- diff --git a/documentation/code/README.md b/documentation/code/README.md new file mode 100644 index 0000000..86eb70c --- /dev/null +++ b/documentation/code/README.md @@ -0,0 +1,200 @@ +# vuepress-jsdoc + +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ph1p_vuepress-jsdoc&metric=alert_status)](https://sonarcloud.io/dashboard?id=ph1p_vuepress-jsdoc) +[![npm](https://img.shields.io/npm/v/vuepress-jsdoc.svg)](https://www.npmjs.com/package/vuepress-jsdoc) +[![vercel](https://img.shields.io/badge/vercel-demo-black)](https://vuepress-jsdoc-example.vercel.app) + +This npm package is a command line script, which scans your JavaScript, Vue or Typescript source code and generates markdown files for vuepress with the help of [jsdoc-to-markdown](https://github.com/jsdoc2md/jsdoc-to-markdown) and [vue-docgen-cli](https://github.com/vue-styleguidist/vue-styleguidist/tree/dev/packages/vue-docgen-cli). + +![CLI ./example](https://user-images.githubusercontent.com/15351728/131877824-0124e47f-9080-4976-88d0-84ad04b64f24.gif) + +## How to + +```bash +yarn global add vuepress-jsdoc +npm i vuepress-jsdoc -g +``` + +**Example:** + +```bash +# search code in src and move it to code (./documentation/code) in your vuepress folder (./documentation) +vuepress-jsdoc --source ./src --dist ./documentation --folder code --title API --exclude=**/*/*.test.js +``` + +#### Plugin (Dev-Mode) `alpha` + +You can use `vuepress-jsdoc` also as plugin. +This plugin watches you generated files. + +```javascript +// .vuepress/config.js +plugins: [ + [ + require('vuepress-jsdoc').default, + { + folder: 'code', + jsDocConfigPath: './jsdoc.json', + source: './src', + dist: './documentation', + title: 'API' + } + ] +]; +``` + +#### Watch-Mode `alpha` + +If you do not want to run`vuepress-jsdoc` again and again and again. +You can simply pass `--watch` or `-w`. + +### Commands + +If no command passed it will run `generate` as default + +| Name | Alias | Description | +| -------- | ------ | ------------------------------------------------------------------------------------------------------- | +| generate | gen, g | search code in src and move it to code (./documentation/code) in your vuepress folder (./documentation) | + +### Options + +| Name | Alias | Default | Description | +| ----------------- | ----- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | +| --source | -s | ./src | Source folder with .js or .ts files | +| --dist | -d | ./documentation | Destination folder | +| --folder | -f | ./code | Folder inside destination folder. Gets overwritten everytime | +| --title | -t | API | Title of your documentation | +| --help | -h | | Show help | +| --version | -v | | Show current version | +| --readme | -r | | Path to custom readme file | +| --exclude | -e | | Pattern to exclude files/folders (Comma seperated) - \*.test.js,exclude.js [more information](https://github.com/micromatch/micromatch#ismatch) | +| --rmPattern | -rm | | Pattern when removing files. You can ex- and include files. (glob pattern) | +| --partials | -p | | jsdoc2markdown partial templates (overwrites default ones) | +| --jsDocConfigPath | -c | | Path to [JsDoc Config](http://usejsdoc.org/about-configuring-jsdoc.html) (experimental) | +| --watch | -w | | Watch changes and update markdown files | + +### config.js + +Inside your generated folder, you can find a `config.js`. +This file includes a complete filetree and an vuepress sidebar tree. + +## How to configure vuepress + +[Vuepress](https://vuepress.vuejs.org/) is a static site generator by Evan You. +You can add all generated documentation files to your existing vuepress project or create a new one. + +```bash +# First install vuepress +yarn global add vuepress + +# Run the CLI +vuepress-jsdoc + +# Run vuepress dev server +vuepress dev ./documentation + +# Run vuepress build, if you want to ship it +vuepress build ./documentation +``` + +**Access it via:** [http://localhost:8080/code/](http://localhost:8080/code/) + +Now you need the sidebar. +Create a `.vuepress` folder inside the `documentation` folder and add the following `config.js`. + +**config.js:** + +```javascript +// auto generated sidebar +const { sidebarTree } = require('../code/config'); + +module.exports = { + dest: 'dist', + locales: { + '/': { + title: 'vuepress-jsdoc', + description: 'Generate jsdoc markdown files for vuepress' + } + }, + themeConfig: { + editLinks: true, + sidebarDepth: 4, + docsDir: 'code', + locales: { + '/': { + nav: [ + { + text: 'Home', + link: '/' + } + ], + // Add the generated sidebar + sidebar: Object.assign({}, sidebarTree('Mainpage title')) + } + } + } +}; +``` + +## Custom readme + +You can easily add a custom path to your readme by using the `--readme ./path/to/file.md` parameter. If you move a `README.md` inside your source folder, it should resolve it automatically. +You can set the title by passing it to the `sidebarTree('Mainpage title')` function inside your `./.vuepress/config.js`. + +Once the README.md has been added, it is no longer overwritten! +If you want it to be overwritten, set `--rmPattern=./documentation/code/README.md`. + +## @vuepress comment block + +You can add custom meta data to your pages by using the `@vuepress` block: + +```javascript +/* + * @vuepress + * --- + * title: Your custom title + * headline: You custom headline + * --- + */ +``` + +Use `headline` to add a custom `h1` title. + +[More information](https://vuepress.vuejs.org/guide/markdown.html#front-matter) + +## Typescript + +To use typescript, you have to install these dev-dependencies: + +```bash +yarn add -D typescript jsdoc-babel @babel/cli @babel/core @babel/preset-env @babel/preset-typescript jsdoc-to-markdown +``` + +Next, you have to add a `jsdoc.json` to your project with some settings and add it with the `-c` parameter. +You can find a full working example with all settings inside the `./example` folder. +The example shows also how to use babel-`plugins`. + +## Example + +The `./example` folder includes a full working vuepress-jsdoc example. + +```bash +# Install dependencies +npm install + +# Run the CLI +vuepress-jsdoc + +# Generate docs +npm run docs + +# Run dev server +npm run dev + +# Generate dist folder +npm run build +``` + +## Contribute + +PRs are always welcome (: diff --git a/documentation/code/__index__.md b/documentation/code/__index__.md new file mode 100644 index 0000000..6568f81 --- /dev/null +++ b/documentation/code/__index__.md @@ -0,0 +1,88 @@ +--- +title: Main +headline: The Main File +--- + +# The Main File + +## Functions + +
+
createVuepressSidebar(options)
+

Create the sidebar

+
+
parseDirectoryFile(file, argv)
+

Parse file

+
+
parseArguments(argv)
+

Parse all CLI arguments

+
+
generate(argv)
+

Default command that generate md files

+
+
plugin(argv, ctx)
+

The vuepress plugins

+
+
+ + + +## createVuepressSidebar(options) ⇒ +Create the sidebar + +**Kind**: global function +**Returns**: Promise + +| Param | +| --- | +| options | + + + +## parseDirectoryFile(file, argv) ⇒ +Parse file + +**Kind**: global function +**Returns**: Promise + +| Param | +| --- | +| file | +| argv | + + + +## parseArguments(argv) ⇒ +Parse all CLI arguments + +**Kind**: global function +**Returns**: all arguments + +| Param | +| --- | +| argv | + + + +## generate(argv) +Default command that generate md files + +**Kind**: global function + +| Param | Type | Description | +| --- | --- | --- | +| argv | object | passed arguments | + + + +## plugin(argv, ctx) ⇒ +The vuepress plugins + +**Kind**: global function +**Returns**: plugin + +| Param | +| --- | +| argv | +| ctx | + diff --git a/documentation/code/config.js b/documentation/code/config.js new file mode 100644 index 0000000..46fedcf --- /dev/null +++ b/documentation/code/config.js @@ -0,0 +1 @@ +exports.fileTree=[{"name":"__index__","path":"/__index__","fullPath":"dist/__index__","ext":".js"},{"name":"lib","children":[{"name":"comment-parser","path":"/comment-parser","fullPath":"dist/lib/comment-parser","ext":".js"},{"name":"list-folder","path":"/list-folder","fullPath":"dist/lib/list-folder","ext":".js"},{"name":"parser","path":"/parser","fullPath":"dist/lib/parser","ext":".js"},{"name":"utils","path":"/utils","fullPath":"dist/lib/utils","ext":".js"},{"name":"vue-sidebar","path":"/vue-sidebar","fullPath":"dist/lib/vue-sidebar","ext":".js"}]}];exports.sidebarTree = (title = 'Mainpage') => ({"/code/":[{"title":"API","collapsable":false,"children":[["",""+title+""],"__index__"]},{"title":"lib","collapsable":false,"children":["lib/comment-parser","lib/list-folder","lib/parser","lib/utils","lib/vue-sidebar"]}]}); \ No newline at end of file diff --git a/documentation/code/lib/comment-parser.md b/documentation/code/lib/comment-parser.md new file mode 100644 index 0000000..8532ced --- /dev/null +++ b/documentation/code/lib/comment-parser.md @@ -0,0 +1,42 @@ +--- +title: comment-parser +--- + +# comment-parser + +## Functions + +
+
parseComment(fileContent)
+

Search in file for @vuepress comment

+
+
parseVuepressFileHeader(content, file)
+

Helper function to get header as strctured markdown

+
+
+ + + +## parseComment(fileContent) ⇒ +Search in file for @vuepress comment + +**Kind**: global function +**Returns**: object of found frontmatter data + +| Param | +| --- | +| fileContent | + + + +## parseVuepressFileHeader(content, file) ⇒ +Helper function to get header as strctured markdown + +**Kind**: global function +**Returns**: markdown header + +| Param | Description | +| --- | --- | +| content | : ; | +| file | | + diff --git a/documentation/code/lib/list-folder.md b/documentation/code/lib/list-folder.md new file mode 100644 index 0000000..e061340 --- /dev/null +++ b/documentation/code/lib/list-folder.md @@ -0,0 +1,21 @@ +--- +title: list-folder +--- + +# list-folder + + + +## listFolder(srcPath, exclude, mainPath, tree) ⇒ +Recursively traverse folders and return exluded files, a file list and a file tree. + +**Kind**: global function +**Returns**: paths array, tree, excluded array + +| Param | +| --- | +| srcPath | +| exclude | +| mainPath | +| tree | + diff --git a/documentation/code/lib/parser.md b/documentation/code/lib/parser.md new file mode 100644 index 0000000..450881d --- /dev/null +++ b/documentation/code/lib/parser.md @@ -0,0 +1,63 @@ +--- +title: parser +--- + +# parser + +## Functions + +
+
parseFile(file, srcFolder, destFolder, configPath, partials)
+

Parse a typescript or javascript file

+
+
parseVueFile(file, srcFolder, destFolder)
+

Parse a vue file

+
+
writeContentToFile(parseData, dest)
+

Write content on disk

+
+
+ + + +## parseFile(file, srcFolder, destFolder, configPath, partials) ⇒ +Parse a typescript or javascript file + +**Kind**: global function +**Returns**: file data + +| Param | +| --- | +| file | +| srcFolder | +| destFolder | +| configPath | +| partials | + + + +## parseVueFile(file, srcFolder, destFolder) ⇒ +Parse a vue file + +**Kind**: global function +**Returns**: file data + +| Param | +| --- | +| file | +| srcFolder | +| destFolder | + + + +## writeContentToFile(parseData, dest) ⇒ +Write content on disk + +**Kind**: global function +**Returns**: null or type with some data of the saved file + +| Param | +| --- | +| parseData | +| dest | + diff --git a/documentation/code/lib/utils.md b/documentation/code/lib/utils.md new file mode 100644 index 0000000..42957c5 --- /dev/null +++ b/documentation/code/lib/utils.md @@ -0,0 +1,72 @@ +--- +title: utils +--- + +# utils + +## Functions + +
+
getExtension(path)
+

Get extension of file

+
+
checkExtension(path, extensions)
+

Check if extension ist correct

+
+
getFilename(path)
+

Get filename without extension

+
+
asyncForEach(array, callback)
+

Async foreach loop

+
+
+ + + +## getExtension(path) ⇒ +Get extension of file + +**Kind**: global function +**Returns**: extension of file + +| Param | +| --- | +| path | + + + +## checkExtension(path, extensions) ⇒ +Check if extension ist correct + +**Kind**: global function +**Returns**: boolean + +| Param | +| --- | +| path | +| extensions | + + + +## getFilename(path) ⇒ +Get filename without extension + +**Kind**: global function +**Returns**: filename + +| Param | +| --- | +| path | + + + +## asyncForEach(array, callback) +Async foreach loop + +**Kind**: global function + +| Param | +| --- | +| array | +| callback | + diff --git a/documentation/code/lib/vue-sidebar.md b/documentation/code/lib/vue-sidebar.md new file mode 100644 index 0000000..4a9a4ae --- /dev/null +++ b/documentation/code/lib/vue-sidebar.md @@ -0,0 +1,18 @@ +--- +title: vue-sidebar +--- + +# vue-sidebar + + + +## generateVueSidebar(param0) ⇒ +Runs through the given tree structure and creates a vuepress config + +**Kind**: global function +**Returns**: returns the vuepress menu strcture + +| Param | +| --- | +| param0 | + diff --git a/package.json b/package.json index 54a721a..e4c4322 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,10 @@ "build": "tsc", "prepublishOnly": "npm i && npm run build", "prepare": "husky install", - "version": "conventional-changelog -p karma -i CHANGELOG.md -s -r 0 && git add ." + "version": "conventional-changelog -p karma -i CHANGELOG.md -s -r 0 && git add .", + "docs": "vuepress-jsdoc --source=./dist --readme ./README.md --exclude=\"**/*.d.ts,**/interfaces.*,**/constants.*,**/cmds.*\"", + "docs:dev": "npm run docs && npx vuepress dev documentation", + "docs:build": "npx vuepress build documentation" }, "keywords": [ "jsdoc", diff --git a/src/index.ts b/src/index.ts index ee66a4b..072e8a8 100755 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,10 @@ +/* + * @vuepress + * --- + * title: Main + * headline: The Main File + * --- + */ import chalk from 'chalk'; import chokidar from 'chokidar'; import del from 'del'; @@ -12,6 +19,11 @@ import { listFolder } from './lib/list-folder'; import { parseFile, parseVueFile, writeContentToFile } from './lib/parser'; import { generateVueSidebar } from './lib/vue-sidebar'; +/** + * Create the sidebar + * @param options + * @returns Promise + */ const createVuepressSidebar = options => fs.writeFile( `${options.docsFolder}/config.js`, @@ -23,6 +35,12 @@ const createVuepressSidebar = options => )});` ); +/** + * Parse file + * @param file + * @param argv + * @returns Promise + */ const parseDirectoryFile = async (file: DirectoryFile, argv: CLIArguments) => { const { srcFolder, docsFolder, partials } = parseArguments(argv); if (!file.isDir && file.folder) { @@ -63,6 +81,11 @@ const createReadmeFile = async (argv: CLIArguments, deletedPaths?: string[]) => await fs.writeFile(`${docsFolder}/README.md`, readMeContent); }; +/** + * Parse all CLI arguments + * @param argv + * @returns all arguments + */ const parseArguments = (argv: CLIArguments) => { return { exclude: (argv.exclude || '').split(',').filter(Boolean), @@ -205,7 +228,13 @@ const watchFiles = (argv: CLIArguments) => { } }; -export default (argv: CLIArguments, ctx) => ({ +/** + * The vuepress plugins + * @param argv + * @param ctx + * @returns plugin + */ +const plugin = (argv: CLIArguments, ctx) => ({ name: 'vuepress-plugin-jsdoc', ready: async () => { if (!ctx.isProd) { @@ -214,3 +243,5 @@ export default (argv: CLIArguments, ctx) => ({ } } }); + +export default plugin; diff --git a/src/lib/comment-parser.ts b/src/lib/comment-parser.ts index b766298..b1a3ccb 100644 --- a/src/lib/comment-parser.ts +++ b/src/lib/comment-parser.ts @@ -2,9 +2,14 @@ import fm from 'front-matter'; import { DirectoryFile } from '../interfaces'; +/** + * Search in file for @vuepress comment + * @param fileContent + * @returns object of found frontmatter data + */ export const parseComment = (fileContent: string) => { try { - const allCommentBlocks = fileContent.match(/\/*[\s\S]*\/.*/g); + const allCommentBlocks = fileContent.match(/\/\*[\s\S]*?\*\/|([^:]|^)\/\/.*$/g); const vuepressBlock = allCommentBlocks?.filter((block: string) => { return block.split('\n').filter(line => line.indexOf('@vuepress') >= 0).length; })[0]; @@ -33,8 +38,15 @@ export const parseComment = (fileContent: string) => { } }; +/** + * Helper function to get header as strctured markdown + * @param content : ; + * @param file + * @returns markdown header + */ export const parseVuepressFileHeader = (content: string, file: DirectoryFile) => { const { frontmatter, attributes } = parseComment(content); + console.log({ frontmatter, attributes }); let fileContent = '---\n'; diff --git a/src/lib/list-folder.ts b/src/lib/list-folder.ts index 7ca5eb8..6194e0f 100644 --- a/src/lib/list-folder.ts +++ b/src/lib/list-folder.ts @@ -4,6 +4,14 @@ import path from 'path'; import { DirectoryFile, FileTree } from '../interfaces'; +/** + * Recursively traverse folders and return exluded files, a file list and a file tree. + * @param srcPath + * @param exclude + * @param mainPath + * @param tree + * @returns paths array, tree, excluded array + */ export const listFolder = async (srcPath: string, exclude: string[] = [], mainPath?: string, tree: FileTree[] = []) => { const paths: DirectoryFile[] = []; const excluded: DirectoryFile[] = []; diff --git a/src/lib/parser.ts b/src/lib/parser.ts index e7cc106..db52114 100644 --- a/src/lib/parser.ts +++ b/src/lib/parser.ts @@ -10,6 +10,15 @@ import { DirectoryFile, ParseReturn } from '../interfaces'; import { parseVuepressFileHeader } from './comment-parser'; +/** + * Parse a typescript or javascript file + * @param file + * @param srcFolder + * @param destFolder + * @param configPath + * @param partials + * @returns file data + */ export const parseFile = async ( file: DirectoryFile, srcFolder: string, @@ -74,6 +83,13 @@ export const parseFile = async ( }; }; +/** + * Parse a vue file + * @param file + * @param srcFolder + * @param destFolder + * @returns file data + */ export const parseVueFile = async ( file: DirectoryFile, srcFolder: string, @@ -129,6 +145,12 @@ export const parseVueFile = async ( }; }; +/** + * Write content on disk + * @param parseData + * @param dest + * @returns null or type with some data of the saved file + */ export const writeContentToFile = async (parseData: ParseReturn | null, dest: string) => { const root = process.cwd(); dest = join(root, dest); diff --git a/src/lib/vue-sidebar.ts b/src/lib/vue-sidebar.ts index 7b3668d..314b16e 100644 --- a/src/lib/vue-sidebar.ts +++ b/src/lib/vue-sidebar.ts @@ -5,6 +5,11 @@ interface Node { children: any[]; } +/** + * Runs through the given tree structure and creates a vuepress config + * @param param0 + * @returns returns the vuepress menu strcture + */ export const generateVueSidebar = ({ fileTree, codeFolder,