Repository: Kocal/jsdoc-vuejs
Branch: master
Commit: e73bd4f74bfd
Files: 59
Total size: 93.3 KB
Directory structure:
gitextract_1cmywy0n/
├── .eslintrc.json
├── .github/
│ ├── FUNDING.yml
│ └── workflows/
│ ├── ci.yml
│ └── release.yml
├── .gitignore
├── .releaserc
├── LICENSE
├── README.md
├── UPGRADE.md
├── __tests__/
│ ├── core/
│ │ ├── __fixtures__/
│ │ │ ├── Component.vue
│ │ │ └── methods/
│ │ │ ├── Component/
│ │ │ │ └── Component.js
│ │ │ ├── Component.vue
│ │ │ ├── ComponentWithExportDefaultInTemplate.vue
│ │ │ ├── ComponentWithSpaces.vue
│ │ │ └── ScriptBeforeTemplate.vue
│ │ ├── __snapshots__/
│ │ │ └── vueScriptExtractor.js.snap
│ │ ├── getTemplatePath.test.js
│ │ ├── renderer.test.js
│ │ ├── seekExportDefaultLine.js
│ │ └── vueScriptExtractor.js
│ └── stubs/
│ └── jsdoc/
│ └── lib/
│ └── jsdoc/
│ └── util/
│ └── templateHelper.js
├── config.js
├── cypress/
│ ├── fixtures/
│ │ └── example.json
│ ├── integration/
│ │ └── templates/
│ │ ├── default.spec.js
│ │ ├── docstrap.spec.js
│ │ ├── minami.spec.js
│ │ └── tui.spec.js
│ ├── plugins/
│ │ └── index.js
│ └── support/
│ ├── commands.js
│ └── index.js
├── cypress.json
├── example/
│ ├── .jsdoc-docstrap.js
│ ├── .jsdoc-minami.js
│ ├── .jsdoc-tui.js
│ ├── .jsdoc.js
│ ├── README.md
│ ├── package.json
│ └── src/
│ ├── Counter.vue
│ ├── better-components/
│ │ └── BetterCounter.vue
│ └── js/
│ ├── CounterJS.js
│ ├── NotVueComponent.js
│ └── NotVueComponent2.js
├── index.js
├── jest.config.js
├── lib/
│ ├── core/
│ │ ├── getTemplatePath.js
│ │ ├── issers.js
│ │ ├── renderer.js
│ │ ├── seekExportDefaultLine.js
│ │ └── vueScriptExtractor.js
│ ├── tags/
│ │ ├── vue-computed.js
│ │ ├── vue-data.js
│ │ ├── vue-event.js
│ │ └── vue-prop.js
│ └── templates/
│ ├── default.ejs
│ ├── docstrap.ejs
│ ├── minami.ejs
│ ├── tui.ejs
│ └── utils/
│ └── renderType.js
└── package.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintrc.json
================================================
{
"extends": [
"airbnb-base"
],
"env": {
"es6": true,
"node": true,
"jest": true,
"cypress/globals": true
},
"plugins": [
"cypress"
],
"settings": {
"import/core-modules": [
"jsdoc/env"
]
},
"rules": {
"no-param-reassign": ["error", {
"props": true,
"ignorePropertyModificationsFor": [
"doclet", // _isVueFile, ...
"e" // for e.doclet
]
}],
"no-underscore-dangle": ["error", {
"allow": [
"_isVueDoc",
"_vueProps",
"_vueData",
"_vueComputed",
"_vueEvent"
]
}]
}
}
================================================
FILE: .github/FUNDING.yml
================================================
github: Kocal
custom: paypal.me/HAlliaume
================================================
FILE: .github/workflows/ci.yml
================================================
name: Node CI
on:
pull_request:
branches:
- '*'
jobs:
ci:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
node-version: [10.x, 12.x, 14.x]
include:
- os: windows-latest
node: 12.x
steps:
- name: Set git to use LF
run: |
git config --global core.autocrlf false
git config --global core.eol lf
if: matrix.os == 'windows-latest'
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Get yarn cache directory
id: yarn-cache
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Restore yarn cache (if available)
uses: actions/cache@v1
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- run: yarn install --frozen-lockfile
- run: |
cd example
yarn install --frozen-lockfile
yarn docs
yarn docs:docstrap
yarn docs:minami
yarn docs:tui
cd ..
- run: yarn lint
- run: yarn test -i && npx codecov
================================================
FILE: .github/workflows/release.yml
================================================
name: Release
on:
push:
branches:
- master
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Node.js
uses: actions/setup-node@v1
with:
node-version: 12.x
- run: yarn install --frozen-lockfile
- run: yarn semantic-release
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
example/docs*
cypress/screenshots/
cypress/videos/
================================================
FILE: .releaserc
================================================
{
"extends": "@kocal/semantic-release-preset"
}
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2018 Hugo Alliaume
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
JSDoc for VueJS
===============
[](https://badge.fury.io/js/jsdoc-vuejs)
[](https://travis-ci.org/Kocal/jsdoc-vuejs)
[](https://ci.appveyor.com/project/Kocal/jsdoc-vuejs)
[](https://codecov.io/gh/Kocal/jsdoc-vuejs)
[](https://www.codacy.com/app/kocal/jsdoc-vuejs?utm_source=github.com&utm_medium=referral&utm_content=Kocal/jsdoc-vuejs&utm_campaign=Badge_Grade)
A JSDoc plugin for listing props, data, computed data, and methods from `.vue` files.
:warning: This branch is for Vue 3. If you still use Vue 2, please see [`3.x` branch](https://github.com/Kocal/jsdoc-vuejs/tree/3.x).
---
## Requirements
- Node 10+
- Vue 3
## Installation
```bash
$ npm install --save-dev jsdoc jsdoc-vuejs
```
You also need to install `@vue/compiler-sfc` that match your Vue version:
```bash
$ npm install --save-dev @vue/compiler-sfc
```
## Usage
Your should update your JSDoc configuration to enable JSDoc-VueJS:
```json
{
"plugins": [
"node_modules/jsdoc-vuejs"
],
"source": {
"includePattern": "\\.(vue|js)$"
}
}
```
Update your .vue files with one of the following tags:
- `@vue-prop`
- `@vue-data`
- `@vue-computed`
- `@vue-event`
All of those tags work the same way than [`@param` tag](http://usejsdoc.org/tags-param.html).
```vue
<template>
<div>Hello world!</div>
</template>
<script>
/**
* @vue-prop {Number} initialCounter - Initial counter's value
* @vue-prop {Number} [step=1] - Step
* @vue-data {Number} counter - Current counter's value
* @vue-computed {String} message
* @vue-event {Number} increment - Emit counter's value after increment
* @vue-event {Number} decrement - Emit counter's value after decrement
*/
export default {
props: {
initialCounter: {
type: Number,
required: true,
},
step: {
type: Number,
default: 1,
},
},
data () {
return {
counter: 0,
}
},
computed: {
message() {
return `Current value is ${this.counter}`;
}
},
methods: {
increment() {
this.counter += 1;
this.$emit('increment', this.counter);
},
decrement() {
this.counter -= 1;
this.$emit('decrement', this.counter);
}
}
}
</script>
```
## Supported templates
The rendering engine has been rewritten in v2, it can supports every JSDoc templates that exists.
Actually, it supports 4 templates:
- Default
- [Docstrap](https://github.com/docstrap/docstrap)
- [Minami](https://github.com/nijikokun/minami)
- [Tui](https://github.com/nhnent/tui.jsdoc-template)
If you use a template that is not supported, it will use the default one as a fallback.
Feel free to open an issue/pull request if your template is not supported!
<details>
<summary>Default</summary>

</details>
<details>
<summary>Docstrap</summary>

</details>
<details>
<summary>Minami</summary>

</details>
<details>
<summary>Tui</summary>

</details>
## Testing
### Install Dependencies
```bash
$ git clone https://github.com/Kocal/jsdoc-vuejs
$ cd jsdoc-vuejs
$ yarn install
# For testing the example docs
$ cd example
$ yarn install
```
#### Generate documentations
```bash
$ cd example
# Generate docs for every renderer
$ yarn docs:all
# or one by one
$ yarn docs # default jsdoc template
$ yarn docs:docstrap
$ yarn docs:minami
$ yarn docs:tui
```
### Unit
```bash
$ yarn test
```
### E2E
Before running integration tests with [Cypress](https://cypress.io),
you should generate documentation with all renderers:
```bash
$ cd example
$ yarn docs:all
```
And then run Cypress:
```bash
$ cd ..
$ yarn cypress run
```
## License
MIT.
================================================
FILE: UPGRADE.md
================================================
## Upgrade from 1.x to 2.x
### Configuration
You MUST remove `jsdoc-vuejs` configuration key inside JSDoc config file,
because it is not used anymore.
**Before:**
```json
{
"plugins": [
"node_modules/jsdoc-vuejs"
],
"source": {
"includePattern": "\\.(vue|js)$"
},
"jsdoc-vuejs": {
"followImports": true // enable/disable require/import function
}
}
```
**After:**
```json
{
"plugins": [
"node_modules/jsdoc-vuejs"
],
"source": {
"includePattern": "\\.(vue|js)$"
}
}
```
### Usage
You SHOULD NOT use `@vue` tag anymore.
Instead, you should use `@vue-prop`, `@vue-data`, and `@vue-computed` like this:
```vue
<template>
<div>Hello world</div>
</template>
<script>
/**
* @vue-prop {Number} initialCounter
* @vue-prop {Number} [step=1] Step
* @vue-data {Number} counter - Current counter's value
* @vue-computed {String} message A message
*/
export default {
// ...
}
</script>
```
================================================
FILE: __tests__/core/__fixtures__/Component.vue
================================================
<template>
<div>Hello world</div>
</template>
<script>
/**
* @vue-data {String} [foo=bar] Foo description
*/
export default {
name: 'Component',
data() {
return {
foo: 'bar'
}
}
}
</script>
================================================
FILE: __tests__/core/__fixtures__/methods/Component/Component.js
================================================
/**
* @vue-prop {String} test - test description
* @vue-data {String} [foo=bar] - Foo description
*/
export default ({
name: 'component',
props: {
test: {
type: String,
},
},
data() {
return {
foo: 'bar',
};
},
methods: {},
computed: {},
});
================================================
FILE: __tests__/core/__fixtures__/methods/Component.vue
================================================
<template>
<div>Hello world</div>
</template>
<script>
/**
* My component
*/
export default {
name: 'Component',
methods: {
/**
* Show a dialog
*/
showDialog() {
// ...
}
}
};
</script>
================================================
FILE: __tests__/core/__fixtures__/methods/ComponentWithExportDefaultInTemplate.vue
================================================
<template>
<div>export default</div>
</template>
<script>
export default {
name: 'Component',
methods: {
/**
* Show a dialog
*/
showDialog() {
// ...
}
}
};
</script>
================================================
FILE: __tests__/core/__fixtures__/methods/ComponentWithSpaces.vue
================================================
<template>
<div>Hello world</div>
</template>
<script>
export default
{
name: 'Component',
methods: {
/**
* Show a dialog
*/
showDialog() {
// ...
}
}
};
</script>
================================================
FILE: __tests__/core/__fixtures__/methods/ScriptBeforeTemplate.vue
================================================
<script>
/**
* @vue-data {String} [foo=bar] Foo description
*/
export default {
name: 'ScriptBeforeTemplate',
data() {
return {
foo: 'bar'
};
}
};
</script>
<template>
<div>Hello world!</div>
</template>
================================================
FILE: __tests__/core/__snapshots__/vueScriptExtractor.js.snap
================================================
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`core.extractVueScript extract script 1`] = `
"
/**
* @vue-data {String} [foo=bar] Foo description
*/
export default {
name: 'Component',
data() {
return {
foo: 'bar'
}
}
}
"
`;
================================================
FILE: __tests__/core/getTemplatePath.test.js
================================================
/* eslint-disable no-console */
const { normalize } = require('path');
const getTemplatePath = require('../../lib/core/getTemplatePath');
describe('guessTemplatePath', () => {
test('guess default', () => {
expect(getTemplatePath().endsWith(normalize('lib/templates/default.ejs'))).toBeTruthy();
expect(getTemplatePath('default').endsWith(normalize('lib/templates/default.ejs'))).toBeTruthy();
});
test('guess docstrap', () => {
const templatePath = getTemplatePath('./node_modules/ink-docstrap/template');
expect(templatePath.endsWith(normalize('lib/templates/docstrap.ejs'))).toBeTruthy();
});
test('guess minami', () => {
const templatePath = getTemplatePath('node_modules/minami');
expect(templatePath.endsWith(normalize('lib/templates/minami.ejs'))).toBeTruthy();
});
test('guess tui', () => {
const templatePath = getTemplatePath('node_modules/tui-jsdoc-template');
expect(templatePath.endsWith(normalize('lib/templates/tui.ejs'))).toBeTruthy();
});
test('guess unsupported', () => {
console.warn = jest.fn();
expect(getTemplatePath('foo-bar').endsWith(normalize('lib/templates/default.ejs'))).toBeTruthy();
expect(console.warn).toHaveBeenCalledWith('The template "foo-bar" is not recognized by jsdoc-vuejs. Using default template as fallback.');
});
});
================================================
FILE: __tests__/core/renderer.test.js
================================================
const ejs = require('ejs');
const renderer = require('../../lib/core/renderer');
describe('code.renderer', () => {
beforeEach(() => {
ejs.renderFile = jest.fn();
});
it('should call ejs render method', () => {
const cb = () => {};
renderer('my-template', {
props: ['props'], data: ['data'], computed: ['computed'], event: ['event'],
}, cb);
expect(ejs.renderFile).toHaveBeenCalledTimes(1);
expect(ejs.renderFile).toHaveBeenCalledWith(
'my-template',
{
props: ['props'],
data: ['data'],
computed: ['computed'],
event: ['event'],
// an helper function, it should be under keys "utils" or "helpers" btw
renderType: expect.any(Function),
},
cb,
);
});
});
================================================
FILE: __tests__/core/seekExportDefaultLine.js
================================================
const path = require('path');
const fs = require('fs');
const seekExportDefaultLine = require('../../lib/core/seekExportDefaultLine');
const readComponent = (componentPath, cb) => {
const filename = path.join(__dirname, `__fixtures__/methods/${componentPath}`);
fs.readFile(filename, 'utf8', (err, source) => cb(source));
};
describe('core.seekExportDefaultLine', () => {
test('A normal component', (done) => {
readComponent('Component.vue', (source) => {
expect(seekExportDefaultLine(source)).toBe(9);
done();
});
});
test('A normal component with a lot of spaces', (done) => {
readComponent('ComponentWithSpaces.vue', (source) => {
expect(seekExportDefaultLine(source)).toBe(14);
done();
});
});
test('When <script> is before <template>', (done) => {
readComponent('ScriptBeforeTemplate.vue', (source) => {
expect(seekExportDefaultLine(source)).toBe(5);
done();
});
});
test('When `export default` is inside <template>', (done) => {
readComponent('ComponentWithExportDefaultInTemplate.vue', (source) => {
expect(seekExportDefaultLine(source)).toBe(6);
done();
});
});
test('When component is js file', (done) => {
readComponent('Component/Component.js', (source) => {
expect(seekExportDefaultLine(source, 'Component.js')).toBe(6);
done();
});
});
});
================================================
FILE: __tests__/core/vueScriptExtractor.js
================================================
const path = require('path');
const extractVueScript = require('../../lib/core/vueScriptExtractor');
describe('core.extractVueScript', () => {
const filename = path.join(__dirname, '__fixtures__', 'Component.vue');
test('extract script', () => {
expect(extractVueScript(filename)).toMatchSnapshot();
});
});
================================================
FILE: __tests__/stubs/jsdoc/lib/jsdoc/util/templateHelper.js
================================================
// Actually stub this module, to prevent follow error:
// "Cannot find module 'jsdoc/tag/dictionary' from 'templateHelper.js'" :)
module.exports = {};
================================================
FILE: config.js
================================================
const env = require('jsdoc/env');
const getTemplatePath = require('./lib/core/getTemplatePath');
const config = env.conf || {};
config['jsdoc-vuejs'] = config['jsdoc-vuejs'] || {};
// Detect JSDoc template if not specified
if (!Object.prototype.hasOwnProperty.call(config['jsdoc-vuejs'], 'template')) {
config['jsdoc-vuejs'].template = getTemplatePath(env.opts.template || 'default');
}
module.exports = config;
================================================
FILE: cypress/fixtures/example.json
================================================
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}
================================================
FILE: cypress/integration/templates/default.spec.js
================================================
/* eslint-disable newline-per-chained-call */
describe('Template: default', () => {
before(() => {
cy.visit('/../../../example/docs/module-better-components_BetterCounter.html');
cy.screenshot();
});
it('should renders module name correctly', () => {
cy
.get('.page-title')
.contains('Module: better-components/BetterCounter');
cy
.get('nav a[href="module-better-components_BetterCounter.html"]')
.contains('better-components/BetterCounter');
});
it('should renders @desc properly', () => {
cy
.get('.container-overview')
.contains('BetterCounter component, like Counter component but better');
});
it('should renders props correctly', () => {
const props = [
{
name: '<code>initialCounter</code>',
type: 'Number',
defaultValue: '-',
required: '<b>Yes</b>',
description: '-',
},
{
name: '<code>step</code>',
type: 'Number',
defaultValue: '<code>1</code>',
required: 'No',
description: 'Step',
},
];
cy.get('[data-jsdoc-vuejs="section-props"]').contains('Props');
cy.get('[data-jsdoc-vuejs="table-props"]').as('table-props');
cy
.get('@table-props')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Default value')
.next().contains('Required?')
.next().contains('Description');
cy
.get('@table-props')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(2);
props.forEach((prop, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(prop.name);
expect($children.eq(1).html()).to.eq(prop.type);
expect($children.eq(2).html()).to.eq(prop.defaultValue);
expect($children.eq(3).html()).to.eq(prop.required);
expect($children.eq(4).html()).to.eq(prop.description);
});
});
});
it('should renders data correctly', () => {
const data = [
{
name: '<code>counter</code>',
type: 'Number',
defaultValue: '-',
description: "Current counter's value",
},
];
cy.get('[data-jsdoc-vuejs="section-data"]').contains('Data');
cy.get('[data-jsdoc-vuejs="table-data"]').as('table-data');
cy
.get('@table-data')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Default value')
.next().contains('Description');
cy
.get('@table-data')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(1);
data.forEach((d, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(d.name);
expect($children.eq(1).html()).to.eq(d.type);
expect($children.eq(2).html()).to.eq(d.defaultValue);
expect($children.eq(3).html()).to.eq(d.description);
});
});
});
it('should renders computed correctly', () => {
const computeds = [
{ name: '<code>fooList</code>', type: 'Array.<String>', description: 'A list of foo' },
{ name: '<code>barList</code>', type: 'Array.<String>', description: 'A list of bar' },
{ name: '<code>message</code>', type: 'String', description: 'A message' },
];
cy.get('[data-jsdoc-vuejs="section-computed"]').contains('Computed');
cy.get('[data-jsdoc-vuejs="table-computed"]').as('table-computed');
cy
.get('@table-computed')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Description');
cy
.get('@table-computed')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(3);
computeds.forEach((computed, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(computed.name);
expect($children.eq(1).html()).to.eq(computed.type);
expect($children.eq(2).html()).to.eq(computed.description);
});
});
});
it('should renders event correctly', () => {
const events = [
{ name: '<code>increment</code>', type: 'Number', description: "Emit counter's value after increment" },
{ name: '<code>decrement</code>', type: 'Number', description: "Emit counter's value after decrement" },
];
cy.get('[data-jsdoc-vuejs="section-event"]').contains('Events');
cy.get('[data-jsdoc-vuejs="table-event"]').as('table-event');
cy
.get('@table-event')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Payload Type')
.next().contains('Description');
cy
.get('@table-event')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(2);
events.forEach((event, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(event.name);
expect($children.eq(1).html()).to.eq(event.type);
expect($children.eq(2).html()).to.eq(event.description);
});
});
});
it('should render methods properly', () => {
cy.contains('h3', 'Methods').should('have.attr', 'class', 'subsection-title');
cy.get('#decrement')
.contains('decrement()')
.next('.description')
.next('.details')
.contains('a[href="better-components_BetterCounter.vue.html#line56"]', 'line 56');
cy.get('#increment')
.contains('increment()')
.next('.description')
.next('.details')
.contains('a[href="better-components_BetterCounter.vue.html#line48"]', 'line 48');
cy.get('#showDialog')
.contains('showDialog(counter)')
.next('.description')
.next('h5')
.next('.params')
.next('.details')
.contains('a[href="better-components_BetterCounter.vue.html#line65"]', 'line 65');
cy.contains('created()').should('not.exist');
});
});
describe('Template JS: default', () => {
/* eslint-disable newline-per-chained-call */
before(() => {
cy.visit('/../../../example/docs/module-CounterJS.html');
cy.screenshot();
});
it('should renders module name correctly', () => {
cy
.get('.page-title')
.contains('Module: CounterJS');
cy
.get('nav a[href="module-CounterJS.html"]')
.contains('CounterJS');
});
it('should renders props correctly', () => {
const props = [
{
name: '<code>initialCounter</code>',
type: 'Number',
defaultValue: '-',
required: '<b>Yes</b>',
description: '-',
},
{
name: '<code>step</code>',
type: 'Number',
defaultValue: '<code>1</code>',
required: 'No',
description: 'Step',
},
];
cy.get('[data-jsdoc-vuejs="section-props"]').contains('Props');
cy.get('[data-jsdoc-vuejs="table-props"]').as('table-props');
cy
.get('@table-props')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Default value')
.next().contains('Required?')
.next().contains('Description');
cy
.get('@table-props')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(2);
props.forEach((prop, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(prop.name);
expect($children.eq(1).html()).to.eq(prop.type);
expect($children.eq(2).html()).to.eq(prop.defaultValue);
expect($children.eq(3).html()).to.eq(prop.required);
expect($children.eq(4).html()).to.eq(prop.description);
});
});
});
it('should renders data correctly', () => {
const data = [
{
name: '<code>counter</code>',
type: 'Number',
defaultValue: '-',
description: "Current counter's value",
},
];
cy.get('[data-jsdoc-vuejs="section-data"]').contains('Data');
cy.get('[data-jsdoc-vuejs="table-data"]').as('table-data');
cy
.get('@table-data')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Default value')
.next().contains('Description');
cy
.get('@table-data')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(1);
data.forEach((d, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(d.name);
expect($children.eq(1).html()).to.eq(d.type);
expect($children.eq(2).html()).to.eq(d.defaultValue);
expect($children.eq(3).html()).to.eq(d.description);
});
});
});
it('should renders computed correctly', () => {
const computeds = [
{ name: '<code>fooList</code>', type: 'Array.<String>', description: 'A list of foo' },
{ name: '<code>barList</code>', type: 'Array.<String>', description: 'A list of bar' },
{ name: '<code>message</code>', type: 'String', description: 'A message' },
];
cy.get('[data-jsdoc-vuejs="section-computed"]').contains('Computed');
cy.get('[data-jsdoc-vuejs="table-computed"]').as('table-computed');
cy
.get('@table-computed')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Description');
cy
.get('@table-computed')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(3);
computeds.forEach((computed, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(computed.name);
expect($children.eq(1).html()).to.eq(computed.type);
expect($children.eq(2).html()).to.eq(computed.description);
});
});
});
it('should render methods properly', () => {
cy.contains('h3', 'Methods').should('have.attr', 'class', 'subsection-title');
cy.get('#decrement')
.contains('decrement()')
.next('.description')
.next('.details')
.contains('a[href="js_CounterJS.js.html#line43"]', 'line 43');
cy.get('#increment')
.contains('increment()')
.next('.description')
.next('.details')
.contains('a[href="js_CounterJS.js.html#line36"]', 'line 36');
cy.get('#showDialog')
.contains('showDialog(counter)')
.next('.description')
.next('h5')
.next('.params')
.next('.details')
.contains('a[href="js_CounterJS.js.html#line51"]', 'line 51');
cy.contains('created()').should('not.exist');
});
});
describe('JS files rendered or not as Vue Component', () => {
before(() => {
cy.visit('/../../../example/docs/index.html');
cy.screenshot();
});
it('NotVueComponent should not be rendered as Vue component', () => {
cy.get('nav > ul > li a[href="global.html#helloWorld"]').contains('helloWorld');
cy.get('nav > ul > li a[href="module-NotVueComponent.html"]').should('not.exist');
});
it('NotVueComponent2 should not be rendered as Vue component', () => {
cy.visit('/../../../example/docs/module-NotVueComponent2.html');
cy.get('nav > ul > li a[href="module-NotVueComponent2.html"]').contains('NotVueComponent2');
cy
.contains('h3', 'Methods')
.should('have.attr', 'class', 'subsection-title')
.next()
.contains('theMethod')
.next('h5')
.next('.params')
.next('.details')
.contains('a[href="js_NotVueComponent2.js.html#line11"]', 'line 11');
});
});
================================================
FILE: cypress/integration/templates/docstrap.spec.js
================================================
/* eslint-disable newline-per-chained-call */
describe('Template: docstrap', () => {
before(() => {
cy.visit('/../../../example/docs-docstrap/module-better-components_BetterCounter.html');
cy.screenshot();
});
it('should renders module name correctly', () => {
cy
.get('.page-title')
.contains('Module: better-components/BetterCounter');
cy
.get('.nav .dropdown a[href="module-better-components_BetterCounter.html"]')
.contains('better-components/BetterCounter');
});
it('should renders @desc properly', () => {
cy
.get('.container-overview')
.contains('BetterCounter component, like Counter component but better');
});
it('should renders props correctly', () => {
const props = [
{
name: '<code>initialCounter</code>',
type: 'Number',
defaultValue: '-',
required: '<b>Yes</b>',
description: '-',
},
{
name: '<code>step</code>',
type: 'Number',
defaultValue: '<code>1</code>',
required: 'No',
description: 'Step',
},
];
cy.get('[data-jsdoc-vuejs="section-props"]').contains('Props').should('have.class', 'subsection-title');
cy.get('[data-jsdoc-vuejs="table-props"]').as('table-props').should('have.class', 'table table-responsive table-hover table-striped');
cy
.get('@table-props')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Default value')
.next().contains('Required?')
.next().contains('Description');
cy
.get('@table-props')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(2);
props.forEach((prop, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(prop.name);
expect($children.eq(1).html()).to.eq(prop.type);
expect($children.eq(2).html()).to.eq(prop.defaultValue);
expect($children.eq(3).html()).to.eq(prop.required);
expect($children.eq(4).html()).to.eq(prop.description);
});
});
});
it('should renders data correctly', () => {
const data = [
{
name: '<code>counter</code>',
type: 'Number',
defaultValue: '-',
description: "Current counter's value",
},
];
cy.get('[data-jsdoc-vuejs="section-data"]').contains('Data').should('have.class', 'subsection-title');
cy.get('[data-jsdoc-vuejs="table-data"]').as('table-data').should('have.class', 'table table-responsive table-hover table-striped');
cy
.get('@table-data')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Default value')
.next().contains('Description');
cy
.get('@table-data')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(1);
data.forEach((d, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(d.name);
expect($children.eq(1).html()).to.eq(d.type);
expect($children.eq(2).html()).to.eq(d.defaultValue);
expect($children.eq(3).html()).to.eq(d.description);
});
});
});
it('should renders computed correctly', () => {
const computeds = [
{ name: '<code>fooList</code>', type: 'Array.<String>', description: 'A list of foo' },
{ name: '<code>barList</code>', type: 'Array.<String>', description: 'A list of bar' },
{ name: '<code>message</code>', type: 'String', description: 'A message' },
];
cy.get('[data-jsdoc-vuejs="section-computed"]').contains('Computed').should('have.class', 'subsection-title');
cy.get('[data-jsdoc-vuejs="table-computed"]').as('table-computed').should('have.class', 'table table-responsive table-hover table-striped');
cy
.get('@table-computed')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Description');
cy
.get('@table-computed')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(3);
computeds.forEach((computed, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(computed.name);
expect($children.eq(1).html()).to.eq(computed.type);
expect($children.eq(2).html()).to.eq(computed.description);
});
});
});
it('should renders event correctly', () => {
const events = [
{ name: '<code>increment</code>', type: 'Number', description: "Emit counter's value after increment" },
{ name: '<code>decrement</code>', type: 'Number', description: "Emit counter's value after decrement" },
];
cy.get('[data-jsdoc-vuejs="section-event"]').contains('Events');
cy.get('[data-jsdoc-vuejs="table-event"]').as('table-event');
cy
.get('@table-event')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Payload Type')
.next().contains('Description');
cy
.get('@table-event')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(2);
events.forEach((event, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(event.name);
expect($children.eq(1).html()).to.eq(event.type);
expect($children.eq(2).html()).to.eq(event.description);
});
});
});
it('should render methods properly', () => {
cy.contains('h3', 'Methods').should('have.attr', 'class', 'subsection-title');
cy.get('#decrement')
.contains('decrement()')
.parent()
.next('dd')
.find('.details')
.contains('a[href="better-components_BetterCounter.vue.html#sunlight-1-line-56"]', 'line 56');
cy.get('#increment')
.contains('increment()')
.parent()
.next('dd')
.find('.details')
.contains('a[href="better-components_BetterCounter.vue.html#sunlight-1-line-48"]', 'line 48');
cy.get('#showDialog')
.contains('showDialog(counter)')
.parent()
.next('dd')
.find('.details')
.contains('a[href="better-components_BetterCounter.vue.html#sunlight-1-line-65"]', 'line 65');
cy.contains('created()').should('not.exist');
});
});
describe('Template JS: docstrap', () => {
before(() => {
cy.visit('/../../../example/docs-docstrap/module-CounterJS.html');
cy.screenshot();
});
it('should renders module name correctly', () => {
cy
.get('.page-title')
.contains('Module: CounterJS');
cy
.get('.nav .dropdown a[href="module-CounterJS.html"]')
.contains('CounterJS');
});
it('should renders props correctly', () => {
const props = [
{
name: '<code>initialCounter</code>',
type: 'Number',
defaultValue: '-',
required: '<b>Yes</b>',
description: '-',
},
{
name: '<code>step</code>',
type: 'Number',
defaultValue: '<code>1</code>',
required: 'No',
description: 'Step',
},
];
cy.get('[data-jsdoc-vuejs="section-props"]').contains('Props').should('have.class', 'subsection-title');
cy.get('[data-jsdoc-vuejs="table-props"]').as('table-props').should('have.class', 'table table-responsive table-hover table-striped');
cy
.get('@table-props')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Default value')
.next().contains('Required?')
.next().contains('Description');
cy
.get('@table-props')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(2);
props.forEach((prop, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(prop.name);
expect($children.eq(1).html()).to.eq(prop.type);
expect($children.eq(2).html()).to.eq(prop.defaultValue);
expect($children.eq(3).html()).to.eq(prop.required);
expect($children.eq(4).html()).to.eq(prop.description);
});
});
});
it('should renders data correctly', () => {
const data = [
{
name: '<code>counter</code>',
type: 'Number',
defaultValue: '-',
description: "Current counter's value",
},
];
cy.get('[data-jsdoc-vuejs="section-data"]').contains('Data').should('have.class', 'subsection-title');
cy.get('[data-jsdoc-vuejs="table-data"]').as('table-data').should('have.class', 'table table-responsive table-hover table-striped');
cy
.get('@table-data')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Default value')
.next().contains('Description');
cy
.get('@table-data')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(1);
data.forEach((d, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(d.name);
expect($children.eq(1).html()).to.eq(d.type);
expect($children.eq(2).html()).to.eq(d.defaultValue);
expect($children.eq(3).html()).to.eq(d.description);
});
});
});
it('should renders computed correctly', () => {
const computeds = [
{ name: '<code>fooList</code>', type: 'Array.<String>', description: 'A list of foo' },
{ name: '<code>barList</code>', type: 'Array.<String>', description: 'A list of bar' },
{ name: '<code>message</code>', type: 'String', description: 'A message' },
];
cy.get('[data-jsdoc-vuejs="section-computed"]').contains('Computed').should('have.class', 'subsection-title');
cy.get('[data-jsdoc-vuejs="table-computed"]').as('table-computed').should('have.class', 'table table-responsive table-hover table-striped');
cy
.get('@table-computed')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Description');
cy
.get('@table-computed')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(3);
computeds.forEach((computed, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(computed.name);
expect($children.eq(1).html()).to.eq(computed.type);
expect($children.eq(2).html()).to.eq(computed.description);
});
});
});
it('should render methods properly', () => {
cy.contains('h3', 'Methods').should('have.attr', 'class', 'subsection-title');
cy.get('#decrement')
.contains('decrement()')
.parent()
.next('dd')
.find('.details')
.contains('a[href="js_CounterJS.js.html#sunlight-1-line-43"]', 'line 43');
cy.get('#increment')
.contains('increment()')
.parent()
.next('dd')
.find('.details')
.contains('a[href="js_CounterJS.js.html#sunlight-1-line-36"]', 'line 36');
cy.get('#showDialog')
.contains('showDialog(counter)')
.parent()
.next('dd')
.find('.details')
.contains('a[href="js_CounterJS.js.html#sunlight-1-line-51"]', 'line 51');
cy.contains('created()').should('not.exist');
});
});
describe('JS files rendered or not as Vue Component', () => {
before(() => {
cy.visit('/../../../example/docs-docstrap/index.html');
cy.screenshot();
});
it('NotVueComponent should not be rendered as Vue component', () => {
cy.get('.nav .dropdown a[href="global.html#helloWorld"]').contains('helloWorld');
cy.get('.nav .dropdown a[href="module-NotVueComponent.html"]').should('not.exist');
});
it('NotVueComponent2 should not be rendered as Vue component', () => {
cy.visit('/../../../example/docs-docstrap/module-NotVueComponent2.html');
cy.get('.nav .dropdown a[href="module-NotVueComponent2.html"]').contains('NotVueComponent2');
cy
.contains('h3', 'Methods')
.should('have.attr', 'class', 'subsection-title')
.next('dl')
.find('h4')
.contains('theMethod')
.parent()
.next('dd')
.find('.details')
.contains('a[href="js_NotVueComponent2.js.html#sunlight-1-line-11"]', 'line 11');
});
});
================================================
FILE: cypress/integration/templates/minami.spec.js
================================================
/* eslint-disable newline-per-chained-call */
describe('Template: minami', () => {
before(() => {
cy.visit('/../../../example/docs-minami/module-better-components_BetterCounter.html');
cy.screenshot();
});
it('should renders module name correctly', () => {
cy
.get('.page-title')
.contains('better-components/BetterCounter');
cy
.get('.nav-item-name a[href="module-better-components_BetterCounter.html"]')
.contains('better-components/BetterCounter');
});
it('should renders @desc properly', () => {
cy
.get('.container-overview')
.contains('BetterCounter component, like Counter component but better');
});
it('should renders props correctly', () => {
const props = [
{
name: '<code>initialCounter</code>',
type: '<code>Number</code>',
defaultValue: '-',
required: '<b>Yes</b>',
description: '-',
},
{
name: '<code>step</code>',
type: '<code>Number</code>',
defaultValue: '<code>1</code>',
required: 'No',
description: 'Step',
},
];
cy.get('[data-jsdoc-vuejs="section-props"]').contains('Props').should('have.class', 'subsection-title');
cy.get('[data-jsdoc-vuejs="table-props"]').as('table-props').should('have.class', 'params');
cy
.get('@table-props')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Default value')
.next().contains('Required?')
.next().contains('Description');
cy
.get('@table-props')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(2);
props.forEach((prop, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(prop.name);
expect($children.eq(0).attr('class')).to.eq('name');
expect($children.eq(1).html()).to.eq(prop.type);
expect($children.eq(2).html()).to.eq(prop.defaultValue);
expect($children.eq(3).html()).to.eq(prop.required);
expect($children.eq(4).html()).to.eq(prop.description);
});
});
});
it('should renders data correctly', () => {
const data = [
{
name: '<code>counter</code>',
type: '<code>Number</code>',
defaultValue: '-',
description: "Current counter's value",
},
];
cy.get('[data-jsdoc-vuejs="section-data"]').contains('Data').should('have.class', 'subsection-title');
cy.get('[data-jsdoc-vuejs="table-data"]').as('table-data').should('have.class', 'params');
cy
.get('@table-data')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Default value')
.next().contains('Description');
cy
.get('@table-data')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(1);
data.forEach((d, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(d.name);
expect($children.eq(1).html()).to.eq(d.type);
expect($children.eq(2).html()).to.eq(d.defaultValue);
expect($children.eq(3).html()).to.eq(d.description);
});
});
});
it('should renders computed correctly', () => {
const computeds = [
{ name: '<code>fooList</code>', type: '<code>Array.<String></code>', description: 'A list of foo' },
{ name: '<code>barList</code>', type: '<code>Array.<String></code>', description: 'A list of bar' },
{ name: '<code>message</code>', type: '<code>String</code>', description: 'A message' },
];
cy.get('[data-jsdoc-vuejs="section-computed"]').contains('Computed').should('have.class', 'subsection-title');
cy.get('[data-jsdoc-vuejs="table-computed"]').as('table-computed').should('have.class', 'params');
cy
.get('@table-computed')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Description');
cy
.get('@table-computed')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(3);
computeds.forEach((computed, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(computed.name);
expect($children.eq(0).attr('class')).to.eq('name');
expect($children.eq(1).html()).to.eq(computed.type);
expect($children.eq(2).html()).to.eq(computed.description);
});
});
});
it('should renders event correctly', () => {
const events = [
{ name: '<code>increment</code>', type: 'Number', description: "Emit counter's value after increment" },
{ name: '<code>decrement</code>', type: 'Number', description: "Emit counter's value after decrement" },
];
cy.get('[data-jsdoc-vuejs="section-event"]').contains('Events');
cy.get('[data-jsdoc-vuejs="table-event"]').as('table-event');
cy
.get('@table-event')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Payload Type')
.next().contains('Description');
cy
.get('@table-event')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(2);
events.forEach((event, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(event.name);
expect($children.eq(1).html()).to.eq(event.type);
expect($children.eq(2).html()).to.eq(event.description);
});
});
});
it('should render methods properly', () => {
cy.contains('h3', 'Methods').should('have.attr', 'class', 'subsection-title');
cy.get('#decrement')
.contains('decrement()')
.next('.description')
.next('.details')
.contains('a[href="better-components_BetterCounter.vue.html#line56"]', 'line 56');
cy.get('#increment')
.contains('increment()')
.next('.description')
.next('.details')
.contains('a[href="better-components_BetterCounter.vue.html#line48"]', 'line 48');
cy.get('#showDialog')
.contains('showDialog(counter)')
.next('.description')
.next('.details')
.contains('a[href="better-components_BetterCounter.vue.html#line65"]', 'line 65');
cy.contains('created()').should('not.exist');
});
});
describe('Template JS: minami', () => {
before(() => {
cy.visit('/../../../example/docs-minami/module-CounterJS.html');
cy.screenshot();
});
it('should renders module name correctly', () => {
cy
.get('.page-title')
.contains('CounterJS');
cy
.get('.nav-item-name a[href="module-CounterJS.html"]')
.contains('CounterJS');
});
it('should renders props correctly', () => {
const props = [
{
name: '<code>initialCounter</code>',
type: '<code>Number</code>',
defaultValue: '-',
required: '<b>Yes</b>',
description: '-',
},
{
name: '<code>step</code>',
type: '<code>Number</code>',
defaultValue: '<code>1</code>',
required: 'No',
description: 'Step',
},
];
cy.get('[data-jsdoc-vuejs="section-props"]').contains('Props').should('have.class', 'subsection-title');
cy.get('[data-jsdoc-vuejs="table-props"]').as('table-props').should('have.class', 'params');
cy
.get('@table-props')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Default value')
.next().contains('Required?')
.next().contains('Description');
cy
.get('@table-props')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(2);
props.forEach((prop, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(prop.name);
expect($children.eq(0).attr('class')).to.eq('name');
expect($children.eq(1).html()).to.eq(prop.type);
expect($children.eq(2).html()).to.eq(prop.defaultValue);
expect($children.eq(3).html()).to.eq(prop.required);
expect($children.eq(4).html()).to.eq(prop.description);
});
});
});
it('should renders data correctly', () => {
const data = [
{
name: '<code>counter</code>',
type: '<code>Number</code>',
defaultValue: '-',
description: "Current counter's value",
},
];
cy.get('[data-jsdoc-vuejs="section-data"]').contains('Data').should('have.class', 'subsection-title');
cy.get('[data-jsdoc-vuejs="table-data"]').as('table-data').should('have.class', 'params');
cy
.get('@table-data')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Default value')
.next().contains('Description');
cy
.get('@table-data')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(1);
data.forEach((d, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(d.name);
expect($children.eq(1).html()).to.eq(d.type);
expect($children.eq(2).html()).to.eq(d.defaultValue);
expect($children.eq(3).html()).to.eq(d.description);
});
});
});
it('should renders computed correctly', () => {
const computeds = [
{ name: '<code>fooList</code>', type: '<code>Array.<String></code>', description: 'A list of foo' },
{ name: '<code>barList</code>', type: '<code>Array.<String></code>', description: 'A list of bar' },
{ name: '<code>message</code>', type: '<code>String</code>', description: 'A message' },
];
cy.get('[data-jsdoc-vuejs="section-computed"]').contains('Computed').should('have.class', 'subsection-title');
cy.get('[data-jsdoc-vuejs="table-computed"]').as('table-computed').should('have.class', 'params');
cy
.get('@table-computed')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Description');
cy
.get('@table-computed')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(3);
computeds.forEach((computed, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(computed.name);
expect($children.eq(0).attr('class')).to.eq('name');
expect($children.eq(1).html()).to.eq(computed.type);
expect($children.eq(2).html()).to.eq(computed.description);
});
});
});
it('should render methods properly', () => {
cy.contains('h3', 'Methods').should('have.attr', 'class', 'subsection-title');
cy.get('#decrement')
.contains('decrement()')
.next('.description')
.next('.details')
.contains('a[href="js_CounterJS.js.html#line43"]', 'line 43');
cy.get('#increment')
.contains('increment()')
.next('.description')
.next('.details')
.contains('a[href="js_CounterJS.js.html#line36"]', 'line 36');
cy.get('#showDialog')
.contains('showDialog(counter)')
.next('.description')
.next('.details')
.contains('a[href="js_CounterJS.js.html#line51"]', 'line 51');
cy.contains('created()').should('not.exist');
});
});
describe('JS files rendered or not as Vue Component', () => {
before(() => {
cy.visit('/../../../example/docs-minami/index.html');
cy.screenshot();
});
it('NotVueComponent should not be rendered as Vue component', () => {
cy.get('.nav-item-name a[href="global.html#helloWorld"]').contains('helloWorld');
cy.get('.nav-item-name a[href="module-NotVueComponent.html"]').should('not.exist');
});
it('NotVueComponent2 should not be rendered as Vue component', () => {
cy.visit('/../../../example/docs-minami/module-NotVueComponent2.html');
cy.get('.nav-item-name a[href="module-NotVueComponent2.html"]').contains('NotVueComponent2');
cy
.contains('h3', 'Methods')
.should('have.attr', 'class', 'subsection-title')
.next('.section-method')
.find('h4.name')
.contains('theMethod')
.next('dl.details')
.contains('a[href="js_NotVueComponent2.js.html#line11"]', 'line 11');
});
});
================================================
FILE: cypress/integration/templates/tui.spec.js
================================================
/* eslint-disable newline-per-chained-call */
describe('Template: tui', () => {
before(() => {
cy.visit('/../../../example/docs-tui/module-better-components_BetterCounter.html');
cy.screenshot();
});
it('should renders module name correctly', () => {
cy
.get('.title')
.contains('Module: better-components/BetterCounter');
cy
.get('h2')
.contains('better-components/BetterCounter');
cy
.get('nav.lnb .lnb-api li a[href="module-better-components_BetterCounter.html"]')
.contains('better-components/BetterCounter');
});
it('should renders @desc properly', () => {
cy
.get('.container-overview')
.contains('BetterCounter component, like Counter component but better');
});
it('should renders props correctly', () => {
const props = [
{
name: '<code>initialCounter</code>',
type: '<span class="param-type">Number</span>',
defaultValue: '-',
required: '<b>Yes</b>',
description: '-',
},
{
name: '<code>step</code>',
type: '<span class="param-type">Number</span>',
defaultValue: '<code>1</code>',
required: 'No',
description: 'Step',
},
];
cy.get('[data-jsdoc-vuejs="section-props"]').contains('Props').should('have.class', 'subsection-title');
cy.get('[data-jsdoc-vuejs="table-props"]').as('table-props').should('have.class', 'params');
cy
.get('@table-props')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Default value')
.next().contains('Required?')
.next().contains('Description');
cy
.get('@table-props')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(2);
props.forEach((prop, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(prop.name);
expect($children.eq(1).html()).to.eq(prop.type);
expect($children.eq(2).html()).to.eq(prop.defaultValue);
expect($children.eq(3).html()).to.eq(prop.required);
expect($children.eq(4).html()).to.eq(prop.description);
});
});
});
it('should renders data correctly', () => {
const data = [
{
name: '<code>counter</code>',
type: '<span class="param-type">Number</span>',
defaultValue: '-',
description: "Current counter's value",
},
];
cy.get('[data-jsdoc-vuejs="section-data"]').contains('Data').should('have.class', 'subsection-title');
cy.get('[data-jsdoc-vuejs="table-data"]').as('table-data').should('have.class', 'params');
cy
.get('@table-data')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Default value')
.next().contains('Description');
cy
.get('@table-data')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(1);
data.forEach((d, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(d.name);
expect($children.eq(1).html()).to.eq(d.type);
expect($children.eq(2).html()).to.eq(d.defaultValue);
expect($children.eq(3).html()).to.eq(d.description);
});
});
});
it('should renders computed correctly', () => {
const computeds = [
{ name: '<code>fooList</code>', type: '<span class="param-type">Array.<String></span>', description: 'A list of foo' },
{ name: '<code>barList</code>', type: '<span class="param-type">Array.<String></span>', description: 'A list of bar' },
{ name: '<code>message</code>', type: '<span class="param-type">String</span>', description: 'A message' },
];
cy.get('[data-jsdoc-vuejs="section-computed"]').contains('Computed').should('have.class', 'subsection-title');
cy.get('[data-jsdoc-vuejs="table-computed"]').as('table-computed').should('have.class', 'params');
cy
.get('@table-computed')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Description');
cy
.get('@table-computed')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(3);
computeds.forEach((computed, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(computed.name);
expect($children.eq(1).html()).to.eq(computed.type);
expect($children.eq(2).html()).to.eq(computed.description);
});
});
});
it('should renders event correctly', () => {
const events = [
{ name: '<code>increment</code>', type: '<span class="param-type">Number</span>', description: "Emit counter's value after increment" },
{ name: '<code>decrement</code>', type: '<span class="param-type">Number</span>', description: "Emit counter's value after decrement" },
];
cy.get('[data-jsdoc-vuejs="section-event"]').contains('Events');
cy.get('[data-jsdoc-vuejs="table-event"]').as('table-event');
cy
.get('@table-event')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Payload Type')
.next().contains('Description');
cy
.get('@table-event')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(2);
events.forEach((event, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(event.name);
expect($children.eq(1).html()).to.eq(event.type);
expect($children.eq(2).html()).to.eq(event.description);
});
});
});
it('should render methods properly', () => {
cy.contains('h3', 'Methods').should('have.attr', 'class', 'subsection-title');
cy.get('#decrement')
.contains('decrement()')
.contains('a[href="better-components_BetterCounter.vue.html#line56"]', 'line 56');
cy.get('#increment')
.contains('increment()')
.contains('a[href="better-components_BetterCounter.vue.html#line48"]', 'line 48');
cy.get('#showDialog')
.contains('showDialog(counter)')
.contains('a[href="better-components_BetterCounter.vue.html#line65"]', 'line 65');
cy.contains('created()').should('not.exist');
});
});
describe('Template JS: tui', () => {
before(() => {
cy.visit('/../../../example/docs-tui/module-CounterJS.html');
cy.screenshot();
});
it('should renders module name correctly', () => {
cy
.get('.title')
.contains('Module: CounterJS');
cy
.get('h2')
.contains('CounterJS');
cy
.get('nav.lnb .lnb-api li a[href="module-CounterJS.html"]')
.contains('CounterJS');
});
it('should renders props correctly', () => {
const props = [
{
name: '<code>initialCounter</code>',
type: '<span class="param-type">Number</span>',
defaultValue: '-',
required: '<b>Yes</b>',
description: '-',
},
{
name: '<code>step</code>',
type: '<span class="param-type">Number</span>',
defaultValue: '<code>1</code>',
required: 'No',
description: 'Step',
},
];
cy.get('[data-jsdoc-vuejs="section-props"]').contains('Props').should('have.class', 'subsection-title');
cy.get('[data-jsdoc-vuejs="table-props"]').as('table-props').should('have.class', 'params');
cy
.get('@table-props')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Default value')
.next().contains('Required?')
.next().contains('Description');
cy
.get('@table-props')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(2);
props.forEach((prop, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(prop.name);
expect($children.eq(1).html()).to.eq(prop.type);
expect($children.eq(2).html()).to.eq(prop.defaultValue);
expect($children.eq(3).html()).to.eq(prop.required);
expect($children.eq(4).html()).to.eq(prop.description);
});
});
});
it('should renders data correctly', () => {
const data = [
{
name: '<code>counter</code>',
type: '<span class="param-type">Number</span>',
defaultValue: '-',
description: "Current counter's value",
},
];
cy.get('[data-jsdoc-vuejs="section-data"]').contains('Data').should('have.class', 'subsection-title');
cy.get('[data-jsdoc-vuejs="table-data"]').as('table-data').should('have.class', 'params');
cy
.get('@table-data')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Default value')
.next().contains('Description');
cy
.get('@table-data')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(1);
data.forEach((d, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(d.name);
expect($children.eq(1).html()).to.eq(d.type);
expect($children.eq(2).html()).to.eq(d.defaultValue);
expect($children.eq(3).html()).to.eq(d.description);
});
});
});
it('should renders computed correctly', () => {
const computeds = [
{ name: '<code>fooList</code>', type: '<span class="param-type">Array.<String></span>', description: 'A list of foo' },
{ name: '<code>barList</code>', type: '<span class="param-type">Array.<String></span>', description: 'A list of bar' },
{ name: '<code>message</code>', type: '<span class="param-type">String</span>', description: 'A message' },
];
cy.get('[data-jsdoc-vuejs="section-computed"]').contains('Computed').should('have.class', 'subsection-title');
cy.get('[data-jsdoc-vuejs="table-computed"]').as('table-computed').should('have.class', 'params');
cy
.get('@table-computed')
.find('> thead > tr > th')
.contains('Name')
.next().contains('Type')
.next().contains('Description');
cy
.get('@table-computed')
.find('> tbody > tr')
.then(($rows) => {
expect($rows).to.have.length(3);
computeds.forEach((computed, i) => {
const $row = $rows.eq(i);
const $children = $row.children();
expect($children.eq(0).html()).to.eq(computed.name);
expect($children.eq(1).html()).to.eq(computed.type);
expect($children.eq(2).html()).to.eq(computed.description);
});
});
});
it('should render methods properly', () => {
cy.contains('h3', 'Methods').should('have.attr', 'class', 'subsection-title');
cy.get('#decrement')
.contains('decrement()')
.contains('a[href="js_CounterJS.js.html#line43"]', 'line 43');
cy.get('#increment')
.contains('increment()')
.contains('a[href="js_CounterJS.js.html#line36"]', 'line 36');
cy.get('#showDialog')
.contains('showDialog(counter)')
.contains('a[href="js_CounterJS.js.html#line51"]', 'line 51');
cy.contains('created()').should('not.exist');
});
});
describe('JS files rendered or not as Vue Component', () => {
before(() => {
cy.visit('/../../../example/docs-tui/index.html');
cy.screenshot();
});
it('NotVueComponent should not be rendered as Vue component', () => {
cy.get('.lnb-api a[href="global.html#helloWorld"]').contains('helloWorld');
cy.get('.lnb-api a[href="module-NotVueComponent.html"]').should('not.exist');
});
it('NotVueComponent2 should not be rendered as Vue component', () => {
cy.visit('/../../../example/docs-tui/module-NotVueComponent2.html');
cy.get('.lnb-api a[href="module-NotVueComponent2.html"]').contains('NotVueComponent2');
cy
.contains('h3', 'Methods')
.should('have.attr', 'class', 'subsection-title')
.next('dl')
.find('.name')
.contains('theMethod')
.find('.container-source.members')
.contains('a[href="js_NotVueComponent2.js.html#line11"]', 'line 11');
});
});
================================================
FILE: cypress/plugins/index.js
================================================
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
// eslint-disable-next-line no-unused-vars
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
};
================================================
FILE: cypress/support/commands.js
================================================
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add("login", (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This is will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
================================================
FILE: cypress/support/index.js
================================================
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands';
// Alternatively you can use CommonJS syntax:
// require('./commands')
================================================
FILE: cypress.json
================================================
{
"projectId": "rryrv7",
"videoCompression": false
}
================================================
FILE: example/.jsdoc-docstrap.js
================================================
const config = Object.assign({}, require('./.jsdoc'));
config.opts.destination = 'docs-docstrap';
config.opts.template = './node_modules/ink-docstrap/template';
config.templates = {
linenums: true,
outputSourceFiles: true,
};
module.exports = config;
================================================
FILE: example/.jsdoc-minami.js
================================================
const config = Object.assign({}, require('./.jsdoc'));
config.opts.destination = 'docs-minami';
config.opts.template = './node_modules/minami';
module.exports = config;
================================================
FILE: example/.jsdoc-tui.js
================================================
const config = Object.assign({}, require('./.jsdoc'));
config.opts.destination = 'docs-tui';
config.opts.template = './node_modules/tui-jsdoc-template';
module.exports = config;
================================================
FILE: example/.jsdoc.js
================================================
module.exports = {
plugins: [
'../',
'plugins/markdown',
],
source: {
include: [
'src/',
'src/better-components',
'src/js',
'README.md',
],
includePattern: '\\.(vue|js)$',
},
opts: {
encoding: 'utf8',
},
};
================================================
FILE: example/README.md
================================================
Demo for [jsdoc-vuejs](https://github.com/Kocal/jsdoc-vuejs).
================================================
FILE: example/package.json
================================================
{
"scripts": {
"docs": "jsdoc -d docs -c .jsdoc.js",
"docs:docstrap": "jsdoc -c .jsdoc-docstrap.js",
"docs:minami": "jsdoc -c .jsdoc-minami.js",
"docs:tui": "jsdoc -c .jsdoc-tui.js",
"docs:all": "rm -rf docs* && yarn docs && yarn docs:docstrap && yarn docs:minami && yarn docs:tui"
},
"dependencies": {
"ink-docstrap": "^1.3.2",
"jsdoc": "^3.6.3",
"minami": "^1.2.3",
"tui-jsdoc-template": "^1.2.2",
"vuex": "^3.0.1"
}
}
================================================
FILE: example/src/Counter.vue
================================================
<template>
<div>
{{ counter }}
</div>
</template>
<script>
/**
* @vue-data {Number} [counter=0] Counter value
*/
export default {
name: 'Counter',
data() {
return {
counter: 0,
};
},
mounted() {
this.interval = setInterval(() => this.increment(), 1000);
},
beforeDestroy() {
clearInterval(this.interval);
},
methods: {
/**
* Increment the internal counter.
*/
increment() {
this.counter += 1;
}
}
};
</script>
================================================
FILE: example/src/better-components/BetterCounter.vue
================================================
<template>
<div>
{{ message }}
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
<button @click="showDialog(counter)">Show counter value in dialog</button>
</div>
</template>
<script>
import { mapState } from 'vuex';
/**
* @module better-components/BetterCounter
* @desc BetterCounter component, like Counter component but better
* @vue-prop {Number} initialCounter
* @vue-prop {Number} [step=1] Step
* @vue-data {Number} counter - Current counter's value
* @vue-computed {Array.<String>} fooList - A list of foo
* @vue-computed {Array.<String>} barList - A list of bar
* @vue-computed {String} message A message
* @vue-event {Number} increment - Emit counter's value after increment
* @vue-event {Number} decrement - Emit counter's value after decrement
*/
export default {
props: {
initialCounter: {type: Number, required: true},
step: {type: Number, default: 1}
},
data() {
return {
counter: this.initialCounter
}
},
computed: {
...mapState({
fooList: state => state.$_foo.fooList,
barList: state => state.$_foo.barList
}),
message() {
return `Counter: ${this.counter}`
}
},
methods: {
/**
* Increment counter and emit event 'increment'
*/
increment() {
this.counter += this.step;
this.$emit('increment', this.counter);
},
/**
* Decrement counter and emit event 'decrement'
*/
decrement() {
this.counter -= this.step;
this.$emit('decrement', this.counter);
},
/**
* Show a dialog displaying counter value.
* @param {Number} counter - Counter value
*/
showDialog(counter) {
alert(`Counter value is ${counter}.`);
}
},
/**
* Counter.vue `created` hook.
*/
created() {
console.info('Counter.vue: created()');
},
mounted() {
console.info('Counter.vue: mounted()');
}
};
</script>
================================================
FILE: example/src/js/CounterJS.js
================================================
import { mapState } from 'vuex';
/**
* @module CounterJS
* @vue-prop {Number} initialCounter
* @vue-prop {Number} [step=1] Step
* @vue-data {Number} counter - Current counter's value
* @vue-computed {Array.<String>} fooList - A list of foo
* @vue-computed {Array.<String>} barList - A list of bar
* @vue-computed {String} message A message
*/
export default {
name: 'CounterJS',
props: {
initialCounter: { type: Number, required: true },
step: { type: Number, default: 1 },
},
data() {
return {
counter: this.initialCounter,
};
},
computed: {
...mapState({
fooList: state => state.$_foo.fooList,
barList: state => state.$_foo.barList,
}),
message() {
return `Counter: ${this.counter}`;
},
},
methods: {
/**
* Increment counter.
*/
increment() {
this.counter += this.step;
},
/**
* Decrement counter.
*/
decrement() {
this.counter -= this.step;
},
/**
* Show a dialog displaying counter value.
* @param {Number} counter - Counter value
*/
showDialog(counter) {
alert(`Counter value is ${counter}.`);
},
},
/**
* Counter.vue `created` hook.
*/
created() {
console.info('Counter.vue: created()');
},
mounted() {
console.info('Counter.vue: mounted()');
},
};
================================================
FILE: example/src/js/NotVueComponent.js
================================================
import NotVueComponent2 from './NotVueComponent2';
NotVueComponent2.theMethod('123');
/**
* @return {Boolean}
*/
const helloWorld = () => {
console.log('Hello world');
return false;
};
export {
helloWorld,
};
================================================
FILE: example/src/js/NotVueComponent2.js
================================================
/**
* @module NotVueComponent2
*/
module.exports = {
state: {
foo: 'bar',
},
/**
* @param {String} i
*/
theMethod(i) {
console.log(i);
},
};
================================================
FILE: index.js
================================================
const { join } = require('path');
const config = require('./config');
const render = require('./lib/core/renderer');
const extractVueScript = require('./lib/core/vueScriptExtractor');
const seekExportDefaultLine = require('./lib/core/seekExportDefaultLine');
const { isSingleFileComponent, isJSComponent } = require('./lib/core/issers');
const vueDataTag = require('./lib/tags/vue-data');
const vuePropTag = require('./lib/tags/vue-prop');
const vueComputedTag = require('./lib/tags/vue-computed');
const vueEventTag = require('./lib/tags/vue-event');
// Used to compute good line number for Vue methods
const exportDefaultLines = {};
const mainDocletLines = {};
exports.handlers = {
beforeParse(e) {
if (/\.vue$/.test(e.filename)) {
exportDefaultLines[e.filename] = seekExportDefaultLine(e.source, e.filename);
e.source = extractVueScript(e.filename);
}
},
newDoclet(e) {
const fileIsSingleFileComponent = isSingleFileComponent(e.doclet);
const fileIsJSComponent = isJSComponent(e.doclet);
if (!fileIsSingleFileComponent && !fileIsJSComponent) {
return;
}
const fullPath = join(e.doclet.meta.path, e.doclet.meta.filename);
const componentName = e.doclet.meta.filename.replace(/\.(vue|js)$/, '');
// The main doclet before `export default {}`
if (e.doclet.longname === 'module.exports') {
e.doclet.kind = 'module';
e.doclet.name = componentName;
e.doclet.alias = componentName;
e.doclet.longname = `module:${componentName}`;
}
if (
!/[.~#]/.test(e.doclet.longname) // filter component's properties and member, not the best way but it werks
&& e.doclet.longname.startsWith('module:')
) {
mainDocletLines[fullPath] = e.doclet.meta.lineno;
}
// It can be the main doclet before `export default {}`
// with at least one `@vue-*` tag
if (e.doclet._isVueDoc) {
const { template } = config['jsdoc-vuejs'];
const data = {
props: e.doclet._vueProps || [],
data: e.doclet._vueData || [],
computed: e.doclet._vueComputed || [],
event: e.doclet._vueEvent || [],
};
render(template, data, (err, str) => {
if (err) throw err;
e.doclet.description = (e.doclet.description || '') + str;
});
// Remove meta for not rendering source for this doclet
delete e.doclet.meta;
}
// Methods and hooks
if (e.doclet.kind === 'function' && 'memberof' in e.doclet) {
if (e.doclet.memberof.endsWith('.methods')) {
e.doclet.scope = 'instance';
e.doclet.memberof = e.doclet.memberof.replace(/\.methods$/, ''); // force method to be displayed
if (fileIsSingleFileComponent) {
e.doclet.meta.lineno += exportDefaultLines[fullPath] - mainDocletLines[fullPath];
}
} else {
e.doclet.memberof = null; // don't include Vue hooks
}
}
},
};
exports.defineTags = function defineTags(dictionary) {
dictionary.defineTag(vueDataTag.name, vueDataTag.options);
dictionary.defineTag(vuePropTag.name, vuePropTag.options);
dictionary.defineTag(vueComputedTag.name, vueComputedTag.options);
dictionary.defineTag(vueEventTag.name, vueEventTag.options);
};
================================================
FILE: jest.config.js
================================================
module.exports = {
bail: true,
verbose: !process.env.CI,
collectCoverage: !!process.env.CI,
collectCoverageFrom: [
'lib/core/*.js',
],
testPathIgnorePatterns: [
'/node_modules/',
'/__fixtures__/',
'/__tests__/stubs',
'/cypress/',
],
moduleNameMapper: {
'jsdoc/(.*)': '<rootDir>/__tests__/stubs/jsdoc/$1.js',
},
};
================================================
FILE: lib/core/getTemplatePath.js
================================================
const { resolve } = require('path');
module.exports = function getTemplatePath(template) {
// eslint-disable-next-line no-param-reassign
template = template || 'default';
const templateFilename = (() => {
switch (true) {
case template === 'default':
return 'default.ejs';
case /ink-docstrap\/template/.test(template):
return 'docstrap.ejs';
case /minami/.test(template):
return 'minami.ejs';
case /tui-jsdoc-template/.test(template):
return 'tui.ejs';
default:
// eslint-disable-next-line no-console
console.warn(`The template "${template}" is not recognized by jsdoc-vuejs. Using default template as fallback.`);
return 'default.ejs';
}
})();
const path = resolve(__dirname, '../templates', templateFilename);
return resolve(path);
};
================================================
FILE: lib/core/issers.js
================================================
const path = require('path');
const hasVueTagRE = /\s*\*\s*@vue/;
// Useful because we use `@vue` tag from first doclet of a .js file
// to determine if this file is a Vue Component.
/**
* @type {Object.<String, Boolean>}
*/
const jsComponentsCache = {};
/**
* @param {Doclet} doclet
*/
function isSingleFileComponent(doclet) {
return doclet.meta.filename.endsWith('.vue');
}
/**
* @param {Doclet} doclet
*/
function isJSComponent(doclet) {
const fullPath = path.join(doclet.meta.path, doclet.meta.filename);
if (fullPath in jsComponentsCache) {
return jsComponentsCache[fullPath];
}
const res = doclet.meta.filename.endsWith('.js') && hasVueTagRE.test(doclet.comment || '');
if (res) {
jsComponentsCache[fullPath] = true;
}
return res;
}
module.exports = {
isSingleFileComponent,
isJSComponent,
};
================================================
FILE: lib/core/renderer.js
================================================
const ejs = require('ejs');
const renderType = require('../templates/utils/renderType');
module.exports = function render(template, {
props, data, computed, event,
}, cb) {
ejs.renderFile(
template,
{
renderType,
props,
data,
computed,
event,
},
cb,
);
};
================================================
FILE: lib/core/seekExportDefaultLine.js
================================================
/* eslint-disable no-continue */
module.exports = function seekExportDefaultLine(source, filename) {
let inScript = filename ? filename.endsWith('.js') : false;
// eslint-disable-next-line no-restricted-syntax
for (const [i, line] of source.split(/\r?\n/).entries()) {
if (line.trim() === '') {
continue;
}
if (/<script[^>]*>/.test(line)) {
inScript = true;
} else if (!inScript && /<\/script>/.test(line)) {
inScript = false;
}
if (inScript && /export\s+default/.test(line)) {
return i + 1; // index starts at 0, but file's lines start at 1
}
}
return 0;
};
================================================
FILE: lib/core/vueScriptExtractor.js
================================================
const fs = require('fs');
const compiler = require('@vue/compiler-sfc');
module.exports = function extractVueScript(filename) {
const source = fs.readFileSync(filename, 'utf8');
const parsedComponent = compiler.parse(source);
const scriptContent = parsedComponent.descriptor.script ? parsedComponent.descriptor.script.content : '';
return scriptContent;
};
================================================
FILE: lib/tags/vue-computed.js
================================================
exports.name = 'vue-computed';
exports.options = {
canHaveType: true,
canHaveName: true,
onTagged(doclet, tag) {
doclet._isVueDoc = true;
doclet._vueComputed = doclet._vueComputed || [];
doclet._vueComputed.push(tag.value || {});
},
};
================================================
FILE: lib/tags/vue-data.js
================================================
exports.name = 'vue-data';
exports.options = {
canHaveType: true,
canHaveName: true,
onTagged(doclet, tag) {
doclet._isVueDoc = true;
doclet._vueData = doclet._vueData || [];
doclet._vueData.push(tag.value || {});
},
};
================================================
FILE: lib/tags/vue-event.js
================================================
exports.name = 'vue-event';
exports.options = {
canHaveType: true, // type of event-payload
canHaveName: true, // name of emitted event
onTagged(doclet, tag) {
doclet._isVueDoc = true;
doclet._vueEvent = doclet._vueEvent || [];
doclet._vueEvent.push(tag.value || {});
},
};
================================================
FILE: lib/tags/vue-prop.js
================================================
exports.name = 'vue-prop';
exports.options = {
canHaveType: true,
canHaveName: true,
onTagged(doclet, tag) {
doclet._isVueDoc = true;
doclet._vueProps = doclet._vueProps || [];
doclet._vueProps.push(tag.value || {});
},
};
================================================
FILE: lib/templates/default.ejs
================================================
</p></div></div> <%# Prematurely close JSDoc default template tags %>
<% if(props.length > 0) { %>
<h3 class="subsection-title" style="margin-top: 1em" data-jsdoc-vuejs="section-props">Props</h3>
<table data-jsdoc-vuejs="table-props">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default value</th>
<th>Required?</th>
<th>Description</th>
</tr>
</thead>
<tbody><% props.forEach(function(prop) { %><tr>
<td><code><%- prop.name %></code></td>
<td><%- renderType(prop.type) %></td>
<td><%- typeof prop.defaultvalue === 'undefined' ? '-' : `<code>${prop.defaultvalue}</code>` %></td>
<td><%- prop.optional ? 'No' : '<b>Yes</b>' %></td>
<td><%- typeof prop.description === 'undefined' ? '-' : prop.description %></td>
</tr><% }) %></tbody>
</table>
<% } %>
<% if(data.length > 0) { %>
<h3 class="subsection-title" style="margin-top: 1em" data-jsdoc-vuejs="section-data">Data</h3>
<table data-jsdoc-vuejs="table-data">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default value</th>
<th>Description</th>
</tr>
</thead>
<tbody><% data.forEach(function(d) { %><tr>
<td><code><%- d.name %></code></td>
<td><%- renderType(d.type) %></td>
<td><%- typeof d.defaultvalue === 'undefined' ? '-' : `<code>${d.defaultvalue}</code>` %></td>
<td><%- typeof d.description === 'undefined' ? '-' : d.description %></td>
</tr><% }) %></tbody>
</table>
<% } %>
<% if(computed.length > 0) { %>
<h3 class="subsection-title" style="margin-top: 1em" data-jsdoc-vuejs="section-computed">Computed</h3>
<table data-jsdoc-vuejs="table-computed">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody><% computed.forEach(function(c) { %><tr>
<td><code><%- c.name %></code></td>
<td><%- renderType(c.type) %></td>
<td><%- typeof c.description === 'undefined' ? '-' : c.description %></td>
</tr><% }) %></tbody>
</table>
<% } %>
<% if(event.length > 0) { %>
<h3 class="subsection-title" style="margin-top: 1em" data-jsdoc-vuejs="section-event">Events</h3>
<table data-jsdoc-vuejs="table-event">
<thead>
<tr>
<th>Name</th>
<th>Payload Type</th>
<th>Description</th>
</tr>
</thead>
<tbody><% event.forEach(function(c) { %><tr>
<td><code><%- c.name %></code></td>
<td><%- renderType(c.type) %></td>
<td><%- typeof c.description === 'undefined' ? '-' : c.description %></td>
</tr><% }) %></tbody>
</table>
<% } %>
<div class="container-overview"><div><p> <%# Re-open JSDoc template tags %>
================================================
FILE: lib/templates/docstrap.ejs
================================================
</p></div></div> <%# Prematurely close JSDoc default template tags %>
<% if(props.length > 0) { %>
<h3 class="subsection-title" style="margin-top: 1em" data-jsdoc-vuejs="section-props">Props</h3>
<table class="table table-responsive table-hover table-striped" data-jsdoc-vuejs="table-props">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default value</th>
<th>Required?</th>
<th>Description</th>
</tr>
</thead>
<tbody><% props.forEach(function(prop) { %><tr>
<td><code><%- prop.name %></code></td>
<td><%- renderType(prop.type) %></td>
<td><%- typeof prop.defaultvalue === 'undefined' ? '-' : `<code>${prop.defaultvalue}</code>` %></td>
<td><%- prop.optional ? 'No' : '<b>Yes</b>' %></td>
<td><%- typeof prop.description === 'undefined' ? '-' : prop.description %></td>
</tr><% }) %></tbody>
</table>
<% } %>
<% if(data.length > 0) { %>
<h3 class="subsection-title" style="margin-top: 1em" data-jsdoc-vuejs="section-data">Data</h3>
<table class="table table-responsive table-hover table-striped" data-jsdoc-vuejs="table-data">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default value</th>
<th>Description</th>
</tr>
</thead>
<tbody><% data.forEach(function(d) { %><tr>
<td><code><%- d.name %></code></td>
<td><%- renderType(d.type) %></td>
<td><%- typeof d.defaultvalue === 'undefined' ? '-' : `<code>${d.defaultvalue}</code>` %></td>
<td><%- typeof d.description === 'undefined' ? '-' : d.description %></td>
</tr><% }) %></tbody>
</table>
<% } %>
<% if(computed.length > 0) { %>
<h3 class="subsection-title" style="margin-top: 1em" data-jsdoc-vuejs="section-computed">Computed</h3>
<table class="table table-responsive table-hover table-striped" data-jsdoc-vuejs="table-computed">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody><% computed.forEach(function(c) { %><tr>
<td><code><%- c.name %></code></td>
<td><%- renderType(c.type) %></td>
<td><%- typeof c.description === 'undefined' ? '-' : c.description %></td>
</tr><% }) %></tbody>
</table>
<% } %>
<% if(event.length > 0) { %>
<h3 class="subsection-title" style="margin-top: 1em" data-jsdoc-vuejs="section-event">Events</h3>
<table data-jsdoc-vuejs="table-event" class="table table-responsive table-hover table-striped">
<thead>
<tr>
<th>Name</th>
<th>Payload Type</th>
<th>Description</th>
</tr>
</thead>
<tbody><% event.forEach(function(c) { %><tr>
<td><code><%- c.name %></code></td>
<td><%- renderType(c.type) %></td>
<td><%- typeof c.description === 'undefined' ? '-' : c.description %></td>
</tr><% }) %></tbody>
</table>
<% } %>
<div class="container-overview"><div><p> <%# Re-open JSDoc template tags %>
================================================
FILE: lib/templates/minami.ejs
================================================
</p></div></div> <%# Prematurely close JSDoc default template tags %>
<% if(props.length > 0) { %>
<h3 class="subsection-title" style="margin-top: 1em" data-jsdoc-vuejs="section-props">Props</h3>
<table class="params" data-jsdoc-vuejs="table-props">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default value</th>
<th>Required?</th>
<th>Description</th>
</tr>
</thead>
<tbody><% props.forEach(function(prop) { %><tr>
<td class="name"><code><%- prop.name %></code></td>
<td><code><%- renderType(prop.type) %></code></td>
<td><%- typeof prop.defaultvalue === 'undefined' ? '-' : `<code>${prop.defaultvalue}</code>` %></td>
<td><%- prop.optional ? 'No' : '<b>Yes</b>' %></td>
<td><%- typeof prop.description === 'undefined' ? '-' : prop.description %></td>
</tr><% }) %></tbody>
</table>
<% } %>
<% if(data.length > 0) { %>
<h3 class="subsection-title" style="margin-top: 1em" data-jsdoc-vuejs="section-data">Data</h3>
<table class="params" data-jsdoc-vuejs="table-data">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default value</th>
<th>Description</th>
</tr>
</thead>
<tbody><% data.forEach(function(d) { %><tr>
<td class="name"><code><%- d.name %></code></td>
<td><code><%- renderType(d.type) %></code></td>
<td><%- typeof d.defaultvalue === 'undefined' ? '-' : `<code>${d.defaultvalue}</code>` %></td>
<td><%- typeof d.description === 'undefined' ? '-' : d.description %></td>
</tr><% }) %></tbody>
</table>
<% } %>
<% if(computed.length > 0) { %>
<h3 class="subsection-title" style="margin-top: 1em" data-jsdoc-vuejs="section-computed">Computed</h3>
<table class="params" data-jsdoc-vuejs="table-computed">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody><% computed.forEach(function(c) { %><tr>
<td class="name"><code><%- c.name %></code></td>
<td><code><%- renderType(c.type) %></code></td>
<td><%- typeof c.description === 'undefined' ? '-' : c.description %></td>
</tr><% }) %></tbody>
</table>
<% } %>
<% if(event.length > 0) { %>
<h3 class="subsection-title" style="margin-top: 1em" data-jsdoc-vuejs="section-event">Events</h3>
<table class="params" data-jsdoc-vuejs="table-event">
<thead>
<tr>
<th>Name</th>
<th>Payload Type</th>
<th>Description</th>
</tr>
</thead>
<tbody><% event.forEach(function(c) { %><tr>
<td><code><%- c.name %></code></td>
<td><%- renderType(c.type) %></td>
<td><%- typeof c.description === 'undefined' ? '-' : c.description %></td>
</tr><% }) %></tbody>
</table>
<% } %>
<div class="container-overview"><div><p> <%# Re-open JSDoc template tags %>
================================================
FILE: lib/templates/tui.ejs
================================================
</p></div></div> <%# Prematurely close JSDoc default template tags %>
<style>
.container-overview {
display: none;
}
.main section article table td.name,
.main section article table td.type,
.main section article table td.attributes,
.main section article table td.default {
max-width: none;
}
</style>
<% if(props.length > 0) { %>
<h3 class="subsection-title" style="margin-top: 1em" data-jsdoc-vuejs="section-props">Props</h3>
<div class="container-params">
<table class="params" data-jsdoc-vuejs="table-props">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default value</th>
<th>Required?</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody><% props.forEach(function(prop) { %><tr>
<td class="name"><code><%- prop.name %></code></td>
<td class="type"><span class="param-type"><%- renderType(prop.type) %></span></td>
<td class="description"><%- typeof prop.defaultvalue === 'undefined' ? '-' : `<code>${prop.defaultvalue}</code>` %></td>
<td class="description"><%- prop.optional ? 'No' : '<b>Yes</b>' %></td>
<td class="description last"><%- typeof prop.description === 'undefined' ? '-' : prop.description %></td>
</tr><% }) %></tbody>
</table>
</div>
<% } %>
<% if(data.length > 0) { %>
<h3 class="subsection-title" style="margin-top: 1em" data-jsdoc-vuejs="section-data">Data</h3>
<div class="container-params">
<table class="params" data-jsdoc-vuejs="table-data">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default value</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody><% data.forEach(function(d) { %><tr>
<td class="name"><code><%- d.name %></code></td>
<td class="type"><span class="param-type"><%- renderType(d.type) %></span></td>
<td class="description"><%- typeof d.defaultvalue === 'undefined' ? '-' : `<code>${d.defaultvalue}</code>` %></td>
<td class="description last"><%- typeof d.description === 'undefined' ? '-' : d.description %></td>
</tr><% }) %></tbody>
</table>
</div>
<% } %>
<% if(computed.length > 0) { %>
<h3 class="subsection-title" style="margin-top: 1em" data-jsdoc-vuejs="section-computed">Computed</h3>
<div class="container-params">
<table class="params" data-jsdoc-vuejs="table-computed">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody><% computed.forEach(function(c) { %><tr>
<td class="name"><code><%- c.name %></code></td>
<td class="type"><span class="param-type"><%- renderType(c.type) %></span></td>
<td class="description last"><%- typeof c.description === 'undefined' ? '-' : c.description %></td>
</tr><% }) %></tbody>
</table>
</div>
<% } %>
<% if(event.length > 0) { %>
<h3 class="subsection-title" style="margin-top: 1em" data-jsdoc-vuejs="section-event">Events</h3>
<div class="container-params">
<table class="params" data-jsdoc-vuejs="table-event">
<thead>
<tr>
<th>Name</th>
<th>Payload Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody><% event.forEach(function(c) { %><tr>
<td class="name"><code><%- c.name %></code></td>
<td class="type"><span class="param-type"><%- renderType(c.type) %></span></td>
<td class="description last"><%- typeof c.description === 'undefined' ? '-' : c.description %></td>
</tr><% }) %></tbody>
</table>
</div>
<% } %>
<div class="container-overview"><div><p> <%# Re-open JSDoc template tags %>
================================================
FILE: lib/templates/utils/renderType.js
================================================
const { htmlsafe } = require('jsdoc/lib/jsdoc/util/templateHelper');
module.exports = function renderTypes(type) {
return ((type && type.names) || []).map(htmlsafe).join('|');
};
================================================
FILE: package.json
================================================
{
"name": "jsdoc-vuejs",
"version": "0.0.0-development",
"description": "A JSDoc plugin for documenting vue 3 files.",
"main": "index.js",
"files": [
"lib",
"config.js"
],
"scripts": {
"test": "jest",
"lint": "eslint --ext .js index.js config.js lib __tests__ cypress",
"semantic-release": "semantic-release"
},
"repository": {
"type": "git",
"url": "https://github.com/Kocal/jsdoc-vuejs"
},
"keywords": [
"jsdoc",
"vuejs",
"vue component",
"vue file",
"vue 3"
],
"author": "Hugo Alliaume <hugo@alliau.me>",
"license": "MIT",
"bugs": {
"url": "https://github.com/Kocal/jsdoc-vuejs/issues"
},
"homepage": "https://github.com/Kocal/jsdoc-vuejs#readme",
"engines": {
"node": "^10.13.0 || >=12.0.0"
},
"dependencies": {
"ejs": "^3.0.1"
},
"peerDependencies": {
"jsdoc": ">=3.0.0",
"@vue/compiler-sfc": ">= 3.0.0"
},
"devDependencies": {
"@kocal/semantic-release-preset": "^2.0.6",
"@vue/compiler-sfc": "^3.1.4",
"cypress": "^4.0.1",
"eslint": "^6.2.0",
"eslint-config-airbnb-base": "^14.0.0",
"eslint-plugin-cypress": "^2.0.1",
"eslint-plugin-import": "^2.13.0",
"jest": "^24.0.0",
"jsdoc": "^3.6.2",
"semantic-release": "^17.1.1"
}
}
gitextract_1cmywy0n/ ├── .eslintrc.json ├── .github/ │ ├── FUNDING.yml │ └── workflows/ │ ├── ci.yml │ └── release.yml ├── .gitignore ├── .releaserc ├── LICENSE ├── README.md ├── UPGRADE.md ├── __tests__/ │ ├── core/ │ │ ├── __fixtures__/ │ │ │ ├── Component.vue │ │ │ └── methods/ │ │ │ ├── Component/ │ │ │ │ └── Component.js │ │ │ ├── Component.vue │ │ │ ├── ComponentWithExportDefaultInTemplate.vue │ │ │ ├── ComponentWithSpaces.vue │ │ │ └── ScriptBeforeTemplate.vue │ │ ├── __snapshots__/ │ │ │ └── vueScriptExtractor.js.snap │ │ ├── getTemplatePath.test.js │ │ ├── renderer.test.js │ │ ├── seekExportDefaultLine.js │ │ └── vueScriptExtractor.js │ └── stubs/ │ └── jsdoc/ │ └── lib/ │ └── jsdoc/ │ └── util/ │ └── templateHelper.js ├── config.js ├── cypress/ │ ├── fixtures/ │ │ └── example.json │ ├── integration/ │ │ └── templates/ │ │ ├── default.spec.js │ │ ├── docstrap.spec.js │ │ ├── minami.spec.js │ │ └── tui.spec.js │ ├── plugins/ │ │ └── index.js │ └── support/ │ ├── commands.js │ └── index.js ├── cypress.json ├── example/ │ ├── .jsdoc-docstrap.js │ ├── .jsdoc-minami.js │ ├── .jsdoc-tui.js │ ├── .jsdoc.js │ ├── README.md │ ├── package.json │ └── src/ │ ├── Counter.vue │ ├── better-components/ │ │ └── BetterCounter.vue │ └── js/ │ ├── CounterJS.js │ ├── NotVueComponent.js │ └── NotVueComponent2.js ├── index.js ├── jest.config.js ├── lib/ │ ├── core/ │ │ ├── getTemplatePath.js │ │ ├── issers.js │ │ ├── renderer.js │ │ ├── seekExportDefaultLine.js │ │ └── vueScriptExtractor.js │ ├── tags/ │ │ ├── vue-computed.js │ │ ├── vue-data.js │ │ ├── vue-event.js │ │ └── vue-prop.js │ └── templates/ │ ├── default.ejs │ ├── docstrap.ejs │ ├── minami.ejs │ ├── tui.ejs │ └── utils/ │ └── renderType.js └── package.json
SYMBOL INDEX (17 symbols across 9 files)
FILE: __tests__/core/__fixtures__/methods/Component/Component.js
method data (line 13) | data() {
FILE: example/src/js/CounterJS.js
method data (line 18) | data() {
method message (line 28) | message() {
method increment (line 36) | increment() {
method decrement (line 43) | decrement() {
method showDialog (line 51) | showDialog(counter) {
method created (line 59) | created() {
method mounted (line 62) | mounted() {
FILE: example/src/js/NotVueComponent2.js
method theMethod (line 11) | theMethod(i) {
FILE: index.js
method beforeParse (line 17) | beforeParse(e) {
method newDoclet (line 23) | newDoclet(e) {
FILE: lib/core/issers.js
function isSingleFileComponent (line 15) | function isSingleFileComponent(doclet) {
function isJSComponent (line 22) | function isJSComponent(doclet) {
FILE: lib/tags/vue-computed.js
method onTagged (line 6) | onTagged(doclet, tag) {
FILE: lib/tags/vue-data.js
method onTagged (line 6) | onTagged(doclet, tag) {
FILE: lib/tags/vue-event.js
method onTagged (line 6) | onTagged(doclet, tag) {
FILE: lib/tags/vue-prop.js
method onTagged (line 6) | onTagged(doclet, tag) {
Condensed preview — 59 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (103K chars).
[
{
"path": ".eslintrc.json",
"chars": 623,
"preview": "{\n \"extends\": [\n \"airbnb-base\"\n ],\n \"env\": {\n \"es6\": true,\n \"node\": true,\n \"jest\": true,\n \"cypress/glo"
},
{
"path": ".github/FUNDING.yml",
"chars": 42,
"preview": "github: Kocal\ncustom: paypal.me/HAlliaume\n"
},
{
"path": ".github/workflows/ci.yml",
"chars": 1720,
"preview": "name: Node CI\n\non:\n pull_request:\n branches:\n - '*'\n\njobs:\n ci:\n runs-on: ${{ matrix.os }"
},
{
"path": ".github/workflows/release.yml",
"chars": 557,
"preview": "name: Release\n\non:\n push:\n branches:\n - master\n\njobs:\n release:\n runs-on: ubuntu-latest\n\n"
},
{
"path": ".gitignore",
"chars": 935,
"preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directo"
},
{
"path": ".releaserc",
"chars": 50,
"preview": "{\n \"extends\": \"@kocal/semantic-release-preset\"\n}\n"
},
{
"path": "LICENSE",
"chars": 1070,
"preview": "MIT License\n\nCopyright (c) 2018 Hugo Alliaume\n\nPermission is hereby granted, free of charge, to any person obtaining a c"
},
{
"path": "README.md",
"chars": 4231,
"preview": "JSDoc for VueJS\n===============\n\n[](https://badge.fury.io/js/jsd"
},
{
"path": "UPGRADE.md",
"chars": 934,
"preview": "## Upgrade from 1.x to 2.x\n\n### Configuration\n\nYou MUST remove `jsdoc-vuejs` configuration key inside JSDoc config file,"
},
{
"path": "__tests__/core/__fixtures__/Component.vue",
"chars": 215,
"preview": "<template>\n <div>Hello world</div>\n</template>\n\n<script>\n/**\n * @vue-data {String} [foo=bar] Foo description\n */\nexport"
},
{
"path": "__tests__/core/__fixtures__/methods/Component/Component.js",
"chars": 288,
"preview": "\n/**\n * @vue-prop {String} test - test description\n * @vue-data {String} [foo=bar] - Foo description\n */\nexport default "
},
{
"path": "__tests__/core/__fixtures__/methods/Component.vue",
"chars": 225,
"preview": "<template>\n <div>Hello world</div>\n</template>\n\n<script>\n/**\n * My component\n */\nexport default {\n name: 'Component',\n"
},
{
"path": "__tests__/core/__fixtures__/methods/ComponentWithExportDefaultInTemplate.vue",
"chars": 204,
"preview": "<template>\n <div>export default</div>\n</template>\n\n<script>\nexport default {\n name: 'Component',\n methods: {\n /**\n"
},
{
"path": "__tests__/core/__fixtures__/methods/ComponentWithSpaces.vue",
"chars": 230,
"preview": "\n\n\n<template>\n <div>Hello world</div>\n</template>\n\n\n\n<script>\n\n\n\n export default\n\n {\n name: 'Component'"
},
{
"path": "__tests__/core/__fixtures__/methods/ScriptBeforeTemplate.vue",
"chars": 229,
"preview": "<script>\n/**\n * @vue-data {String} [foo=bar] Foo description\n */\nexport default {\n name: 'ScriptBeforeTemplate',\n data"
},
{
"path": "__tests__/core/__snapshots__/vueScriptExtractor.js.snap",
"chars": 252,
"preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`core.extractVueScript extract script 1`] = `\n\"\n/**\n * @vue-data {St"
},
{
"path": "__tests__/core/getTemplatePath.test.js",
"chars": 1333,
"preview": "/* eslint-disable no-console */\nconst { normalize } = require('path');\nconst getTemplatePath = require('../../lib/core/g"
},
{
"path": "__tests__/core/renderer.test.js",
"chars": 770,
"preview": "const ejs = require('ejs');\nconst renderer = require('../../lib/core/renderer');\n\ndescribe('code.renderer', () => {\n be"
},
{
"path": "__tests__/core/seekExportDefaultLine.js",
"chars": 1382,
"preview": "const path = require('path');\nconst fs = require('fs');\nconst seekExportDefaultLine = require('../../lib/core/seekExport"
},
{
"path": "__tests__/core/vueScriptExtractor.js",
"chars": 320,
"preview": "const path = require('path');\nconst extractVueScript = require('../../lib/core/vueScriptExtractor');\n\ndescribe('core.ext"
},
{
"path": "__tests__/stubs/jsdoc/lib/jsdoc/util/templateHelper.js",
"chars": 152,
"preview": "// Actually stub this module, to prevent follow error:\n// \"Cannot find module 'jsdoc/tag/dictionary' from 'templateHelpe"
},
{
"path": "config.js",
"chars": 418,
"preview": "const env = require('jsdoc/env');\nconst getTemplatePath = require('./lib/core/getTemplatePath');\n\nconst config = env.con"
},
{
"path": "cypress/fixtures/example.json",
"chars": 154,
"preview": "{\n \"name\": \"Using fixtures to represent data\",\n \"email\": \"hello@cypress.io\",\n \"body\": \"Fixtures are a great way to mo"
},
{
"path": "cypress/integration/templates/default.spec.js",
"chars": 11926,
"preview": "/* eslint-disable newline-per-chained-call */\n\ndescribe('Template: default', () => {\n before(() => {\n cy.visit('/../"
},
{
"path": "cypress/integration/templates/docstrap.spec.js",
"chars": 12678,
"preview": "/* eslint-disable newline-per-chained-call */\n\ndescribe('Template: docstrap', () => {\n before(() => {\n cy.visit('/.."
},
{
"path": "cypress/integration/templates/minami.spec.js",
"chars": 12671,
"preview": "/* eslint-disable newline-per-chained-call */\n\ndescribe('Template: minami', () => {\n before(() => {\n cy.visit('/../."
},
{
"path": "cypress/integration/templates/tui.spec.js",
"chars": 12511,
"preview": "/* eslint-disable newline-per-chained-call */\n\ndescribe('Template: tui', () => {\n before(() => {\n cy.visit('/../../."
},
{
"path": "cypress/plugins/index.js",
"chars": 688,
"preview": "// ***********************************************************\n// This example plugins/index.js can be used to load plug"
},
{
"path": "cypress/support/commands.js",
"chars": 841,
"preview": "// ***********************************************\n// This example commands.js shows you how to\n// create various custom"
},
{
"path": "cypress/support/index.js",
"chars": 671,
"preview": "// ***********************************************************\n// This example support/index.js is processed and\n// load"
},
{
"path": "cypress.json",
"chars": 57,
"preview": "{\n \"projectId\": \"rryrv7\",\n \"videoCompression\": false\n}\n"
},
{
"path": "example/.jsdoc-docstrap.js",
"chars": 257,
"preview": "const config = Object.assign({}, require('./.jsdoc'));\n\nconfig.opts.destination = 'docs-docstrap';\nconfig.opts.template "
},
{
"path": "example/.jsdoc-minami.js",
"chars": 171,
"preview": "const config = Object.assign({}, require('./.jsdoc'));\n\nconfig.opts.destination = 'docs-minami';\nconfig.opts.template = "
},
{
"path": "example/.jsdoc-tui.js",
"chars": 180,
"preview": "const config = Object.assign({}, require('./.jsdoc'));\n\nconfig.opts.destination = 'docs-tui';\nconfig.opts.template = './"
},
{
"path": "example/.jsdoc.js",
"chars": 267,
"preview": "module.exports = {\n plugins: [\n '../',\n 'plugins/markdown',\n ],\n source: {\n include: [\n 'src/',\n '"
},
{
"path": "example/README.md",
"chars": 61,
"preview": "Demo for [jsdoc-vuejs](https://github.com/Kocal/jsdoc-vuejs)."
},
{
"path": "example/package.json",
"chars": 469,
"preview": "{\n \"scripts\": {\n \"docs\": \"jsdoc -d docs -c .jsdoc.js\",\n \"docs:docstrap\": \"jsdoc -c .jsdoc-docstrap.js\",\n \"docs"
},
{
"path": "example/src/Counter.vue",
"chars": 489,
"preview": "<template>\n <div>\n {{ counter }}\n </div>\n</template>\n\n<script>\n/**\n * @vue-data {Number} [counter=0] Counter value\n"
},
{
"path": "example/src/better-components/BetterCounter.vue",
"chars": 2070,
"preview": "<template>\n <div>\n {{ message }}\n <button @click=\"increment\">+1</button>\n <button @click=\"decrement\">-1</butto"
},
{
"path": "example/src/js/CounterJS.js",
"chars": 1354,
"preview": "import { mapState } from 'vuex';\n\n/**\n * @module CounterJS\n * @vue-prop {Number} initialCounter\n * @vue-prop {Number} [s"
},
{
"path": "example/src/js/NotVueComponent.js",
"chars": 220,
"preview": "import NotVueComponent2 from './NotVueComponent2';\n\nNotVueComponent2.theMethod('123');\n\n/**\n * @return {Boolean}\n */\ncon"
},
{
"path": "example/src/js/NotVueComponent2.js",
"chars": 167,
"preview": "/**\n * @module NotVueComponent2\n */\nmodule.exports = {\n state: {\n foo: 'bar',\n },\n /**\n * @param {String} i\n *"
},
{
"path": "index.js",
"chars": 3232,
"preview": "const { join } = require('path');\nconst config = require('./config');\nconst render = require('./lib/core/renderer');\ncon"
},
{
"path": "jest.config.js",
"chars": 356,
"preview": "module.exports = {\n bail: true,\n verbose: !process.env.CI,\n collectCoverage: !!process.env.CI,\n collectCoverageFrom:"
},
{
"path": "lib/core/getTemplatePath.js",
"chars": 846,
"preview": "const { resolve } = require('path');\n\nmodule.exports = function getTemplatePath(template) {\n // eslint-disable-next-lin"
},
{
"path": "lib/core/issers.js",
"chars": 842,
"preview": "const path = require('path');\n\nconst hasVueTagRE = /\\s*\\*\\s*@vue/;\n\n// Useful because we use `@vue` tag from first docle"
},
{
"path": "lib/core/renderer.js",
"chars": 309,
"preview": "const ejs = require('ejs');\nconst renderType = require('../templates/utils/renderType');\n\nmodule.exports = function rend"
},
{
"path": "lib/core/seekExportDefaultLine.js",
"chars": 626,
"preview": "/* eslint-disable no-continue */\n\nmodule.exports = function seekExportDefaultLine(source, filename) {\n let inScript = f"
},
{
"path": "lib/core/vueScriptExtractor.js",
"chars": 367,
"preview": "const fs = require('fs');\nconst compiler = require('@vue/compiler-sfc');\n\nmodule.exports = function extractVueScript(fil"
},
{
"path": "lib/tags/vue-computed.js",
"chars": 257,
"preview": "exports.name = 'vue-computed';\n\nexports.options = {\n canHaveType: true,\n canHaveName: true,\n onTagged(doclet, tag) {\n"
},
{
"path": "lib/tags/vue-data.js",
"chars": 241,
"preview": "exports.name = 'vue-data';\n\nexports.options = {\n canHaveType: true,\n canHaveName: true,\n onTagged(doclet, tag) {\n "
},
{
"path": "lib/tags/vue-event.js",
"chars": 295,
"preview": "exports.name = 'vue-event';\n\nexports.options = {\n canHaveType: true, // type of event-payload\n canHaveName: true, // n"
},
{
"path": "lib/tags/vue-prop.js",
"chars": 244,
"preview": "exports.name = 'vue-prop';\n\nexports.options = {\n canHaveType: true,\n canHaveName: true,\n onTagged(doclet, tag) {\n "
},
{
"path": "lib/templates/default.ejs",
"chars": 2723,
"preview": "</p></div></div> <%# Prematurely close JSDoc default template tags %>\n\n<% if(props.length > 0) { %>\n<h3 class=\"subsectio"
},
{
"path": "lib/templates/docstrap.ejs",
"chars": 2950,
"preview": "</p></div></div> <%# Prematurely close JSDoc default template tags %>\n\n<% if(props.length > 0) { %>\n<h3 class=\"subsectio"
},
{
"path": "lib/templates/minami.ejs",
"chars": 2860,
"preview": "</p></div></div> <%# Prematurely close JSDoc default template tags %>\n\n<% if(props.length > 0) { %>\n<h3 class=\"subsectio"
},
{
"path": "lib/templates/tui.ejs",
"chars": 3869,
"preview": "</p></div></div> <%# Prematurely close JSDoc default template tags %>\n\n<style>\n.container-overview {\n display: none;\n"
},
{
"path": "lib/templates/utils/renderType.js",
"chars": 182,
"preview": "const { htmlsafe } = require('jsdoc/lib/jsdoc/util/templateHelper');\n\nmodule.exports = function renderTypes(type) {\n re"
},
{
"path": "package.json",
"chars": 1289,
"preview": "{\n \"name\": \"jsdoc-vuejs\",\n \"version\": \"0.0.0-development\",\n \"description\": \"A JSDoc plugin for documenting vue 3 file"
}
]
About this extraction
This page contains the full source code of the Kocal/jsdoc-vuejs GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 59 files (93.3 KB), approximately 27.0k tokens, and a symbol index with 17 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.