diff --git a/README.md b/README.md index 651ddac9c5..e790e63eee 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ If you want to work on the volar extension follow these commands to set up your git clone https://github.com/vuejs/language-tools.git cd language-tools pnpm install -run build +npm run build ``` The recommended way to develop the volar extension is to use the [Debug Tools](https://code.visualstudio.com/Docs/editor/debugging) provided by VSCode. @@ -84,7 +84,7 @@ Alternatively, you can run one of the scripts defined in the [package.json](http Additional info for contributing to open source projects can be found here: https://docs.github.com/en/get-started/quickstart/contributing-to-projects -To develop with upstream Volar.js modules, you can setup workspace with https://github.com/volarjs/workspace. +To develop with upstream Volar.js modules, you can setup a workspace with https://github.com/volarjs/workspace. ## ❤️ Thanks to Our Sponsors diff --git a/packages/component-meta/lib/base.ts b/packages/component-meta/lib/base.ts index 477c3cb94b..cdd21d14de 100644 --- a/packages/component-meta/lib/base.ts +++ b/packages/component-meta/lib/base.ts @@ -641,6 +641,13 @@ function createSchemaResolvers( return acc; } + function getJsDocTags(target: ts.Symbol | ts.Signature) { + return target.getJsDocTags(typeChecker).map(tag => ({ + name: tag.name, + text: tag.text !== undefined ? ts.displayPartsToString(tag.text) : undefined, + })); + } + function resolveNestedProperties(prop: ts.Symbol): PropertyMeta { const subtype = typeChecker.getTypeOfSymbolAtLocation(prop, symbolNode); let schema: PropertyMetaSchema | undefined; @@ -650,10 +657,7 @@ function createSchemaResolvers( name: prop.getEscapedName().toString(), global: false, description: ts.displayPartsToString(prop.getDocumentationComment(typeChecker)), - tags: prop.getJsDocTags(typeChecker).map(tag => ({ - name: tag.name, - text: tag.text !== undefined ? ts.displayPartsToString(tag.text) : undefined, - })), + tags: getJsDocTags(prop), required: !(prop.flags & ts.SymbolFlags.Optional), type: getFullyQualifiedName(subtype), get declarations() { @@ -680,6 +684,7 @@ function createSchemaResolvers( name: prop.getName(), type: getFullyQualifiedName(subtype), description: ts.displayPartsToString(prop.getDocumentationComment(typeChecker)), + tags: getJsDocTags(prop), get declarations() { return declarations ??= getDeclarations(prop.declarations ?? []); }, @@ -701,6 +706,7 @@ function createSchemaResolvers( name: expose.getName(), type: getFullyQualifiedName(subtype), description: ts.displayPartsToString(expose.getDocumentationComment(typeChecker)), + tags: getJsDocTags(expose), get declarations() { return declarations ??= getDeclarations(expose.declarations ?? []); }, @@ -748,10 +754,7 @@ function createSchemaResolvers( return { name: (typeChecker.getTypeOfSymbolAtLocation(call.parameters[0]!, symbolNode) as ts.StringLiteralType).value, description: ts.displayPartsToString(call.getDocumentationComment(typeChecker)), - tags: call.getJsDocTags().map(tag => ({ - name: tag.name, - text: tag.text !== undefined ? ts.displayPartsToString(tag.text) : undefined, - })), + tags: getJsDocTags(call), type: subtypeStr, signature: typeChecker.signatureToString(call), get declarations() { diff --git a/packages/component-meta/lib/types.ts b/packages/component-meta/lib/types.ts index 50e9be00be..dfcb23ee5a 100644 --- a/packages/component-meta/lib/types.ts +++ b/packages/component-meta/lib/types.ts @@ -25,11 +25,11 @@ export enum TypeMeta { export interface PropertyMeta { name: string; - default?: string; description: string; + type: string; + default?: string; global: boolean; required: boolean; - type: string; tags: { name: string; text?: string }[]; declarations: Declaration[]; schema: PropertyMetaSchema; @@ -57,8 +57,9 @@ export interface EventMeta { export interface SlotMeta { name: string; - type: string; description: string; + type: string; + tags: { name: string; text?: string }[]; declarations: Declaration[]; schema: PropertyMetaSchema; /** @@ -72,6 +73,7 @@ export interface ExposeMeta { name: string; description: string; type: string; + tags: { name: string; text?: string }[]; declarations: Declaration[]; schema: PropertyMetaSchema; /** diff --git a/packages/component-meta/tests/index.spec.ts b/packages/component-meta/tests/index.spec.ts index a46e31a1af..441dc16544 100644 --- a/packages/component-meta/tests/index.spec.ts +++ b/packages/component-meta/tests/index.spec.ts @@ -1181,6 +1181,18 @@ const worker = (checker: ComponentMetaChecker, withTsconfig: boolean) => expect(b).toBeDefined(); expect(c).toBeDefined(); expect(d).toBeDefined(); + + expect(c).toStrictEqual(expect.objectContaining( + { + description: 'Slot with tags', + tags: [ + { + name: 'deprecated', + text: 'do not use', + }, + ], + }, + )); }); test('reference-type-slots w/ generic', () => { @@ -1205,6 +1217,8 @@ const worker = (checker: ComponentMetaChecker, withTsconfig: boolean) => expect(meta.type).toEqual(TypeMeta.Class); const counter = meta.exposed.find(exposed => exposed.name === 'counter'); + const oldCounter = meta.exposed.find(exposed => exposed.name === 'oldCounter'); + expect(counter).toMatchInlineSnapshot(` { "declarations": [], @@ -1213,9 +1227,21 @@ const worker = (checker: ComponentMetaChecker, withTsconfig: boolean) => "name": "counter", "rawType": undefined, "schema": "string", + "tags": [], "type": "string", } `); + expect(oldCounter).toStrictEqual(expect.objectContaining( + { + description: 'an oldCounter string', + tags: [ + { + name: 'deprecated', + text: 'use counter instead', + }, + ], + }, + )); }); test('component with both props and events', () => { diff --git a/packages/tsc/tests/__snapshots__/dts.spec.ts.snap b/packages/tsc/tests/__snapshots__/dts.spec.ts.snap index fa7840dfd3..eeb0fc48e5 100644 --- a/packages/tsc/tests/__snapshots__/dts.spec.ts.snap +++ b/packages/tsc/tests/__snapshots__/dts.spec.ts.snap @@ -385,13 +385,9 @@ export {}; `; exports[`Input: reference-type-exposed/component.vue, Output: reference-type-exposed/component.vue.d.ts 1`] = ` -"declare const __VLS_export: import("vue").DefineComponent2<{ - setup(): { - /** - * a counter string - */ - counter: import("vue").Ref; - }; +"import type { MyExposed } from './my-exposed'; +declare const __VLS_export: import("vue").DefineComponent2<{ + setup(): MyExposed; data(): {}; props: {}; computed: {}; @@ -416,6 +412,22 @@ export default _default; " `; +exports[`Input: reference-type-exposed/my-exposed.ts, Output: reference-type-exposed/my-exposed.d.ts 1`] = ` +"import type { Ref } from 'vue'; +export interface MyExposed { + /** + * a counter string + */ + counter: Ref; + /** + * an oldCounter string + * @deprecated use counter instead + */ + oldCounter: Ref; +} +" +`; + exports[`Input: reference-type-model/component.vue, Output: reference-type-model/component.vue.d.ts 1`] = ` "type __VLS_ModelProps = { /** @@ -803,20 +815,8 @@ type __VLS_WithSlots = T & { `; exports[`Input: reference-type-slots/component-define-slots.vue, Output: reference-type-slots/component-define-slots.vue.d.ts 1`] = ` -"import type { VNode } from 'vue'; -type __VLS_Slots = { - default: (props: { - num: number; - }) => VNode[]; - 'named-slot': (props: { - str: string; - }) => VNode[]; - vbind: (props: { - num: number; - str: string; - }) => VNode[]; - 'no-bind': () => VNode[]; -}; +"import type { MySlots } from './my-slots'; +type __VLS_Slots = MySlots; declare const __VLS_base: import("vue").DefineComponent2<{ setup(): {}; data(): {}; @@ -899,6 +899,31 @@ type __VLS_WithSlots = T & { " `; +exports[`Input: reference-type-slots/my-slots.ts, Output: reference-type-slots/my-slots.d.ts 1`] = ` +"import type { VNode } from 'vue'; +export interface MySlots { + /** + * Default slot + */ + default: (props: { + num: number; + }) => VNode[]; + 'named-slot': (props: { + str: string; + }) => VNode[]; + /** + * Slot with tags + * @deprecated do not use + */ + vbind: (props: { + num: number; + str: string; + }) => VNode[]; + 'no-bind': () => VNode[]; +} +" +`; + exports[`Input: ts-component/PropDefinitions.ts, Output: ts-component/PropDefinitions.d.ts 1`] = ` "export interface MyProps { /** diff --git a/test-workspace/component-meta/reference-type-exposed/component.vue b/test-workspace/component-meta/reference-type-exposed/component.vue index a8796adc83..a9c4bf47f0 100644 --- a/test-workspace/component-meta/reference-type-exposed/component.vue +++ b/test-workspace/component-meta/reference-type-exposed/component.vue @@ -1,12 +1,12 @@ \ No newline at end of file diff --git a/test-workspace/component-meta/reference-type-exposed/my-exposed.ts b/test-workspace/component-meta/reference-type-exposed/my-exposed.ts new file mode 100644 index 0000000000..58c35a63e9 --- /dev/null +++ b/test-workspace/component-meta/reference-type-exposed/my-exposed.ts @@ -0,0 +1,13 @@ +import type { Ref } from 'vue'; + +export interface MyExposed { + /** + * a counter string + */ + counter: Ref; + /** + * an oldCounter string + * @deprecated use counter instead + */ + oldCounter: Ref; +} diff --git a/test-workspace/component-meta/reference-type-slots/component-define-slots.vue b/test-workspace/component-meta/reference-type-slots/component-define-slots.vue index bf348e0e7f..2d3f51f6db 100644 --- a/test-workspace/component-meta/reference-type-slots/component-define-slots.vue +++ b/test-workspace/component-meta/reference-type-slots/component-define-slots.vue @@ -3,12 +3,7 @@ diff --git a/test-workspace/component-meta/reference-type-slots/my-slots.ts b/test-workspace/component-meta/reference-type-slots/my-slots.ts new file mode 100644 index 0000000000..3ed788f3eb --- /dev/null +++ b/test-workspace/component-meta/reference-type-slots/my-slots.ts @@ -0,0 +1,15 @@ +import type { VNode } from 'vue'; + +export interface MySlots { + /** + * Default slot + */ + default: (props: { num: number }) => VNode[]; + 'named-slot': (props: { str: string }) => VNode[]; + /** + * Slot with tags + * @deprecated do not use + */ + vbind: (props: { num: number; str: string }) => VNode[]; + 'no-bind': () => VNode[]; +}