From 6f166e0b7f476be96311ac4ddc4d9d169bef239b Mon Sep 17 00:00:00 2001 From: Shota Fuji Date: Tue, 11 Feb 2020 20:13:36 +0000 Subject: [PATCH] feat: Ignore props/events with @ignore JSDoc tag --- src/index.js | 23 +++++++++++- src/utils.js | 27 +++++++++++++ src/utils.spec.js | 52 ++++++++++++++++++++++++++ test/__snapshots__/loader.spec.js.snap | 39 ++++++++++++++++--- test/fixtures/ignore.vue | 45 ++++++++++++++++++++++ test/loader.spec.js | 10 +++++ 6 files changed, 190 insertions(+), 6 deletions(-) create mode 100644 src/utils.js create mode 100644 src/utils.spec.js create mode 100644 test/fixtures/ignore.vue diff --git a/src/index.js b/src/index.js index c8cb9a4..adc7532 100644 --- a/src/index.js +++ b/src/index.js @@ -4,6 +4,7 @@ const loaderUtils = require('loader-utils') const qs = require('querystring') const inject = require('./inject') +const { filterDescriptors } = require('./utils') const defaultOptions = { injectAt: '__docgenInfo' @@ -45,7 +46,15 @@ module.exports = async function(content, map) { infoOrPromise instanceof Promise ? await infoOrPromise : infoOrPromise ) - callback(null, inject(content, allInfo, options.injectAt), map) + const filteredInfo = allInfo.map(info => { + return { + ...info, + props: filterDescriptors(info.props, prop => !isIgnoredProps(prop)), + events: filterDescriptors(info.events, ev => !isIgnoredEvent(ev)) + } + }) + + callback(null, inject(content, filteredInfo, options.injectAt), map) } catch (e) { if (e instanceof Error) { e.message = @@ -61,3 +70,15 @@ function attemptMultiParse(content, path, options) { if (docgen.parseMulti) return docgen.parseMulti(path, options) else return docgen.parseSource(content, path, options) } + +function isIgnoredProps(propDescriptor) { + return propDescriptor.tags && propDescriptor.tags.ignore +} + +function isIgnoredEvent(eventDescriptor) { + return ( + eventDescriptor.tags && + eventDescriptor.tags instanceof Array && + eventDescriptor.tags.find(t => t.title === 'ignore') + ) +} diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..e747ec7 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,27 @@ +/** + * Filter descriptors with given function. + * @param {Object[] | {[name: string]: Object}} descriptors + * A list of descriptors. + * - vue-docgen-api < v4 ... descriptors is key-values + * - vue-docgen-api >= v4 ... descriptors is an array of objects + * @param {(descriptor: Object) => boolean} filterFn + * Same as Array.prototype.filter but no index and self arguments. + */ +function filterDescriptors(descriptors, filterFn) { + if (!descriptors) { + // return falsy values as-is + return descriptors + } + + if (descriptors instanceof Array) { + return descriptors.filter(filterFn) + } + + const entries = Object.entries(descriptors).filter(([, descriptor]) => + filterFn(descriptor) + ) + + return entries.reduce((obj, [key, value]) => ({ ...obj, [key]: value }), {}) +} + +exports.filterDescriptors = filterDescriptors diff --git a/src/utils.spec.js b/src/utils.spec.js new file mode 100644 index 0000000..2774f2c --- /dev/null +++ b/src/utils.spec.js @@ -0,0 +1,52 @@ +describe('#filterDescriptors', () => { + const { filterDescriptors } = require('./utils') + + it('Should apply filter function to an array of descriptors', () => { + const input = [ + { + name: 'foo', + required: true + }, + { + name: 'bar', + required: false + } + ] + + const expected = [ + { + name: 'foo', + required: true + } + ] + + expect(filterDescriptors(input, d => d.required)).toEqual(expected) + }) + + it('Should apply filter function to key-value pairs', () => { + const input = { + foo: { + name: 'foo', + required: true + }, + bar: { + name: 'bar', + required: false + } + } + + const expected = { + foo: { + name: 'foo', + required: true + } + } + + expect(filterDescriptors(input, d => d.required)).toEqual(expected) + }) + + it('Should return falsy values as-is', () => { + expect(filterDescriptors(null, d => d.required)).toBeNull() + expect(filterDescriptors(void 0, d => d.required)).toBeUndefined() + }) +}) diff --git a/test/__snapshots__/loader.spec.js.snap b/test/__snapshots__/loader.spec.js.snap index e114ff1..2b20033 100644 --- a/test/__snapshots__/loader.spec.js.snap +++ b/test/__snapshots__/loader.spec.js.snap @@ -13,7 +13,6 @@ Object { }, "description": "Description of foo.", "name": "foo", - "tags": Object {}, "type": Object { "name": "string", }, @@ -36,7 +35,6 @@ Object { }, "description": "Foo the number.", "name": "foo", - "tags": Object {}, "type": Object { "name": "number", }, @@ -59,7 +57,6 @@ Object { }, "description": "Foo the number.", "name": "foo", - "tags": Object {}, "type": Object { "name": "number", }, @@ -81,7 +78,6 @@ Object { }, "description": "Foo the number.", "name": "foo", - "tags": Object {}, "type": Object { "name": "number", }, @@ -103,7 +99,6 @@ Object { }, "description": "Foo the number.", "name": "foo", - "tags": Object {}, "type": Object { "name": "number", }, @@ -112,3 +107,37 @@ Object { "tags": Object {}, } `; + +exports[`Should ignore props/events with @ignore JSDoc tag 1`] = ` +Object { + "description": "", + "displayName": "ignore", + "events": Array [ + Object { + "description": "Not ignored.", + "name": "qux", + }, + ], + "exportName": "default", + "props": Array [ + Object { + "defaultValue": Object { + "func": false, + "value": "Infinity", + }, + "description": "Not ignored.", + "name": "bar", + "type": Object { + "name": "number", + }, + }, + ], + "slots": Array [ + Object { + "description": "Slots can't be ignored for now.", + "name": "default", + }, + ], + "tags": Object {}, +} +`; diff --git a/test/fixtures/ignore.vue b/test/fixtures/ignore.vue new file mode 100644 index 0000000..75b115f --- /dev/null +++ b/test/fixtures/ignore.vue @@ -0,0 +1,45 @@ + + + diff --git a/test/loader.spec.js b/test/loader.spec.js index ca6d0fb..378c006 100644 --- a/test/loader.spec.js +++ b/test/loader.spec.js @@ -64,3 +64,13 @@ it('Specify property name to inject docgen info at', async () => { await renderComponent(output, fixture, mod => mod.MyButton, '__DOCGEN__') }) + +it('Should ignore props/events with @ignore JSDoc tag', async () => { + const stats = await compiler('./fixtures/ignore.vue') + const output = stats.toJson().modules[0].modules[0].source + + const docgenPattern = /\.__docgenInfo\s?=\s?(\{[\s\S]*})/ + + expect(output).toMatch(docgenPattern) + expect(JSON.parse(output.match(docgenPattern)[1])).toMatchSnapshot() +})