From 33e8bc4922b595db007cf54e0eceec63b00a2b95 Mon Sep 17 00:00:00 2001 From: Bart Ledoux Date: Mon, 21 Jan 2019 17:20:54 -0600 Subject: [PATCH 1/5] fix: describe typo --- src/script-handlers/__tests__/eventHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/script-handlers/__tests__/eventHandler.ts b/src/script-handlers/__tests__/eventHandler.ts index 45537c6..15418be 100644 --- a/src/script-handlers/__tests__/eventHandler.ts +++ b/src/script-handlers/__tests__/eventHandler.ts @@ -11,7 +11,7 @@ function parse(src: string): NodePath[] { return resolveExportedComponent(ast) } -describe('displayNameHandler', () => { +describe('eventHandler', () => { let documentation: Documentation let mockEventDescriptor: EventDescriptor From 7c0d6728166869f45167588edfe54a66370e48e5 Mon Sep 17 00:00:00 2001 From: Bart Ledoux Date: Mon, 21 Jan 2019 17:21:09 -0600 Subject: [PATCH 2/5] feat: handle slots in render functions --- src/script-handlers/__tests__/slotHandler.ts | 54 ++++++++++++++++++++ src/script-handlers/slotHandler.ts | 53 +++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 src/script-handlers/__tests__/slotHandler.ts create mode 100644 src/script-handlers/slotHandler.ts diff --git a/src/script-handlers/__tests__/slotHandler.ts b/src/script-handlers/__tests__/slotHandler.ts new file mode 100644 index 0000000..47e8c05 --- /dev/null +++ b/src/script-handlers/__tests__/slotHandler.ts @@ -0,0 +1,54 @@ +import { NodePath } from 'ast-types' +import babylon from '../../babel-parser' +import { Documentation, SlotDescriptor } from '../../Documentation' +import resolveExportedComponent from '../../utils/resolveExportedComponent' +import slotHandler from '../slotHandler' + +jest.mock('../../Documentation') + +function parse(src: string): NodePath[] { + const ast = babylon().parse(src) + return resolveExportedComponent(ast) +} + +describe('render function slotHandler', () => { + let documentation: Documentation + let mockSlotDescriptor: SlotDescriptor + + beforeEach(() => { + mockSlotDescriptor = { description: '' } + documentation = new (require('../../Documentation')).Documentation() + const mockGetSlotDescriptor = documentation.getSlotDescriptor as jest.Mock + mockGetSlotDescriptor.mockReturnValue(mockSlotDescriptor) + }) + + it('should find slots in render function', () => { + const src = ` + export default { + render: function (createElement) { + return createElement('div', this.$slots.mySlot) + } + } + ` + const def = parse(src) + slotHandler(documentation, def[0]) + expect(documentation.getSlotDescriptor).toHaveBeenCalledWith('mySlot') + }) + + it('should find scoped slots in render function', () => { + const src = ` + export default { + render: function (createElement) { + return createElement('div', [ + this.$scopedSlots.myScopedSlot({ + text: this.message + }) + ]) + } + } + ` + const def = parse(src) + slotHandler(documentation, def[0]) + expect(documentation.getSlotDescriptor).toHaveBeenCalledWith('myScopedSlot') + }) +}) diff --git a/src/script-handlers/slotHandler.ts b/src/script-handlers/slotHandler.ts new file mode 100644 index 0000000..014c8dc --- /dev/null +++ b/src/script-handlers/slotHandler.ts @@ -0,0 +1,53 @@ +import * as bt from '@babel/types' +import { NodePath } from 'ast-types' +import { Documentation, ParamTag, ParamType } from '../Documentation' + +export interface TypedParamTag extends ParamTag { + type: ParamType +} + +// tslint:disable-next-line:no-var-requires +import recast = require('recast') + +export default function eventHandler(documentation: Documentation, path: NodePath) { + if (bt.isObjectExpression(path.node)) { + const renderPath = path + .get('properties') + .filter((p: NodePath) => bt.isObjectProperty(p.node) && p.node.key.name === 'render') + + // if no prop return + if (!renderPath.length) { + return + } + + const renderValuePath = renderPath[0].get('value') + recast.visit(renderValuePath, { + visitCallExpression(pathCall: NodePath) { + if ( + bt.isMemberExpression(pathCall.node.callee) && + bt.isMemberExpression(pathCall.node.callee.object) && + bt.isThisExpression(pathCall.node.callee.object.object) && + bt.isIdentifier(pathCall.node.callee.property) && + pathCall.node.callee.object.property.name === '$scopedSlots' + ) { + documentation.getSlotDescriptor(pathCall.node.callee.property.name) + return false + } + this.traverse(pathCall) + }, + visitMemberExpression(pathMember: NodePath) { + if ( + bt.isMemberExpression(pathMember.node.object) && + bt.isThisExpression(pathMember.node.object.object) && + bt.isIdentifier(pathMember.node.object.property) && + pathMember.node.object.property.name === '$slots' && + bt.isIdentifier(pathMember.node.property) + ) { + documentation.getSlotDescriptor(pathMember.node.property.name) + return false + } + this.traverse(pathMember) + }, + }) + } +} From 970318f06b4345d503744780382941ed8b1b9113 Mon Sep 17 00:00:00 2001 From: Bart Ledoux Date: Tue, 22 Jan 2019 09:19:37 -0600 Subject: [PATCH 3/5] fix: extract prop type from decorator arguments as well --- src/script-handlers/__tests__/classPropHandler.ts | 13 +++++++++++++ src/script-handlers/classPropHandler.ts | 6 +++++- src/script-handlers/propHandler.ts | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/script-handlers/__tests__/classPropHandler.ts b/src/script-handlers/__tests__/classPropHandler.ts index f28ae37..0b476b6 100644 --- a/src/script-handlers/__tests__/classPropHandler.ts +++ b/src/script-handlers/__tests__/classPropHandler.ts @@ -100,5 +100,18 @@ describe('propHandler', () => { }) expect(documentation.getPropDescriptor).toHaveBeenCalledWith('testDescribed') }) + + it('should extract type from decorator arguments', () => { + const src = ` + @Component + export default class MyTest { + @Prop({type:String}) + testTyped; + }` + tester(src, { + type: { name: 'string' }, + }) + expect(documentation.getPropDescriptor).toHaveBeenCalledWith('testTyped') + }) }) }) diff --git a/src/script-handlers/classPropHandler.ts b/src/script-handlers/classPropHandler.ts index 61bde39..bbdae95 100644 --- a/src/script-handlers/classPropHandler.ts +++ b/src/script-handlers/classPropHandler.ts @@ -5,7 +5,7 @@ import getDocblock from '../utils/getDocblock' import getDoclets from '../utils/getDoclets' import getTypeFromAnnotation from '../utils/getTypeFromAnnotation' import transformTagsIntoObject from '../utils/transformTagsIntoObject' -import { describeDefault, describeRequired } from './propHandler' +import { describeDefault, describeRequired, describeType } from './propHandler' export default function propHandler( documentation: Documentation, @@ -60,6 +60,10 @@ export default function propHandler( .filter((p: NodePath) => bt.isObjectProperty(p.node)) as Array< NodePath > + // if there is no type annotation, get it from the decorators arguments + if (!propPath.node.typeAnnotation) { + describeType(propsPath, propDescriptor) + } describeDefault(propsPath, propDescriptor) describeRequired(propsPath, propDescriptor) } diff --git a/src/script-handlers/propHandler.ts b/src/script-handlers/propHandler.ts index 9cb2948..df340b0 100644 --- a/src/script-handlers/propHandler.ts +++ b/src/script-handlers/propHandler.ts @@ -85,7 +85,7 @@ export default function propHandler(documentation: Documentation, path: NodePath } } -function describeType( +export function describeType( propPropertiesPath: Array>, propDescriptor: PropDescriptor, ) { From 7192aad3d9c3523a2d1d918a865f1e18c563b6ae Mon Sep 17 00:00:00 2001 From: Bart Ledoux Date: Tue, 22 Jan 2019 09:23:12 -0600 Subject: [PATCH 4/5] add e2e tests to show it off --- tests/components/button-typescript/Button.vue | 11 ++++++++++- .../__snapshots__/button-ts.test.ts.snap | 10 +++++++++- tests/components/button-typescript/button-ts.test.ts | 4 ++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/tests/components/button-typescript/Button.vue b/tests/components/button-typescript/Button.vue index 0b9ed3e..1eb3416 100644 --- a/tests/components/button-typescript/Button.vue +++ b/tests/components/button-typescript/Button.vue @@ -15,7 +15,13 @@ import { Component, Prop, Vue } from 'vue-property-decorator' */ @Component export default class MyComponent extends Vue { - @Prop() propA: number + aHiddenData: string + + @Prop({ type: String }) + propNoType + + @Prop + propA: number @Prop({ default: 'default value' }) propB: string @@ -28,6 +34,9 @@ export default class MyComponent extends Vue { * @public */ onClick(a: string) { + /** + * Success event when we click + */ this.$emit('success', a) } } diff --git a/tests/components/button-typescript/__snapshots__/button-ts.test.ts.snap b/tests/components/button-typescript/__snapshots__/button-ts.test.ts.snap index bfee00e..9030dca 100644 --- a/tests/components/button-typescript/__snapshots__/button-ts.test.ts.snap +++ b/tests/components/button-typescript/__snapshots__/button-ts.test.ts.snap @@ -6,7 +6,7 @@ Object { "displayName": "MyComponent", "events": Object { "success": Object { - "description": "", + "description": "Success event when we click", "properties": Array [ Object { "name": "", @@ -70,6 +70,14 @@ Object { "name": "TSUnionType", }, }, + "propNoType": Object { + "description": "", + "required": "", + "tags": Object {}, + "type": Object { + "name": "string", + }, + }, }, "slots": Object { "default": Object { diff --git a/tests/components/button-typescript/button-ts.test.ts b/tests/components/button-typescript/button-ts.test.ts index 5ab25e9..133c953 100644 --- a/tests/components/button-typescript/button-ts.test.ts +++ b/tests/components/button-typescript/button-ts.test.ts @@ -23,6 +23,10 @@ describe('tests button', () => { beforeEach(() => { props = docButton.props || {} }) + it('should return propNoType type as string', () => { + expect(props.propNoType.type).toMatchObject({ name: 'string' }) + }) + it('should return propA type as number', () => { expect(props.propA.type).toMatchObject({ name: 'number' }) }) From c6835f3bb9bd7f545285aefeb6516bb3324ab59d Mon Sep 17 00:00:00 2001 From: Bart Ledoux Date: Tue, 22 Jan 2019 09:25:21 -0600 Subject: [PATCH 5/5] add description to show how to use it --- tests/components/button-typescript/Button.vue | 14 +++++++++++++- .../__snapshots__/button-ts.test.ts.snap | 8 ++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/tests/components/button-typescript/Button.vue b/tests/components/button-typescript/Button.vue index 1eb3416..1a7a25c 100644 --- a/tests/components/button-typescript/Button.vue +++ b/tests/components/button-typescript/Button.vue @@ -17,16 +17,28 @@ import { Component, Prop, Vue } from 'vue-property-decorator' export default class MyComponent extends Vue { aHiddenData: string + /** + * An example of a property typed through the decorators arguments + */ @Prop({ type: String }) propNoType + /** + * An example of a property typed through the annotation + */ @Prop propA: number + /** + * A prop with a default value + */ @Prop({ default: 'default value' }) propB: string - @Prop([String, Boolean]) + /** + * A prop with a hybrid type + */ + @Prop propC: string | boolean /** diff --git a/tests/components/button-typescript/__snapshots__/button-ts.test.ts.snap b/tests/components/button-typescript/__snapshots__/button-ts.test.ts.snap index 9030dca..f5116ba 100644 --- a/tests/components/button-typescript/__snapshots__/button-ts.test.ts.snap +++ b/tests/components/button-typescript/__snapshots__/button-ts.test.ts.snap @@ -45,7 +45,7 @@ Object { ], "props": Object { "propA": Object { - "description": "", + "description": "An example of a property typed through the annotation", "tags": Object {}, "type": Object { "name": "number", @@ -56,7 +56,7 @@ Object { "func": false, "value": "'default value'", }, - "description": "", + "description": "A prop with a default value", "required": "", "tags": Object {}, "type": Object { @@ -64,14 +64,14 @@ Object { }, }, "propC": Object { - "description": "", + "description": "A prop with a hybrid type", "tags": Object {}, "type": Object { "name": "TSUnionType", }, }, "propNoType": Object { - "description": "", + "description": "An example of a property typed through the decorators arguments", "required": "", "tags": Object {}, "type": Object {