From 6ac1ff1719616f0ae315128a533ec3fd0a4e1bdd Mon Sep 17 00:00:00 2001 From: Hugo Alliaume Date: Sat, 19 Jan 2019 15:17:37 +0100 Subject: [PATCH] feat: Added `@vue-event` tag for `$emit` events (#174) The same than #168, but with 2/3 minors modif. Close #160. --- .eslintrc.json | 3 +- README.md | 13 +++++++ __tests__/core/renderer.test.js | 5 ++- cypress/integration/templates/default.spec.js | 39 +++++++++++++++++-- .../integration/templates/docstrap.spec.js | 39 +++++++++++++++++-- cypress/integration/templates/minami.spec.js | 39 +++++++++++++++++-- cypress/integration/templates/tui.spec.js | 39 +++++++++++++++++-- .../src/better-components/BetterCounter.vue | 8 +++- index.js | 4 +- lib/core/renderer.js | 5 ++- lib/tags/vue-event.js | 11 ++++++ lib/templates/default.ejs | 23 +++++++++++ lib/templates/docstrap.ejs | 22 +++++++++++ lib/templates/minami.ejs | 22 +++++++++++ lib/templates/tui.ejs | 24 ++++++++++++ 15 files changed, 278 insertions(+), 18 deletions(-) create mode 100644 lib/tags/vue-event.js diff --git a/.eslintrc.json b/.eslintrc.json index 6dfe513..93c27ec 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -29,7 +29,8 @@ "_isVueDoc", "_vueProps", "_vueData", - "_vueComputed" + "_vueComputed", + "_vueEvent" ] }] } diff --git a/README.md b/README.md index 78859b8..0e7f958 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ 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). @@ -56,6 +57,8 @@ All of those tags work the same way than [`@param` tag](http://usejsdoc.org/tags * @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: { @@ -77,6 +80,16 @@ All of those tags work the same way than [`@param` tag](http://usejsdoc.org/tags 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); + } } } diff --git a/__tests__/core/renderer.test.js b/__tests__/core/renderer.test.js index 0ca1081..3fbe905 100644 --- a/__tests__/core/renderer.test.js +++ b/__tests__/core/renderer.test.js @@ -9,7 +9,9 @@ describe('code.renderer', () => { it('should call ejs render method', () => { const cb = () => {}; - renderer('my-template', { props: ['props'], data: ['data'], computed: ['computed'] }, cb); + renderer('my-template', { + props: ['props'], data: ['data'], computed: ['computed'], event: ['event'], + }, cb); expect(ejs.renderFile).toHaveBeenCalledTimes(1); expect(ejs.renderFile).toHaveBeenCalledWith( @@ -18,6 +20,7 @@ describe('code.renderer', () => { props: ['props'], data: ['data'], computed: ['computed'], + event: ['event'], // an helper function, it should be under keys "utils" or "helpers" btw renderType: expect.any(Function), }, diff --git a/cypress/integration/templates/default.spec.js b/cypress/integration/templates/default.spec.js index 656c18f..a1dd8be 100644 --- a/cypress/integration/templates/default.spec.js +++ b/cypress/integration/templates/default.spec.js @@ -144,6 +144,39 @@ describe('Template: default', () => { }); }); + it('should renders event correctly', () => { + const events = [ + { name: 'increment', type: 'Number', description: "Emit counter's value after increment" }, + { name: 'decrement', 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'); @@ -151,13 +184,13 @@ describe('Template: default', () => { .contains('decrement()') .next('.description') .next('.details') - .contains('a[href="better-components_BetterCounter.vue.html#line53"]', 'line 53'); + .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#line46"]', 'line 46'); + .contains('a[href="better-components_BetterCounter.vue.html#line48"]', 'line 48'); cy.get('#showDialog') .contains('showDialog(counter)') @@ -165,7 +198,7 @@ describe('Template: default', () => { .next('h5') .next('.params') .next('.details') - .contains('a[href="better-components_BetterCounter.vue.html#line61"]', 'line 61'); + .contains('a[href="better-components_BetterCounter.vue.html#line65"]', 'line 65'); cy.contains('created()').should('not.exist'); }); diff --git a/cypress/integration/templates/docstrap.spec.js b/cypress/integration/templates/docstrap.spec.js index b547a22..5cd64ce 100644 --- a/cypress/integration/templates/docstrap.spec.js +++ b/cypress/integration/templates/docstrap.spec.js @@ -144,6 +144,39 @@ describe('Template: docstrap', () => { }); }); + it('should renders event correctly', () => { + const events = [ + { name: 'increment', type: 'Number', description: "Emit counter's value after increment" }, + { name: 'decrement', 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') @@ -151,21 +184,21 @@ describe('Template: docstrap', () => { .parent() .next('dd') .find('.details') - .contains('a[href="better-components_BetterCounter.vue.html#sunlight-1-line-53"]', 'line 53'); + .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-46"]', 'line 46'); + .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-61"]', 'line 61'); + .contains('a[href="better-components_BetterCounter.vue.html#sunlight-1-line-65"]', 'line 65'); cy.contains('created()').should('not.exist'); }); diff --git a/cypress/integration/templates/minami.spec.js b/cypress/integration/templates/minami.spec.js index d86fcdc..9900cf7 100644 --- a/cypress/integration/templates/minami.spec.js +++ b/cypress/integration/templates/minami.spec.js @@ -146,25 +146,58 @@ describe('Template: minami', () => { }); }); + it('should renders event correctly', () => { + const events = [ + { name: 'increment', type: 'Number', description: "Emit counter's value after increment" }, + { name: 'decrement', 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#line53"]', 'line 53'); + .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#line46"]', 'line 46'); + .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#line61"]', 'line 61'); + .contains('a[href="better-components_BetterCounter.vue.html#line65"]', 'line 65'); cy.contains('created()').should('not.exist'); }); diff --git a/cypress/integration/templates/tui.spec.js b/cypress/integration/templates/tui.spec.js index 7ab1509..8008b27 100644 --- a/cypress/integration/templates/tui.spec.js +++ b/cypress/integration/templates/tui.spec.js @@ -148,19 +148,52 @@ describe('Template: tui', () => { }); }); + it('should renders event correctly', () => { + const events = [ + { name: 'increment', type: 'Number', description: "Emit counter's value after increment" }, + { name: 'decrement', 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()') - .contains('a[href="better-components_BetterCounter.vue.html#line53"]', 'line 53'); + .contains('a[href="better-components_BetterCounter.vue.html#line56"]', 'line 56'); cy.get('#increment') .contains('increment()') - .contains('a[href="better-components_BetterCounter.vue.html#line46"]', 'line 46'); + .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#line61"]', 'line 61'); + .contains('a[href="better-components_BetterCounter.vue.html#line65"]', 'line 65'); cy.contains('created()').should('not.exist'); }); diff --git a/example/src/better-components/BetterCounter.vue b/example/src/better-components/BetterCounter.vue index 0c756d4..b8763f8 100644 --- a/example/src/better-components/BetterCounter.vue +++ b/example/src/better-components/BetterCounter.vue @@ -19,6 +19,8 @@ * @vue-computed {Array.} fooList - A list of foo * @vue-computed {Array.} 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: { @@ -41,17 +43,19 @@ }, methods: { /** - * Increment counter. + * Increment counter and emit event 'increment' */ increment() { this.counter += this.step; + this.$emit('increment', this.counter); }, /** - * Decrement counter. + * Decrement counter and emit event 'decrement' */ decrement() { this.counter -= this.step; + this.$emit('decrement', this.counter); }, /** diff --git a/index.js b/index.js index 3125777..2205f33 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,7 @@ 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 = {}; @@ -22,7 +23,6 @@ exports.handlers = { newDoclet(e) { const fileIsSingleFileComponent = isSingleFileComponent(e.doclet); const fileIsJSComponent = isJSComponent(e.doclet); - if (!fileIsSingleFileComponent && !fileIsJSComponent) { return; } @@ -53,6 +53,7 @@ exports.handlers = { props: e.doclet._vueProps || [], data: e.doclet._vueData || [], computed: e.doclet._vueComputed || [], + event: e.doclet._vueEvent || [], }; render(template, data, (err, str) => { @@ -84,4 +85,5 @@ 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); }; diff --git a/lib/core/renderer.js b/lib/core/renderer.js index d510ff3..c679023 100644 --- a/lib/core/renderer.js +++ b/lib/core/renderer.js @@ -1,7 +1,9 @@ const ejs = require('ejs'); const renderType = require('../templates/utils/renderType'); -module.exports = function render(template, { props, data, computed }, cb) { +module.exports = function render(template, { + props, data, computed, event, +}, cb) { ejs.renderFile( template, { @@ -9,6 +11,7 @@ module.exports = function render(template, { props, data, computed }, cb) { props, data, computed, + event, }, cb, ); diff --git a/lib/tags/vue-event.js b/lib/tags/vue-event.js new file mode 100644 index 0000000..334dc43 --- /dev/null +++ b/lib/tags/vue-event.js @@ -0,0 +1,11 @@ +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 || {}); + }, +}; diff --git a/lib/templates/default.ejs b/lib/templates/default.ejs index 6e99f5b..be7d69d 100644 --- a/lib/templates/default.ejs +++ b/lib/templates/default.ejs @@ -72,4 +72,27 @@ <% } %> + +<% if(event.length > 0) { %> +

Events

+ + + + + + + + + + <% event.forEach(function(c) { %> + + + + + + <% }) %> + +
NamePayload TypeDescription
<%- c.name %><%- renderType(c.type) %><%- typeof c.description === 'undefined' ? '-' : c.description %>
+<% } %> +

