diff --git a/example/documentation/.vuepress/config.js b/example/documentation/.vuepress/config.js index fb9d205..d6373d7 100644 --- a/example/documentation/.vuepress/config.js +++ b/example/documentation/.vuepress/config.js @@ -23,7 +23,7 @@ module.exports = { ], // Add the generated sidebar sidebar: { - ...sidebarTree('Test') + ...sidebarTree('Readme') } } } diff --git a/example/documentation/code/README.md b/example/documentation/code/README.md new file mode 100644 index 0000000..862f10f --- /dev/null +++ b/example/documentation/code/README.md @@ -0,0 +1,18 @@ +## 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 +``` diff --git a/example/documentation/code/components/sub/sub-test.md b/example/documentation/code/components/sub/sub-test.md index 3f0de94..1fcc0b1 100644 --- a/example/documentation/code/components/sub/sub-test.md +++ b/example/documentation/code/components/sub/sub-test.md @@ -1,4 +1,76 @@ --- title: sub-test --- - # grid > This is an example of creating a reusable grid component and using it with external data. Author: [Rafael](https://github.com/rafaesc92) Since: Version 1.0.1 Version: 1.0.5 ## Props | Prop name | Description | Type | Values | Default | | ------------- | ----------- | --------- | ----------- | ----------- | | msg | object/array defaults should be returned from a factory function
`@version` 1.0.5
`@since` Version 1.0.1
`@see` See [Wikipedia](https://en.wikipedia.org/wiki/Web_colors#HTML_color_names) for a list of color names
`@link` See [Wikipedia](https://en.wikipedia.org/wiki/Web_colors#HTML_color_names) for a list of color names | string\|number | - | text || myF | Function | func | - | (param, param2) => {} || v-model | Model example
`@model` true | string | - | || data | describe data
`@version` 1.0.5 | array | - | || columns | get columns list | array | - | || filterKey | filter key
`@ignore` true | string | - | 'example' | ## Methods ### sortBy > Sets the order #### Params | Param name | Type | Description | | ------------- |------------- | -------------| | key | string | Key to order | #### Return | Type | Description | | ------------- | -------------| | string | Test | ## Events | Event name | Properties | Description | | -------------- |--------------- | -------------| | success | **example** `object` - the demo example
**exampleStr** `string` - the demo example
**exampleNum** `number` - the demo example | Success event. ## Slots | Name | Description | Bindings | | ------------- | ------------ | -------- | | header | Use this slot header | || footer | Use this slot footer | | --- \ No newline at end of file + + # grid + + + > This is an example of creating a reusable grid component and using it with external data. + + + Author: [Rafael](https://github.com/rafaesc92) + + Since: Version 1.0.1 + + Version: 1.0.5 + + + + + +## Props + + | Prop name | Description | Type | Values | Default | + | ------------- | ----------- | --------- | ----------- | ----------- | + | msg | object/array defaults should be returned from a factory function
`@version` 1.0.5
`@since` Version 1.0.1
`@see` See [Wikipedia](https://en.wikipedia.org/wiki/Web_colors#HTML_color_names) for a list of color names
`@link` See [Wikipedia](https://en.wikipedia.org/wiki/Web_colors#HTML_color_names) for a list of color names | string\|number | - | text | +| myF | Function | func | - | (param, param2) => {} | +| v-model | Model example
`@model` true | string | - | | +| data | describe data
`@version` 1.0.5 | array | - | | +| columns | get columns list | array | - | | +| filterKey | filter key
`@ignore` true | string | - | 'example' | + + + +## Methods + + +### sortBy + > Sets the order + + +#### Params + + | Param name | Type | Description | + | ------------- |------------- | -------------| + | key | string | Key to order | + + +#### Return + + | Type | Description | + | ------------- | -------------| + | string | Test | + + + + +## Events + + | Event name | Properties | Description | + | -------------- |--------------- | -------------| + | success | **example** `object` - the demo example
**exampleStr** `string` - the demo example
**exampleNum** `number` - the demo example | Success event. + + + +## Slots + + | Name | Description | Bindings | + | ------------- | ------------ | -------- | + | header | Use this slot header | | +| footer | Use this slot footer | | + + --- + + + + \ No newline at end of file diff --git a/example/documentation/code/components/sub/sub-vue-md.md b/example/documentation/code/components/sub/sub-vue-md.md index 5cd0c73..f211444 100644 --- a/example/documentation/code/components/sub/sub-vue-md.md +++ b/example/documentation/code/components/sub/sub-vue-md.md @@ -1,4 +1,56 @@ --- title: sub-vue-md --- - # Button > The only true button. ## Props | Prop name | Description | Type | Values | Default | | ------------- | ----------- | --------- | ----------- | ----------- | | color | The color for the button. | string | - | '#333' || size | The size of the button | string | `small`, `normal`, `large` | 'normal' || onClick | Gets called when the user clicks on the button
`@ignore` true | func | - | event => {
console.log('You have clicked me!', event.target);
} | ## Slots | Name | Description | Bindings | | ------------- | ------------ | -------- | | default | Content of button | | ---Use vue live right here too````markdown```jsx live``````````jsx live```To render an example as highlighted source code remove the live modifier```html``` \ No newline at end of file + + # Button + + + > The only true button. + + + + + + + + + +## Props + + | Prop name | Description | Type | Values | Default | + | ------------- | ----------- | --------- | ----------- | ----------- | + | color | The color for the button. | string | - | '#333' | +| size | The size of the button | string | `small`, `normal`, `large` | 'normal' | +| onClick | Gets called when the user clicks on the button
`@ignore` true | func | - | event => {
console.log('You have clicked me!', event.target);
} | + + + + + +## Slots + + | Name | Description | Bindings | + | ------------- | ------------ | -------- | + | default | Content of button | | + + --- +Use vue live right here too + +````markdown +```jsx live + +``` +```` + +```jsx live + +``` + +To render an example as highlighted source code remove the live modifier + +```html + +``` + + + \ No newline at end of file diff --git a/example/documentation/code/components/test.md b/example/documentation/code/components/test.md index e609950..9297194 100644 --- a/example/documentation/code/components/test.md +++ b/example/documentation/code/components/test.md @@ -1,4 +1,76 @@ --- title: test --- - # grid > This is an example of creating a reusable grid component and using it with external data. Author: [Rafael](https://github.com/rafaesc92) Since: Version 1.0.1 Version: 1.0.5 ## Props | Prop name | Description | Type | Values | Default | | ------------- | ----------- | --------- | ----------- | ----------- | | msg | object/array defaults should be returned from a factory function
`@version` 1.0.5
`@since` Version 1.0.1
`@see` See [Wikipedia](https://en.wikipedia.org/wiki/Web_colors#HTML_color_names) for a list of color names
`@link` See [Wikipedia](https://en.wikipedia.org/wiki/Web_colors#HTML_color_names) for a list of color names | string\|number | - | text || myF | Function | func | - | (param, param2) => {} || v-model | Model example
`@model` true | string | - | || data | describe data
`@version` 1.0.5 | array | - | || columns | get columns list | array | - | || filterKey | filter key
`@ignore` true | string | - | 'example' | ## Methods ### sortBy > Sets the order #### Params | Param name | Type | Description | | ------------- |------------- | -------------| | key | string | Key to order | #### Return | Type | Description | | ------------- | -------------| | string | Test | ## Events | Event name | Properties | Description | | -------------- |--------------- | -------------| | success | **example** `object` - the demo example
**exampleStr** `string` - the demo example
**exampleNum** `number` - the demo example | Success event. ## Slots | Name | Description | Bindings | | ------------- | ------------ | -------- | | header | Use this slot header | || footer | Use this slot footer | | --- \ No newline at end of file + + # grid + + + > This is an example of creating a reusable grid component and using it with external data. + + + Author: [Rafael](https://github.com/rafaesc92) + + Since: Version 1.0.1 + + Version: 1.0.5 + + + + + +## Props + + | Prop name | Description | Type | Values | Default | + | ------------- | ----------- | --------- | ----------- | ----------- | + | msg | object/array defaults should be returned from a factory function
`@version` 1.0.5
`@since` Version 1.0.1
`@see` See [Wikipedia](https://en.wikipedia.org/wiki/Web_colors#HTML_color_names) for a list of color names
`@link` See [Wikipedia](https://en.wikipedia.org/wiki/Web_colors#HTML_color_names) for a list of color names | string\|number | - | text | +| myF | Function | func | - | (param, param2) => {} | +| v-model | Model example
`@model` true | string | - | | +| data | describe data
`@version` 1.0.5 | array | - | | +| columns | get columns list | array | - | | +| filterKey | filter key
`@ignore` true | string | - | 'example' | + + + +## Methods + + +### sortBy + > Sets the order + + +#### Params + + | Param name | Type | Description | + | ------------- |------------- | -------------| + | key | string | Key to order | + + +#### Return + + | Type | Description | + | ------------- | -------------| + | string | Test | + + + + +## Events + + | Event name | Properties | Description | + | -------------- |--------------- | -------------| + | success | **example** `object` - the demo example
**exampleStr** `string` - the demo example
**exampleNum** `number` - the demo example | Success event. + + + +## Slots + + | Name | Description | Bindings | + | ------------- | ------------ | -------- | + | header | Use this slot header | | +| footer | Use this slot footer | | + + --- + + + + \ No newline at end of file diff --git a/example/documentation/code/components/vue-md.md b/example/documentation/code/components/vue-md.md index 26090fe..59f5755 100644 --- a/example/documentation/code/components/vue-md.md +++ b/example/documentation/code/components/vue-md.md @@ -1,4 +1,56 @@ --- title: vue-md --- - # Button > The only true button. ## Props | Prop name | Description | Type | Values | Default | | ------------- | ----------- | --------- | ----------- | ----------- | | color | The color for the button. | string | - | '#333' || size | The size of the button | string | `small`, `normal`, `large` | 'normal' || onClick | Gets called when the user clicks on the button
`@ignore` true | func | - | event => {
console.log('You have clicked me!', event.target);
} | ## Slots | Name | Description | Bindings | | ------------- | ------------ | -------- | | default | Content of button | | ---Use vue live right here too````markdown```jsx live``````````jsx live```To render an example as highlighted source code remove the live modifier```html``` \ No newline at end of file + + # Button + + + > The only true button. + + + + + + + + + +## Props + + | Prop name | Description | Type | Values | Default | + | ------------- | ----------- | --------- | ----------- | ----------- | + | color | The color for the button. | string | - | '#333' | +| size | The size of the button | string | `small`, `normal`, `large` | 'normal' | +| onClick | Gets called when the user clicks on the button
`@ignore` true | func | - | event => {
console.log('You have clicked me!', event.target);
} | + + + + + +## Slots + + | Name | Description | Bindings | + | ------------- | ------------ | -------- | + | default | Content of button | | + + --- +Use vue live right here too + +````markdown +```jsx live + +``` +```` + +```jsx live + +``` + +To render an example as highlighted source code remove the live modifier + +```html + +``` + + + \ No newline at end of file diff --git a/example/documentation/code/config.js b/example/documentation/code/config.js new file mode 100644 index 0000000..f6415a4 --- /dev/null +++ b/example/documentation/code/config.js @@ -0,0 +1 @@ +exports.fileTree=[{"name":"Icon","path":"/Icon","fullPath":"src/Icon"},{"name":"class-constructor","path":"/class-constructor","fullPath":"src/class-constructor"},{"name":"components","children":[{"name":"lib","children":[]},{"name":"sub","children":[{"name":"sub-test","path":"/sub-test","fullPath":"src/components/sub/sub-test"},{"name":"sub-vue-md","path":"/sub-vue-md","fullPath":"src/components/sub/sub-vue-md"}]},{"name":"sub copy","children":[]},{"name":"test","path":"/test","fullPath":"src/components/test"},{"name":"vue-md","path":"/vue-md","fullPath":"src/components/vue-md"}]},{"name":"error","path":"/error","fullPath":"src/error"},{"name":"lib","children":[{"name":"cli-data","path":"/cli-data","fullPath":"src/lib/cli-data"},{"name":"dmd-options","path":"/dmd-options","fullPath":"src/lib/dmd-options"},{"name":"jsdoc-options","path":"/jsdoc-options","fullPath":"src/lib/jsdoc-options"},{"name":"jsdoc-to-markdown","path":"/jsdoc-to-markdown","fullPath":"src/lib/jsdoc-to-markdown"},{"name":"subfolder","children":[{"name":"sub","children":[]},{"name":"subfolder","children":[]}]}]},{"name":"lib copy","children":[{"name":"sub","children":[]}]},{"name":"methods","path":"/methods","fullPath":"src/methods"},{"name":"objects","path":"/objects","fullPath":"src/objects"},{"name":"subfolder","children":[{"name":"sub","children":[]},{"name":"subfolder","children":[{"name":"variables","path":"/variables","fullPath":"src/subfolder/subfolder.1/variables"}]},{"name":"variables","path":"/variables","fullPath":"src/subfolder/variables"}]},{"name":"test","path":"/test","fullPath":"src/test"},{"name":"tests","children":[{"name":"class","path":"/class","fullPath":"src/tests/class"}]},{"name":"vue-md","path":"/vue-md","fullPath":"src/vue-md"}];exports.sidebarTree = (title = 'Mainpage') => ({"/code/":[{"title":"API","collapsable":false,"children":[["",""+title+""],"Icon","class-constructor","error","methods","objects","test","vue-md"]},{"title":"components","collapsable":false,"children":["components/sub/sub-test","components/sub/sub-vue-md","components/test","components/vue-md"]},{"title":"lib","collapsable":false,"children":["lib/cli-data","lib/dmd-options","lib/jsdoc-options","lib/jsdoc-to-markdown"]},{"title":"lib copy","collapsable":false,"children":[]},{"title":"subfolder","collapsable":false,"children":["subfolder/subfolder.1/variables","subfolder/variables"]},{"title":"tests","collapsable":false,"children":["tests/class"]}]}); \ No newline at end of file diff --git a/example/documentation/code/test.md b/example/documentation/code/test.md index 5f41b4e..253da3f 100644 --- a/example/documentation/code/test.md +++ b/example/documentation/code/test.md @@ -1,4 +1,85 @@ --- title: test --- - # grid > This is an example of creating a reusable grid component and using it with external data. Author: [Rafael](https://github.com/rafaesc92) Since: Version 1.0.1 Version: 1.0.5 ## Props | Prop name | Description | Type | Values | Default | | ------------- | ----------- | --------- | ----------- | ----------- | | msg | object/array defaults should be returned from a factory function
`@version` 1.0.5
`@since` Version 1.0.1
`@see` See [Wikipedia](https://en.wikipedia.org/wiki/Web_colors#HTML_color_names) for a list of color names
`@link` See [Wikipedia](https://en.wikipedia.org/wiki/Web_colors#HTML_color_names) for a list of color names | string\|number | - | text || myF | Function | func | - | (param, param2) => {} || v-model | Model example
`@model` true | string | - | || data | describe data
`@version` 1.0.5 | array | - | || columns | get columns list | array | - | || filterKey | filter key
`@ignore` true | string | - | 'example' | ## Methods ### sortBy > Sets the order #### Params | Param name | Type | Description | | ------------- |------------- | -------------| | key | string | Key to order | #### Return | Type | Description | | ------------- | -------------| | string | Test | ## Events | Event name | Properties | Description | | -------------- |--------------- | -------------| | success | **example** `object` - the demo example
**exampleStr** `string` - the demo example
**exampleNum** `number` - the demo example | Success event. ## Slots | Name | Description | Bindings | | ------------- | ------------ | -------- | | header | Use this slot header | || footer | Use this slot footer | | ---# Home## Section 1Section 1## Section 2Section 2 \ No newline at end of file + + # grid + + + > This is an example of creating a reusable grid component and using it with external data. + + + Author: [Rafael](https://github.com/rafaesc92) + + Since: Version 1.0.1 + + Version: 1.0.5 + + + + + +## Props + + | Prop name | Description | Type | Values | Default | + | ------------- | ----------- | --------- | ----------- | ----------- | + | msg | object/array defaults should be returned from a factory function
`@version` 1.0.5
`@since` Version 1.0.1
`@see` See [Wikipedia](https://en.wikipedia.org/wiki/Web_colors#HTML_color_names) for a list of color names
`@link` See [Wikipedia](https://en.wikipedia.org/wiki/Web_colors#HTML_color_names) for a list of color names | string\|number | - | text | +| myF | Function | func | - | (param, param2) => {} | +| v-model | Model example
`@model` true | string | - | | +| data | describe data
`@version` 1.0.5 | array | - | | +| columns | get columns list | array | - | | +| filterKey | filter key
`@ignore` true | string | - | 'example' | + + + +## Methods + + +### sortBy + > Sets the order + + +#### Params + + | Param name | Type | Description | + | ------------- |------------- | -------------| + | key | string | Key to order | + + +#### Return + + | Type | Description | + | ------------- | -------------| + | string | Test | + + + + +## Events + + | Event name | Properties | Description | + | -------------- |--------------- | -------------| + | success | **example** `object` - the demo example
**exampleStr** `string` - the demo example
**exampleNum** `number` - the demo example | Success event. + + + +## Slots + + | Name | Description | Bindings | + | ------------- | ------------ | -------- | + | header | Use this slot header | | +| footer | Use this slot footer | | + + --- + +# Home + +## Section 1 + +Section 1 + +## Section 2 + +Section 2 + + + \ No newline at end of file diff --git a/example/documentation/code/vue-md.md b/example/documentation/code/vue-md.md index f2528e9..a7be8c7 100644 --- a/example/documentation/code/vue-md.md +++ b/example/documentation/code/vue-md.md @@ -1,4 +1,67 @@ --- title: vue-md --- - # Button > The only true button. ## Props | Prop name | Description | Type | Values | Default | | ------------- | ----------- | --------- | ----------- | ----------- | | color | The color for the button. | string | - | '#333' || size | The size of the button | string | `small`, `normal`, `large` | 'normal' || onClick | Gets called when the user clicks on the button
`@ignore` true | func | - | event => {
console.log('You have clicked me!', event.target);
} | ## Slots | Name | Description | Bindings | | ------------- | ------------ | -------- | | default | Content of button | | ---Use vue live right here too````markdown```jsx live``````````jsx live```To render an example as highlighted source code remove the live modifier```html```---# Home## Section 1Section 1## Section 2Section 2 \ No newline at end of file + + # Button + + + > The only true button. + + + + + + + + + +## Props + + | Prop name | Description | Type | Values | Default | + | ------------- | ----------- | --------- | ----------- | ----------- | + | color | The color for the button. | string | - | '#333' | +| size | The size of the button | string | `small`, `normal`, `large` | 'normal' | +| onClick | Gets called when the user clicks on the button
`@ignore` true | func | - | event => {
console.log('You have clicked me!', event.target);
} | + + + + + +## Slots + + | Name | Description | Bindings | + | ------------- | ------------ | -------- | + | default | Content of button | | + + --- +Use vue live right here too + +````markdown +```jsx live + +``` +```` + +```jsx live + +``` + +To render an example as highlighted source code remove the live modifier + +```html + +``` +--- + +# Home + +## Section 1 + +Section 1 + +## Section 2 + +Section 2 + + + \ No newline at end of file diff --git a/example/package.json b/example/package.json index 3d577e0..eb607a2 100644 --- a/example/package.json +++ b/example/package.json @@ -4,7 +4,7 @@ "description": "", "main": "index.js", "scripts": { - "docs": "../bin/vuepress-jsdoc.js -c ./jsdoc.json --source=./src --dist=./documentation --title=API --exclude=**/*/*.test.js,class.js --partials=./partials/*.hbs", + "docs": "../bin/vuepress-jsdoc.js -c ./jsdoc.json --source=./src --dist=./documentation --title=API --exclude=**/*/*.test.js,class.js --partials=./partials/*.hbs --readme=./README.md", "dev": "vuepress dev documentation", "build": "vuepress build documentation" }, diff --git a/package-lock.json b/package-lock.json index 2265a24..2d9af68 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,7 +29,7 @@ "@types/micromatch": "^4.0.2", "@types/mkdirp": "^1.0.2", "@typescript-eslint/eslint-plugin": "^4.30.0", - "@typescript-eslint/parser": "^4.29.3", + "@typescript-eslint/parser": "^4.30.0", "babel-jest": "^27.1.0", "cross-env": "^7.0.3", "eslint": "^7.32.0", diff --git a/package.json b/package.json index ffe8aae..b617dac 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "@types/micromatch": "^4.0.2", "@types/mkdirp": "^1.0.2", "@typescript-eslint/eslint-plugin": "^4.30.0", - "@typescript-eslint/parser": "^4.29.3", + "@typescript-eslint/parser": "^4.30.0", "babel-jest": "^27.1.0", "cross-env": "^7.0.3", "eslint": "^7.32.0", diff --git a/src/__tests__/list-folder.test.ts b/src/__tests__/list-folder.test.ts index bc948f2..8e15603 100644 --- a/src/__tests__/list-folder.test.ts +++ b/src/__tests__/list-folder.test.ts @@ -21,12 +21,23 @@ describe('test file-structure', () => { './src' ); - expect(await listFolder('./src', [])).toEqual([ + expect((await listFolder('./src', [])).paths).toEqual([ { ext: '.js', folder: 'src/', isDir: false, name: 'file1', path: 'src/file1.js' }, { ext: '.ts', folder: 'src/', isDir: false, name: 'file2', path: 'src/file2.ts' }, { ext: '.vue', folder: 'src/lib/', isDir: false, name: 'file3', path: 'src/lib/file3.vue' }, { ext: '.js', folder: 'src/lib/index', isDir: false, name: '_index', path: 'src/lib/index.js' }, { isDir: true, name: 'lib', path: 'src/lib' } ]); + expect((await listFolder('./src', [])).tree).toEqual([ + { fullPath: 'src/file1', name: 'file1', path: '/file1' }, + { fullPath: 'src/file2', name: 'file2', path: '/file2' }, + { + children: [ + { fullPath: 'src/lib/file3', name: 'file3', path: '/file3' }, + { fullPath: 'src/lib/index', name: 'index', path: '/index' } + ], + name: 'lib' + } + ]); }); }); diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 0000000..0d94c11 --- /dev/null +++ b/src/constants.ts @@ -0,0 +1,6 @@ +export enum StatisticType { + EMPTY = 'EMPTY', + ERROR = 'ERROR', + SUCCESS = 'SUCCESS', + EXCLUDE = 'EXCLUDE' +} diff --git a/src/index.ts b/src/index.ts index 26a7f20..95fffda 100755 --- a/src/index.ts +++ b/src/index.ts @@ -1,40 +1,14 @@ import chalk from 'chalk'; import del from 'del'; -import { join } from 'path'; -import mkdirp from 'mkdirp'; import fs from 'fs/promises'; +import mkdirp from 'mkdirp'; +import { join } from 'path'; +import { StatisticType } from './constants'; import { listFolder } from './lib/list-folder'; import { parseFile, parseVueFile, writeContentToFile } from './lib/parser'; -import { getExtension } from './lib/utils'; import { generateVueSidebar } from './lib/vue-sidebar'; -const fileTree: any[] = []; -const statistics: Record = {}; -const statusTypes = { - success: 'green', - error: 'red', - exclude: 'blueBright', - empty: 'yellow' -}; - -const extensions = ['.ts', '.js', '.tsx', '.jsx', '.vue']; - -/** A - * Add status and count to result - * @param {string} file - * @param {string} status - * @param {boolean} isDir - */ -const addToStatistics = (file: string, status: string, isDir = false) => { - const extension = !isDir ? getExtension(file) : 'folder'; - - if (!statistics[extension]) { - statistics[extension] = Object.keys(statusTypes).reduce((before, curr) => ({ ...before, [curr]: 0 }), {}); - } - statistics[extension][status]++; -}; - /** * Default command that generate md files * @param {object} argv passed arguments @@ -52,16 +26,29 @@ export const generate = async (argv: Record) => { const startTime = +new Date(); // remove docs folder, except README.md - const deletedPaths = await del([`${docsFolder}/**/*`, `!${docsFolder}/README.md`, ...rmPattern]); + const deletedPaths = await del([`${docsFolder}/**/*`, ...rmPattern]); - const filesAndFolder = await listFolder(srcFolder, exclude); + const { tree, paths } = await listFolder(srcFolder, exclude); await mkdirp(docsFolder); const parsePromises: Promise[] = []; - console.log(); - for (const file of filesAndFolder) { + // write vuepress sidebar + await fs.writeFile( + `${docsFolder}/config.js`, + `exports.fileTree=${JSON.stringify(tree)};exports.sidebarTree = (title = 'Mainpage') => (${JSON.stringify( + generateVueSidebar({ + fileTree: tree, + srcFolder, + codeFolder, + title + }) + ).replace('::vuepress-jsdoc-title::', '"+title+"')});` + ); + + // print out all files + for (const file of paths) { if (!file.isDir) { process.stdout.clearLine(-1); process.stdout.cursorTo(0); @@ -72,46 +59,49 @@ export const generate = async (argv: Record) => { process.stdout.clearLine(-1); process.stdout.cursorTo(0); - for (const file of filesAndFolder) { - if (!file.isDir) { + // iterate through files and parse them + for (const file of paths) { + if (!file.isDir && file.folder) { + // path where file should be saved + const dest = join(docsFolder, file.folder.replace(srcFolder, '')); + switch (file.ext) { case '.tsx': case '.ts': case '.js': parsePromises.push( - writeContentToFile(parseFile(file, srcFolder, docsFolder, argv.jsDocConfigPath, partials)) + writeContentToFile(await parseFile(file, srcFolder, docsFolder, argv.jsDocConfigPath, partials), dest) ); break; case '.jsx': case '.vue': - parsePromises.push(writeContentToFile(parseVueFile(file, srcFolder, docsFolder))); + parsePromises.push(writeContentToFile(await parseVueFile(file, srcFolder, docsFolder), dest)); break; } } } + // wait unitl all files resolved const result = await Promise.all(parsePromises); + // print stats for (const entry of result.flat()) { + if (!entry.file) continue; + + const color = { + [StatisticType.SUCCESS]: 'green', + [StatisticType.ERROR]: 'red', + [StatisticType.EMPTY]: 'yellow' + }[entry.type]; + console.log( - chalk.reset.inverse.bold.green(` ${entry.type.toUpperCase()} `), + chalk.reset.inverse.bold[color](` ${entry.type} `), `${chalk.dim(entry.relativePathSrc)}${chalk.bold(entry.file.name + entry.file.ext)} \u2192 ${chalk.dim( entry.relativePathDest )}${chalk.bold(entry.file.name + '.md')}` ); } - // await fs.writeFile( - // `${docsFolder}/config.js`, - // `exports.fileTree=${JSON.stringify(fileTree)};exports.sidebarTree = (title = 'Mainpage') => (${JSON.stringify( - // generateVueSidebar({ - // fileTree, - // codeFolder, - // title - // }) - // ).replace('::vuepress-jsdoc-title::', '"+title+"')});` - // ); - // create README.md let readMeContent = `### Welcome to ${title}`; const readmePath = readme || `${srcFolder}/README.md`; @@ -119,16 +109,18 @@ export const generate = async (argv: Record) => { try { readMeContent = await fs.readFile(readmePath, 'utf-8'); if (deletedPaths.some(p => p.indexOf(`${codeFolder}/README.md`) !== -1)) { - console.log(`\n${chalk.black.bgYellow('found')} ${readmePath} and copies content to ${docsFolder}/README.md`); + console.log( + `\n${chalk.white.bgBlack(' README ')} ${chalk.dim(readmePath.replace('README.md', ''))}${chalk.bold( + 'README.md' + )} \u2192 ${chalk.dim(docsFolder)}${chalk.bold('/README.md')}` + ); } } catch (e) { - console.log(`${chalk.white.bgBlack('skipped')} copy README.md`); + console.log(`\n${chalk.white.bgBlack(' README ')} Add default README.md`); } - // Do nothing if README.md already exists try { - readMeContent = await fs.readFile(`${docsFolder}/README.md`, 'utf-8'); - console.log(`\n${chalk.yellow(`${docsFolder}/README.md already exists`)}`); + await fs.access(`${docsFolder}/README.md`); } catch (e) { await fs.writeFile(`${docsFolder}/README.md`, readMeContent); } @@ -136,270 +128,4 @@ export const generate = async (argv: Record) => { const resultTime = (Math.abs(startTime - +new Date()) / 1000).toFixed(2); console.log(`\n⏰ Time: ${resultTime}s\n`); - - // /** - // * Read all files in directory - // * @param {string} folder - // * @param {number} depth - // * @param {array} tree - // */ - // const readFiles = async (folder: string, depth: number, tree: any[]) => { - // try { - // // get all files - // const files = await fs.readdir(folder); - // const completeFolderPath = folder.replace(srcFolder, ''); - - // // if this is not a subdir - // let folderPath = docsFolder; - - // // generate correct docs folder path - // if (depth > 0) { - // folderPath += completeFolderPath; - // } - - // // iterate through all files in folder - // await asyncForEach(files, async file => { - // let isExcluded = false; - - // if (exclude && mm.isMatch(path.join(folder.replace(srcFolder, ''), file), exclude)) { - // console.log(chalk.reset.inverse.bold.blueBright(' EXCLUDE '), `${chalk.dim(folder)}/${chalk.bold(file)}`); - - // addToStatistics(file, 'exclude'); - // isExcluded = true; - // } - - // const stat = await fs.lstat(`${folder}/${file}`); - - // let fileName = getFilename(file); - - // // prefix index with unserscore, the generated index.html comes from vuepress - // if (fileName === 'index') { - // fileName = '_index'; - // } - - // if (stat.isDirectory()) { - // // check file length and skip empty folders - // try { - // let dirFiles = await fs.readdir(path.join(folder, file)); - - // dirFiles = dirFiles.filter(f => { - // return !mm.isMatch(path.join(folder.replace(srcFolder, ''), file, f), exclude); - // }); - - // if (dirFiles.length > 0) { - // await fs.mkdir(`${folderPath}/${file}`); - // } - - // addToStatistics(file, 'success', true); - // } catch (e) { - // const error = e as Record; - // console.log(error.message); - // console.log( - // chalk.yellow('cannot create folder, because it already exists'), - // `${chalk.dim(folderPath)}/${file}` - // ); - - // addToStatistics(file, 'error', true); - // } - - // // Add to tree - // tree.push({ - // name: file, - // children: [] - // }); - - // // read files from subfolder - // await readFiles(`${folder}/${file}`, depth + 1, tree.filter(treeItem => file === treeItem.name)[0].children); - // } - // // Else branch accessed when file is not a folder - // else if (!isExcluded) { - // // check if extension is correct - // if (checkExtension(file, extensions)) { - // const fileData = await fs.readFile(`${folder}/${file}`, 'utf8'); - // let mdFileData = ''; - - // if (/\.vue$/.test(file)) { - // // const rootProjectFolder = process.cwd(); - // // await vueDocgen({ - // // ...extractConfig(path.join(rootProjectFolder, folder)), - // // components: file, - // // outDir: path.join(rootProjectFolder, folderPath) - // // }); - // // // just a small workaround to get the written file - // // await new Promise(resolve => setTimeout(resolve, 200)); - // // mdFileData = await fs.readFile(`${path.join(rootProjectFolder, folderPath, fileName)}.md`, 'utf-8'); - // } else if (/\.(js|ts|jsx|tsx)$/.test(file) && fileData) { - // const configPath = argv.jsDocConfigPath; - - // try { - // // render file - // mdFileData = await jsdoc2md.render({ - // files: [`${folder}/${file}`], - // configure: configPath, - // partial: [ - // path.resolve(__filename, '../../template/header.hbs'), - // path.resolve(__filename, '../../template/main.hbs'), - // ...partials - // ] - // }); - // } catch (e) { - // const error = e as Record; - // const isConfigExclude = error.message.includes('no input files'); - - // console.log( - // chalk.reset.inverse.bold.red(isConfigExclude ? ' EXCLUDE BY CONFIG ' : ' ERROR '), - // `${chalk.dim(folder)}/${chalk.bold(file)} \u2192 ${chalk.dim(folderPath)}/${chalk.bold( - // fileName + '.md' - // )}` - // ); - - // if (!isConfigExclude) { - // console.log(error.message); - - // addToStatistics(file, 'error'); - // } - // } - // } - - // if (mdFileData) { - // const { frontmatter, attributes } = parseVuepressComment(fileData); - - // console.log( - // chalk.reset.inverse.bold.green(' SUCCESS '), - // `${chalk.dim(folder)}/${chalk.bold(file)} \u2192 ${chalk.dim(folderPath)}/${chalk.bold( - // fileName + '.md' - // )}` - // ); - - // let fileContent = '---\n'; - - // fileContent += !attributes?.title ? `title: ${fileName}` : ''; - - // if (frontmatter) { - // fileContent += !attributes?.title ? '\n' : ''; - // fileContent += `${frontmatter}`; - // } - - // fileContent += '\n---\n'; - // if (attributes?.title || !/\.vue$/.test(file)) { - // let headline = fileName; - - // if (attributes?.headline) { - // headline = attributes.headline; - // } else if (attributes?.title) { - // headline = attributes.title; - // } - - // fileContent += `\n# ${headline}\n\n`; - // } - // fileContent += mdFileData; - - // await fs.writeFile(`${folderPath}/${fileName}.md`, fileContent); - - // tree.push({ - // name: fileName, - // path: `/${fileName}`, - // fullPath: `${folderPath.replace(`${docsFolder}/`, '')}/${fileName}` - // }); - - // addToStatistics(file, 'success'); - // } else { - // console.log( - // chalk.reset.inverse.bold.yellow(' EMPTY '), - // `${chalk.dim(folder)}/${chalk.bold(file)} \u2192 ${chalk.dim(folderPath)}/${chalk.bold( - // fileName + '.md' - // )}` - // ); - - // addToStatistics(file, 'empty'); - // } - // } - // } - // }); - - // return Promise.resolve(files); - // } catch (e) { - // const error = e as Record; - // console.log(error); - // if (error.code === 'ENOENT') { - // console.log('cannot find source folder'); - // } else { - // console.log(error.message); - // } - // } - // }; - - // // create docs folder - // mkdirp(docsFolder).then(async () => { - // const startTime = +new Date(); - // // read folder files - // await readFiles(srcFolder, 0, fileTree); - - // await fs.writeFile( - // `${docsFolder}/config.js`, - // `exports.fileTree=${JSON.stringify(fileTree)};exports.sidebarTree = (title = 'Mainpage') => (${JSON.stringify( - // vueSidebar({ - // fileTree, - // codeFolder, - // title - // }) - // ).replace('::vuepress-jsdoc-title::', '"+title+"')});` - // ); - - // // create README.md - // let readMeContent = `### Welcome to ${title}`; - // const readmePath = readme || `${srcFolder}/README.md`; - - // try { - // readMeContent = await fs.readFile(readmePath, 'utf-8'); - // if (deletedPaths.some(p => p.indexOf(`${codeFolder}/README.md`) !== -1)) { - // console.log(`\n${chalk.black.bgYellow('found')} ${readmePath} and copies content to ${docsFolder}/README.md`); - // } - // } catch (e) { - // console.log(`${chalk.white.bgBlack('skipped')} copy README.md`); - // } - - // // Do nothing if README.md already exists - // try { - // readMeContent = await fs.readFile(`${docsFolder}/README.md`, 'utf-8'); - // console.log(`\n${chalk.yellow(`${docsFolder}/README.md already exists`)}`); - // } catch (e) { - // await fs.writeFile(`${docsFolder}/README.md`, readMeContent); - // } - - // const resultTime = (Math.abs(startTime - +new Date()) / 1000).toFixed(2); - - // // get longest type string - // const maxExtLength = Object.keys(statistics).length - // ? Math.max.apply( - // null, - // Object.keys(statistics).map(w => w.length) - // ) - // : 0; - - // const errorCount = Object.keys(statistics).reduce((b, c) => b + statistics[c].error, 0); - - // // iterate trough stats - // console.log(); - // Object.entries(statistics) - // .sort() - // .forEach(([extension, types]) => { - // const content = Object.keys(statusTypes) - // .map(key => types[key] && chalk[statusTypes[key]].bold(`${types[key]} ${key}`)) - // .filter(Boolean) - // .join(' '); - - // const total = Object.keys(statusTypes).reduce((before, curr) => before + types[curr], 0); - - // console.log( - // `${extension}${Array(Math.round(maxExtLength - extension.length + maxExtLength / 2)).join( - // ' ' - // )}| ${content} - ${total} total` - // ); - // }); - - // console.log(`\n⏰ Time: ${resultTime}s\n`); - - // process.exit(errorCount ? 1 : 0); - // }); }; diff --git a/src/lib/list-folder.ts b/src/lib/list-folder.ts index e281e0e..d2c886f 100644 --- a/src/lib/list-folder.ts +++ b/src/lib/list-folder.ts @@ -5,8 +5,16 @@ import path from 'path'; import { DirectoryFile } from '../interfaces'; -export const listFolder = async (srcPath: string, exclude: string[] = [], mainPath?: string) => { +interface FileTree { + name: string; + path?: string; + fullPath?: string; + children?: FileTree[]; +} + +export const listFolder = async (srcPath: string, exclude: string[] = [], mainPath?: string, tree: FileTree[] = []) => { const paths: DirectoryFile[] = []; + const dirs = await fs.readdir(srcPath, { withFileTypes: true }); @@ -17,15 +25,26 @@ export const listFolder = async (srcPath: string, exclude: string[] = [], mainPa const ext = path.extname(filePath); let name = path.basename(filePath).replace(ext, ''); - if (!mm.isMatch(path.join(srcPath.replace(mainPath || srcPath, ''), dirent.name), exclude)) { - if (isDir) { - paths.push(...(await listFolder(filePath, exclude, mainPath || srcPath))); - } + // skip readmes as they are automatically resolved + if (name.toLowerCase() === 'readme') continue; + if (!mm.isMatch(path.join(srcPath.replace(mainPath || srcPath, ''), dirent.name), exclude)) { if (name === 'index') { name = '_index'; } + const treeEntry: FileTree = { + name, + ...(!isDir ? { path: `/${name}`, fullPath: path.join(srcPath, name) } : {}) + }; + + tree.push(treeEntry); + + if (isDir) { + treeEntry.children = []; + paths.push(...(await listFolder(filePath, exclude, mainPath || srcPath, treeEntry.children)).paths); + } + paths.push({ isDir, name, @@ -38,5 +57,5 @@ export const listFolder = async (srcPath: string, exclude: string[] = [], mainPa } } - return paths; + return { paths, tree }; }; diff --git a/src/lib/parser.ts b/src/lib/parser.ts index 090c740..f2711a5 100644 --- a/src/lib/parser.ts +++ b/src/lib/parser.ts @@ -5,6 +5,7 @@ import { join, resolve } from 'path'; import compileTemplates from 'vue-docgen-cli/lib/compileTemplates'; import { extractConfig } from 'vue-docgen-cli/lib/docgen'; +import { StatisticType } from '../constants'; import { DirectoryFile } from '../interfaces'; import { parseVuepressFileHeader } from './comment-parser'; @@ -47,14 +48,14 @@ export const parseFile = async ( ] }); - if (content) { - fileContent = parseVuepressFileHeader( - await fs.readFile(`${join(folderInSrc, file.name + file.ext)}`, 'utf-8'), - file - ); - fileContent += content; - } - } catch { + fileContent = parseVuepressFileHeader( + await fs.readFile(`${join(folderInSrc, file.name + file.ext)}`, 'utf-8'), + file + ); + + fileContent += content; + } catch (e) { + console.log(e); success = false; } @@ -96,15 +97,14 @@ export const parseVueFile = async ( file.name + file.ext ); - if (data.content) { - fileContent = parseVuepressFileHeader( - await fs.readFile(`${join(folderInSrc, file.name + file.ext)}`, 'utf-8'), - file - ); + fileContent = parseVuepressFileHeader( + await fs.readFile(`${join(folderInSrc, file.name + file.ext)}`, 'utf-8'), + file + ); - fileContent += data.content; - } - } catch { + fileContent += data.content; + } catch (e) { + console.log(e); success = false; } @@ -118,30 +118,27 @@ export const parseVueFile = async ( }; }; -export const writeContentToFile = async (file: Promise) => { - const data = await file; - let type = data?.success ? 'empty' : 'error'; +export const writeContentToFile = async (parseData: ParseReturn | null, dest: string) => { + const root = process.cwd(); + dest = join(root, dest); + + let type = parseData?.success ? StatisticType.EMPTY : StatisticType.ERROR; try { - if (data && data?.content) { - const path = `${join(data.dest, data.file.name)}.md`; + if (parseData?.content) { + const path = `${join(dest, parseData.file.name)}.md`; - await mkdirp(data?.dest); - await fs.writeFile(path, data.content, 'utf-8'); + await mkdirp(dest); + await fs.writeFile(path, parseData.content, 'utf-8'); - type = 'success'; + type = StatisticType.SUCCESS; } return { - ...data, + ...parseData, type }; - } catch { - type = 'error'; - } + } catch {} - return { - ...data, - type - }; + return null; }; diff --git a/src/lib/vue-sidebar.ts b/src/lib/vue-sidebar.ts index 944e646..570536e 100644 --- a/src/lib/vue-sidebar.ts +++ b/src/lib/vue-sidebar.ts @@ -1,4 +1,4 @@ -// create vuepress sidebar +import { join } from 'path'; interface Node { name: string; children: any[]; @@ -7,10 +7,12 @@ interface Node { export const generateVueSidebar = ({ fileTree, codeFolder, + srcFolder, title }: { fileTree: any; codeFolder: string; + srcFolder: string; title: string; }) => { let rootFiles = [['', '::vuepress-jsdoc-title::']]; @@ -25,7 +27,7 @@ export const generateVueSidebar = ({ if (child.children && child.children.length > 0) { newChildren = newChildren.concat(buildChildren(child.children, child.name, depth + 1)); } else if (child.fullPath) { - newChildren.push(child.fullPath); + newChildren.push(child.fullPath.replace(`${srcFolder}/`, '')); } });