Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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

Expand Down
19 changes: 11 additions & 8 deletions packages/component-meta/lib/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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() {
Expand All @@ -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 ?? []);
},
Expand All @@ -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 ?? []);
},
Expand Down Expand Up @@ -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() {
Expand Down
8 changes: 5 additions & 3 deletions packages/component-meta/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
/**
Expand All @@ -72,6 +73,7 @@ export interface ExposeMeta {
name: string;
description: string;
type: string;
tags: { name: string; text?: string }[];
declarations: Declaration[];
schema: PropertyMetaSchema;
/**
Expand Down
26 changes: 26 additions & 0 deletions packages/component-meta/tests/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand All @@ -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": [],
Expand All @@ -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', () => {
Expand Down
67 changes: 46 additions & 21 deletions packages/tsc/tests/__snapshots__/dts.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, string>;
};
"import type { MyExposed } from './my-exposed';
declare const __VLS_export: import("vue").DefineComponent2<{
setup(): MyExposed;
data(): {};
props: {};
computed: {};
Expand All @@ -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<string>;
/**
* an oldCounter string
* @deprecated use counter instead
*/
oldCounter: Ref<string>;
}
"
`;

exports[`Input: reference-type-model/component.vue, Output: reference-type-model/component.vue.d.ts 1`] = `
"type __VLS_ModelProps = {
/**
Expand Down Expand Up @@ -803,20 +815,8 @@ type __VLS_WithSlots<T, S> = 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(): {};
Expand Down Expand Up @@ -899,6 +899,31 @@ type __VLS_WithSlots<T, S> = 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 {
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<script setup lang="ts">
import { ref } from 'vue';
import type { MyExposed } from './my-exposed';

const counter = ref('foo')
const oldCounter = ref('bar')

defineExpose({
/**
* a counter string
*/
counter
defineExpose<MyExposed>({
counter,
oldCounter,
});
</script>
13 changes: 13 additions & 0 deletions test-workspace/component-meta/reference-type-exposed/my-exposed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { Ref } from 'vue';

export interface MyExposed {
/**
* a counter string
*/
counter: Ref<string>;
/**
* an oldCounter string
* @deprecated use counter instead
*/
oldCounter: Ref<string>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@
</template>

<script setup lang="ts">
import type { VNode } from 'vue'
import type { MySlots } from './my-slots';

defineSlots<{
default: (props: { num: number }) => VNode[],
'named-slot': (props: { str: string }) => VNode[],
vbind: (props: { num: number, str: string }) => VNode[],
'no-bind': () => VNode[],
}>()
defineSlots<MySlots>()
</script>
15 changes: 15 additions & 0 deletions test-workspace/component-meta/reference-type-slots/my-slots.ts
Original file line number Diff line number Diff line change
@@ -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[];
}