<%# Re-open JSDoc template tags %> diff --git a/lib/templates/docstrap.ejs b/lib/templates/docstrap.ejs index ea57206..3a9afba 100644 --- a/lib/templates/docstrap.ejs +++ b/lib/templates/docstrap.ejs @@ -72,4 +72,26 @@ <% } %> +<% if(event.length > 0) { %> +

Events

+ + + + + + + + + + <% event.forEach(function(c) { %> + + + + + + <% }) %> + +
NamePayload TypeDescription
<%- c.name %><%- renderType(c.type) %><%- typeof c.description === 'undefined' ? '-' : c.description %>
+<% } %> +

<%# Re-open JSDoc template tags %> diff --git a/lib/templates/minami.ejs b/lib/templates/minami.ejs index 529806b..4a18758 100644 --- a/lib/templates/minami.ejs +++ b/lib/templates/minami.ejs @@ -72,4 +72,26 @@ <% } %> +<% if(event.length > 0) { %> +

Events

+ + + + + + + + + + <% event.forEach(function(c) { %> + + + + + + <% }) %> + +
NamePayload TypeDescription
<%- c.name %><%- renderType(c.type) %><%- typeof c.description === 'undefined' ? '-' : c.description %>
+<% } %> +

<%# Re-open JSDoc template tags %> diff --git a/lib/templates/tui.ejs b/lib/templates/tui.ejs index 9499013..1aab4ad 100644 --- a/lib/templates/tui.ejs +++ b/lib/templates/tui.ejs @@ -91,4 +91,28 @@

<% } %> +<% if(computed.length > 0) { %> +

Events

+
+ + + + + + + + + + <% event.forEach(function(c) { %> + + + + + + <% }) %> + +
NamePayload TypeDescription
<%- c.name %><%- renderType(c.type) %><%- typeof c.description === 'undefined' ? '-' : c.description %>
+
+<% } %> +

<%# Re-open JSDoc template tags %>