Skip to content

Commit a144b6b

Browse files
authored
feat(component-meta): add tags to slots and exposed (#5862)
1 parent b780861 commit a144b6b

File tree

9 files changed

+125
-46
lines changed

9 files changed

+125
-46
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ If you want to work on the volar extension follow these commands to set up your
7474
git clone https://github.com/vuejs/language-tools.git
7575
cd language-tools
7676
pnpm install
77-
run build
77+
npm run build
7878
```
7979

8080
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
8484

8585
Additional info for contributing to open source projects can be found here: https://docs.github.com/en/get-started/quickstart/contributing-to-projects
8686

87-
To develop with upstream Volar.js modules, you can setup workspace with https://github.com/volarjs/workspace.
87+
To develop with upstream Volar.js modules, you can setup a workspace with https://github.com/volarjs/workspace.
8888

8989
## ❤️ Thanks to Our Sponsors
9090

packages/component-meta/lib/base.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,13 @@ function createSchemaResolvers(
641641
return acc;
642642
}
643643

644+
function getJsDocTags(target: ts.Symbol | ts.Signature) {
645+
return target.getJsDocTags(typeChecker).map(tag => ({
646+
name: tag.name,
647+
text: tag.text !== undefined ? ts.displayPartsToString(tag.text) : undefined,
648+
}));
649+
}
650+
644651
function resolveNestedProperties(prop: ts.Symbol): PropertyMeta {
645652
const subtype = typeChecker.getTypeOfSymbolAtLocation(prop, symbolNode);
646653
let schema: PropertyMetaSchema | undefined;
@@ -650,10 +657,7 @@ function createSchemaResolvers(
650657
name: prop.getEscapedName().toString(),
651658
global: false,
652659
description: ts.displayPartsToString(prop.getDocumentationComment(typeChecker)),
653-
tags: prop.getJsDocTags(typeChecker).map(tag => ({
654-
name: tag.name,
655-
text: tag.text !== undefined ? ts.displayPartsToString(tag.text) : undefined,
656-
})),
660+
tags: getJsDocTags(prop),
657661
required: !(prop.flags & ts.SymbolFlags.Optional),
658662
type: getFullyQualifiedName(subtype),
659663
get declarations() {
@@ -680,6 +684,7 @@ function createSchemaResolvers(
680684
name: prop.getName(),
681685
type: getFullyQualifiedName(subtype),
682686
description: ts.displayPartsToString(prop.getDocumentationComment(typeChecker)),
687+
tags: getJsDocTags(prop),
683688
get declarations() {
684689
return declarations ??= getDeclarations(prop.declarations ?? []);
685690
},
@@ -701,6 +706,7 @@ function createSchemaResolvers(
701706
name: expose.getName(),
702707
type: getFullyQualifiedName(subtype),
703708
description: ts.displayPartsToString(expose.getDocumentationComment(typeChecker)),
709+
tags: getJsDocTags(expose),
704710
get declarations() {
705711
return declarations ??= getDeclarations(expose.declarations ?? []);
706712
},
@@ -748,10 +754,7 @@ function createSchemaResolvers(
748754
return {
749755
name: (typeChecker.getTypeOfSymbolAtLocation(call.parameters[0]!, symbolNode) as ts.StringLiteralType).value,
750756
description: ts.displayPartsToString(call.getDocumentationComment(typeChecker)),
751-
tags: call.getJsDocTags().map(tag => ({
752-
name: tag.name,
753-
text: tag.text !== undefined ? ts.displayPartsToString(tag.text) : undefined,
754-
})),
757+
tags: getJsDocTags(call),
755758
type: subtypeStr,
756759
signature: typeChecker.signatureToString(call),
757760
get declarations() {

packages/component-meta/lib/types.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ export enum TypeMeta {
2525

2626
export interface PropertyMeta {
2727
name: string;
28-
default?: string;
2928
description: string;
29+
type: string;
30+
default?: string;
3031
global: boolean;
3132
required: boolean;
32-
type: string;
3333
tags: { name: string; text?: string }[];
3434
declarations: Declaration[];
3535
schema: PropertyMetaSchema;
@@ -57,8 +57,9 @@ export interface EventMeta {
5757

5858
export interface SlotMeta {
5959
name: string;
60-
type: string;
6160
description: string;
61+
type: string;
62+
tags: { name: string; text?: string }[];
6263
declarations: Declaration[];
6364
schema: PropertyMetaSchema;
6465
/**
@@ -72,6 +73,7 @@ export interface ExposeMeta {
7273
name: string;
7374
description: string;
7475
type: string;
76+
tags: { name: string; text?: string }[];
7577
declarations: Declaration[];
7678
schema: PropertyMetaSchema;
7779
/**

packages/component-meta/tests/index.spec.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,6 +1181,18 @@ const worker = (checker: ComponentMetaChecker, withTsconfig: boolean) =>
11811181
expect(b).toBeDefined();
11821182
expect(c).toBeDefined();
11831183
expect(d).toBeDefined();
1184+
1185+
expect(c).toStrictEqual(expect.objectContaining(
1186+
{
1187+
description: 'Slot with tags',
1188+
tags: [
1189+
{
1190+
name: 'deprecated',
1191+
text: 'do not use',
1192+
},
1193+
],
1194+
},
1195+
));
11841196
});
11851197

11861198
test('reference-type-slots w/ generic', () => {
@@ -1205,6 +1217,8 @@ const worker = (checker: ComponentMetaChecker, withTsconfig: boolean) =>
12051217
expect(meta.type).toEqual(TypeMeta.Class);
12061218

12071219
const counter = meta.exposed.find(exposed => exposed.name === 'counter');
1220+
const oldCounter = meta.exposed.find(exposed => exposed.name === 'oldCounter');
1221+
12081222
expect(counter).toMatchInlineSnapshot(`
12091223
{
12101224
"declarations": [],
@@ -1213,9 +1227,21 @@ const worker = (checker: ComponentMetaChecker, withTsconfig: boolean) =>
12131227
"name": "counter",
12141228
"rawType": undefined,
12151229
"schema": "string",
1230+
"tags": [],
12161231
"type": "string",
12171232
}
12181233
`);
1234+
expect(oldCounter).toStrictEqual(expect.objectContaining(
1235+
{
1236+
description: 'an oldCounter string',
1237+
tags: [
1238+
{
1239+
name: 'deprecated',
1240+
text: 'use counter instead',
1241+
},
1242+
],
1243+
},
1244+
));
12191245
});
12201246

12211247
test('component with both props and events', () => {

packages/tsc/tests/__snapshots__/dts.spec.ts.snap

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -385,13 +385,9 @@ export {};
385385
`;
386386
387387
exports[`Input: reference-type-exposed/component.vue, Output: reference-type-exposed/component.vue.d.ts 1`] = `
388-
"declare const __VLS_export: import("vue").DefineComponent2<{
389-
setup(): {
390-
/**
391-
* a counter string
392-
*/
393-
counter: import("vue").Ref<string, string>;
394-
};
388+
"import type { MyExposed } from './my-exposed';
389+
declare const __VLS_export: import("vue").DefineComponent2<{
390+
setup(): MyExposed;
395391
data(): {};
396392
props: {};
397393
computed: {};
@@ -416,6 +412,22 @@ export default _default;
416412
"
417413
`;
418414
415+
exports[`Input: reference-type-exposed/my-exposed.ts, Output: reference-type-exposed/my-exposed.d.ts 1`] = `
416+
"import type { Ref } from 'vue';
417+
export interface MyExposed {
418+
/**
419+
* a counter string
420+
*/
421+
counter: Ref<string>;
422+
/**
423+
* an oldCounter string
424+
* @deprecated use counter instead
425+
*/
426+
oldCounter: Ref<string>;
427+
}
428+
"
429+
`;
430+
419431
exports[`Input: reference-type-model/component.vue, Output: reference-type-model/component.vue.d.ts 1`] = `
420432
"type __VLS_ModelProps = {
421433
/**
@@ -803,20 +815,8 @@ type __VLS_WithSlots<T, S> = T & {
803815
`;
804816
805817
exports[`Input: reference-type-slots/component-define-slots.vue, Output: reference-type-slots/component-define-slots.vue.d.ts 1`] = `
806-
"import type { VNode } from 'vue';
807-
type __VLS_Slots = {
808-
default: (props: {
809-
num: number;
810-
}) => VNode[];
811-
'named-slot': (props: {
812-
str: string;
813-
}) => VNode[];
814-
vbind: (props: {
815-
num: number;
816-
str: string;
817-
}) => VNode[];
818-
'no-bind': () => VNode[];
819-
};
818+
"import type { MySlots } from './my-slots';
819+
type __VLS_Slots = MySlots;
820820
declare const __VLS_base: import("vue").DefineComponent2<{
821821
setup(): {};
822822
data(): {};
@@ -899,6 +899,31 @@ type __VLS_WithSlots<T, S> = T & {
899899
"
900900
`;
901901
902+
exports[`Input: reference-type-slots/my-slots.ts, Output: reference-type-slots/my-slots.d.ts 1`] = `
903+
"import type { VNode } from 'vue';
904+
export interface MySlots {
905+
/**
906+
* Default slot
907+
*/
908+
default: (props: {
909+
num: number;
910+
}) => VNode[];
911+
'named-slot': (props: {
912+
str: string;
913+
}) => VNode[];
914+
/**
915+
* Slot with tags
916+
* @deprecated do not use
917+
*/
918+
vbind: (props: {
919+
num: number;
920+
str: string;
921+
}) => VNode[];
922+
'no-bind': () => VNode[];
923+
}
924+
"
925+
`;
926+
902927
exports[`Input: ts-component/PropDefinitions.ts, Output: ts-component/PropDefinitions.d.ts 1`] = `
903928
"export interface MyProps {
904929
/**
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<script setup lang="ts">
22
import { ref } from 'vue';
3+
import type { MyExposed } from './my-exposed';
34
45
const counter = ref('foo')
6+
const oldCounter = ref('bar')
57
6-
defineExpose({
7-
/**
8-
* a counter string
9-
*/
10-
counter
8+
defineExpose<MyExposed>({
9+
counter,
10+
oldCounter,
1111
});
1212
</script>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type { Ref } from 'vue';
2+
3+
export interface MyExposed {
4+
/**
5+
* a counter string
6+
*/
7+
counter: Ref<string>;
8+
/**
9+
* an oldCounter string
10+
* @deprecated use counter instead
11+
*/
12+
oldCounter: Ref<string>;
13+
}

test-workspace/component-meta/reference-type-slots/component-define-slots.vue

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,7 @@
33
</template>
44

55
<script setup lang="ts">
6-
import type { VNode } from 'vue'
6+
import type { MySlots } from './my-slots';
77
8-
defineSlots<{
9-
default: (props: { num: number }) => VNode[],
10-
'named-slot': (props: { str: string }) => VNode[],
11-
vbind: (props: { num: number, str: string }) => VNode[],
12-
'no-bind': () => VNode[],
13-
}>()
8+
defineSlots<MySlots>()
149
</script>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { VNode } from 'vue';
2+
3+
export interface MySlots {
4+
/**
5+
* Default slot
6+
*/
7+
default: (props: { num: number }) => VNode[];
8+
'named-slot': (props: { str: string }) => VNode[];
9+
/**
10+
* Slot with tags
11+
* @deprecated do not use
12+
*/
13+
vbind: (props: { num: number; str: string }) => VNode[];
14+
'no-bind': () => VNode[];
15+
}

0 commit comments

Comments
 (0)