diff --git a/packages/component-meta/lib/base.ts b/packages/component-meta/lib/base.ts index 4e959b11a..13f8cd84b 100644 --- a/packages/component-meta/lib/base.ts +++ b/packages/component-meta/lib/base.ts @@ -565,6 +565,7 @@ function createSchemaResolvers( return { name: (typeChecker.getTypeOfSymbolAtLocation(call.parameters[0], symbolNode) as ts.StringLiteralType).value, + description: ts.displayPartsToString(call.getDocumentationComment(typeChecker)), type: typeChecker.typeToString(subtype), rawType: rawType ? subtype : undefined, signature: typeChecker.signatureToString(call), diff --git a/packages/component-meta/lib/types.ts b/packages/component-meta/lib/types.ts index 0a14954b7..8154039f6 100644 --- a/packages/component-meta/lib/types.ts +++ b/packages/component-meta/lib/types.ts @@ -36,6 +36,7 @@ export interface PropertyMeta { export interface EventMeta { name: string; + description: string; type: string; rawType?: ts.Type; signature: string; diff --git a/packages/component-meta/tests/index.spec.ts b/packages/component-meta/tests/index.spec.ts index cc9aff864..7b7bcf5a6 100644 --- a/packages/component-meta/tests/index.spec.ts +++ b/packages/component-meta/tests/index.spec.ts @@ -26,14 +26,14 @@ const worker = (checker: ComponentMetaChecker, withTsconfig: boolean) => describ // expect(meta.type).toEqual(TypeMeta.Class); const foo = meta.props.find(prop => prop.name === 'foo'); - const onUpdateFoo = meta.events.find(event => event.name === 'update:foo') + const onUpdateFoo = meta.events.find(event => event.name === 'update:foo'); const bar = meta.props.find(prop => prop.name === 'bar'); - const onUpdateBar = meta.events.find(event => event.name === 'update:bar') + const onUpdateBar = meta.events.find(event => event.name === 'update:bar'); const qux = meta.props.find(prop => prop.name === 'qux'); const quxModifiers = meta.props.find(prop => prop.name === 'quxModifiers'); - const onUpdateQux = meta.events.find(event => event.name === 'update:qux') + const onUpdateQux = meta.events.find(event => event.name === 'update:qux'); expect(foo).toBeDefined(); expect(bar).toBeDefined(); @@ -42,7 +42,7 @@ const worker = (checker: ComponentMetaChecker, withTsconfig: boolean) => describ expect(onUpdateFoo).toBeDefined(); expect(onUpdateBar).toBeDefined(); expect(onUpdateQux).toBeDefined(); - }) + }); test('reference-type-props', () => { const componentPath = path.resolve(__dirname, '../../../test-workspace/component-meta/reference-type-props/component.vue'); @@ -724,6 +724,23 @@ const worker = (checker: ComponentMetaChecker, withTsconfig: boolean) => describ expect(b).toBeDefined(); }); + test('emits-generic', () => { + const componentPath = path.resolve(__dirname, '../../../test-workspace/component-meta/events/component-generic.vue'); + const meta = checker.getComponentMeta(componentPath); + const foo = meta.events.find(event =>event.name === 'foo'); + + expect(foo?.description).toBe('Emitted when foo...'); + }); + + // Wait for https://github.com/vuejs/core/pull/10801 + test.skip('emits-class', () => { + const componentPath = path.resolve(__dirname, '../../../test-workspace/component-meta/events/component-class.vue'); + const meta = checker.getComponentMeta(componentPath); + const foo = meta.events.find(event =>event.name === 'foo'); + + expect(foo?.description).toBe('Emitted when foo...'); + }); + test('ts-named-exports', () => { const componentPath = path.resolve(__dirname, '../../../test-workspace/component-meta/ts-named-export/component.ts'); const exportNames = checker.getExportNames(componentPath); diff --git a/packages/language-core/lib/codegen/script/component.ts b/packages/language-core/lib/codegen/script/component.ts index 5f73d41e8..31ab11a33 100644 --- a/packages/language-core/lib/codegen/script/component.ts +++ b/packages/language-core/lib/codegen/script/component.ts @@ -117,4 +117,7 @@ export function* generateScriptSetupOptions( if (scriptSetupRanges.props.define?.typeArg) { yield `__typeProps: typeof __VLS_typeProps,${newLine}`; } + if (scriptSetupRanges.emits.define) { + yield `__typeEmits: typeof ${scriptSetupRanges.emits.name ?? '__VLS_emit'},${newLine}`; + } } diff --git a/packages/tsc/tests/__snapshots__/dts.spec.ts.snap b/packages/tsc/tests/__snapshots__/dts.spec.ts.snap index 40975f581..01f1312db 100644 --- a/packages/tsc/tests/__snapshots__/dts.spec.ts.snap +++ b/packages/tsc/tests/__snapshots__/dts.spec.ts.snap @@ -28,6 +28,51 @@ export default _default; " `; +exports[`vue-tsc-dts > Input: events/component-class.vue, Output: events/component-class.vue.d.ts 1`] = ` +"declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, { + foo: (value: string) => void; +}, string, import("vue").PublicProps, Readonly> & { + onFoo?: (value: string) => any; +}, {}, {}>; +export default _default; +" +`; + +exports[`vue-tsc-dts > Input: events/component-generic.vue, Output: events/component-generic.vue.d.ts 1`] = ` +"declare const _default: (__VLS_props: { + onFoo?: (value: string) => any; +} & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, __VLS_ctx?: { + slots: {}; + attrs: any; + emit: (evt: "foo", value: string) => void; +}, __VLS_expose?: (exposed: import('vue').ShallowUnwrapRef<{}>) => void, __VLS_setup?: Promise<{ + props: { + onFoo?: (value: string) => any; + } & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps; + expose(exposed: import('vue').ShallowUnwrapRef<{}>): void; + attrs: any; + slots: {}; + emit: (evt: "foo", value: string) => void; +}>) => import("vue").VNode & { + __ctx?: { + props: { + onFoo?: (value: string) => any; + } & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps; + expose(exposed: import('vue').ShallowUnwrapRef<{}>): void; + attrs: any; + slots: {}; + emit: (evt: "foo", value: string) => void; + }; +}; +export default _default; +type __VLS_Prettify = { + [K in keyof T]: T[K]; +} & {}; +" +`; + exports[`vue-tsc-dts > Input: generic/component.vue, Output: generic/component.vue.d.ts 1`] = ` "declare const _default: (__VLS_props: { onBar?: (data: number) => any; @@ -268,13 +313,13 @@ exports[`vue-tsc-dts > Input: reference-type-events/component.vue, Output: refer }) => void; baz: () => void; }, string, import("vue").PublicProps, Readonly> & { + onFoo?: (data?: { + foo: string; + }) => any; onBar?: (value: { arg1: number; arg2?: any; }) => any; - onFoo?: (data?: { - foo: string; - }) => any; onBaz?: () => any; }, {}, {}>; export default _default; diff --git a/test-workspace/component-meta/events/component-class.vue b/test-workspace/component-meta/events/component-class.vue new file mode 100644 index 000000000..abe106e08 --- /dev/null +++ b/test-workspace/component-meta/events/component-class.vue @@ -0,0 +1,6 @@ + diff --git a/test-workspace/component-meta/events/component-generic.vue b/test-workspace/component-meta/events/component-generic.vue new file mode 100644 index 000000000..592c5ccff --- /dev/null +++ b/test-workspace/component-meta/events/component-generic.vue @@ -0,0 +1,6 @@ +