Skip to content

Commit

Permalink
solution of vuejs#4663
Browse files Browse the repository at this point in the history
  • Loading branch information
joy-yu committed Sep 3, 2024
1 parent bdf5d41 commit 27537dc
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 16 deletions.
2 changes: 1 addition & 1 deletion packages/language-service/lib/ideFeatures/nameCasing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export async function convertAttrName(
for (const [tagName, { attrs }] of tags) {
const componentName = components.find(component => component === tagName || hyphenateTag(component) === tagName);
if (componentName) {
const props = await tsPluginClient?.getComponentProps(rootCode.fileName, componentName) ?? [];
const props = (await tsPluginClient?.getComponentProps(rootCode.fileName, componentName) ?? []).map(prop => prop.name);
for (const [attrName, { offsets }] of attrs) {
const propName = props.find(prop => prop === attrName || hyphenateAttr(prop) === attrName);
if (propName) {
Expand Down
21 changes: 13 additions & 8 deletions packages/language-service/lib/plugins/vue-template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ export function create(
? tagName
: components.find(component => component === tagName || hyphenateTag(component) === tagName);
if (checkTag) {
componentProps[checkTag] ??= await tsPluginClient?.getComponentProps(code.fileName, checkTag, true) ?? [];
componentProps[checkTag] ??= (await tsPluginClient?.getComponentProps(code.fileName, checkTag, true) ?? []).map(prop => prop.name);
current = {
unburnedRequiredProps: [...componentProps[checkTag]],
labelOffset: scanner.getTokenOffset() + scanner.getTokenLength(),
Expand Down Expand Up @@ -453,7 +453,7 @@ export function create(
const promises: Promise<void>[] = [];
const tagInfos = new Map<string, {
attrs: string[];
props: string[];
propsInfo: { name: string, commentMarkdown: string; }[];
events: string[];
}>();

Expand Down Expand Up @@ -522,12 +522,12 @@ export function create(
if (!tagInfo) {
promises.push((async () => {
const attrs = await tsPluginClient?.getElementAttrs(vueCode.fileName, tag) ?? [];
const props = await tsPluginClient?.getComponentProps(vueCode.fileName, tag) ?? [];
const propsInfo = await tsPluginClient?.getComponentProps(vueCode.fileName, tag) ?? [];
const events = await tsPluginClient?.getComponentEvents(vueCode.fileName, tag) ?? [];
tagInfos.set(tag, {
attrs,
props: props.filter(prop =>
!prop.startsWith('ref_')
propsInfo: propsInfo.filter(prop =>
!prop.name.startsWith('ref_')
),
events,
});
Expand All @@ -536,7 +536,8 @@ export function create(
return [];
}

const { attrs, props, events } = tagInfo;
const { attrs, propsInfo, events } = tagInfo;
const props = propsInfo.map(prop => prop.name);
const attributes: html.IAttributeData[] = [];
const _tsCodegen = tsCodegen.get(vueCode.sfc);

Expand Down Expand Up @@ -594,7 +595,11 @@ export function create(
else {

const propName = name;
const propKey = createInternalItemId('componentProp', [isGlobal ? '*' : tag, propName]);
const propDesc = propsInfo.find(prop => {
const name = casing.attr === AttrNameCasing.Camel ? prop.name : hyphenateAttr(prop.name);
return name === propName;
})?.commentMarkdown;
const propKey = propDesc || createInternalItemId('componentProp', [isGlobal ? '*' : tag, propName]);

attributes.push(
{
Expand Down Expand Up @@ -984,4 +989,4 @@ function tryGetEventName(
return [true, name];
}
return [false, name];
}
}
58 changes: 54 additions & 4 deletions packages/typescript-plugin/lib/requests/componentInfos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function getComponentProps(
}
}

const result = new Set<string>();
let result = new Map<string, { name: string, commentMarkdown: string; }>();

for (const sig of componentType.getCallSignatures()) {
const propParam = sig.parameters[0];
Expand All @@ -56,7 +56,10 @@ export function getComponentProps(
const props = propsType.getProperties();
for (const prop of props) {
if (!requiredOnly || !(prop.flags & ts.SymbolFlags.Optional)) {
result.add(prop.name);
const name = prop.name;
const commentMarkdown = generateCommentMarkdown(prop.getDocumentationComment(checker), prop.getJsDocTags());

result.set(name, { name, commentMarkdown });
}
}
}
Expand All @@ -73,13 +76,16 @@ export function getComponentProps(
continue;
}
if (!requiredOnly || !(prop.flags & ts.SymbolFlags.Optional)) {
result.add(prop.name);
const name = prop.name;
const commentMarkdown = generateCommentMarkdown(prop.getDocumentationComment(checker), prop.getJsDocTags());

result.set(name, { name, commentMarkdown });
}
}
}
}

return [...result];
return [...result.values()];
}

export function getComponentEvents(
Expand Down Expand Up @@ -286,3 +292,47 @@ function searchVariableDeclarationNode(
}
}
}

function generateCommentMarkdown(parts: ts.SymbolDisplayPart[], jsDocTags: ts.JSDocTagInfo[]) {
const parsedComment = _symbolDisplayPartsToMarkdown(parts);
const parsedJsDoc = _jsDocTagInfoToMarkdown(jsDocTags);
let result = parsedComment;

if (parsedJsDoc) {
if (parsedComment) {
result += '\n\n';
}
result += parsedJsDoc;
}
return result;
}


function _symbolDisplayPartsToMarkdown(parts: ts.SymbolDisplayPart[]) {
return parts.map(part => {
switch (part.kind) {
case 'keyword':
return `\`${part.text}\``;
case 'functionName':
return `**${part.text}**`;
default:
return part.text;
}
}).join('');
}


function _jsDocTagInfoToMarkdown(jsDocTags: ts.JSDocTagInfo[]) {
return jsDocTags.map(tag => {
const tagName = `*@${tag.name}*`;
const tagText = tag.text?.map(t => {
if (t.kind === 'parameterName') {
return `\`${t.text}\``;
} else {
return t.text;
}
}).join('') || '';

return `${tagName} ${tagText}`;
}).join('\n\n');
}
10 changes: 9 additions & 1 deletion test-workspace/component-meta/generic/component.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
<script setup lang="ts" generic="T">
defineProps<{ foo: number }>();
defineProps<{
/** jsdoc typing test: foo */
foo: number;
/** jsdoc typing test: book
* @param {string} title - The title of the book.
* @param {string} author - The author of the book.
*/
book?: { title: string; author: string };
}>();
defineEmits<{ (e: 'bar', data: number): void }>();
defineExpose({ baz: {} as number });
defineSlots<{ default?(data: { foo: number }): any }>();
Expand Down
4 changes: 2 additions & 2 deletions test-workspace/component-meta/generic/main.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ const title = ref('');
</script>

<template>
<Comp :foo="1" v-model:title="title" />
</template>
<Comp :foo="1" v-model:title="title" />
</template>

0 comments on commit 27537dc

Please sign in to comment.