From cc71098edf3078912dc7cf16faebcb10456addba Mon Sep 17 00:00:00 2001 From: joy-yu <775154773@qq.com> Date: Tue, 3 Sep 2024 17:30:06 +0800 Subject: [PATCH 1/8] feat(language-service): JSDoc display support when typing props on component template --- .../lib/ideFeatures/nameCasing.ts | 2 +- .../lib/plugins/vue-template.ts | 22 ++++--- .../lib/requests/componentInfos.ts | 58 +++++++++++++++++-- .../component-meta/generic/component.vue | 10 +++- 4 files changed, 78 insertions(+), 14 deletions(-) diff --git a/packages/language-service/lib/ideFeatures/nameCasing.ts b/packages/language-service/lib/ideFeatures/nameCasing.ts index 4201d27b54..a80eb8526f 100644 --- a/packages/language-service/lib/ideFeatures/nameCasing.ts +++ b/packages/language-service/lib/ideFeatures/nameCasing.ts @@ -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) { diff --git a/packages/language-service/lib/plugins/vue-template.ts b/packages/language-service/lib/plugins/vue-template.ts index 1b267dcc0d..968eb8fafc 100644 --- a/packages/language-service/lib/plugins/vue-template.ts +++ b/packages/language-service/lib/plugins/vue-template.ts @@ -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(), @@ -453,7 +453,7 @@ export function create( const promises: Promise[] = []; const tagInfos = new Map(); @@ -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, }); @@ -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); @@ -594,7 +595,12 @@ export function create( else { const propName = name; - const propKey = createInternalItemId('componentProp', [isGlobal ? '*' : tag, propName]); + const propDescription = propsInfo.find(prop => { + const name = casing.attr === AttrNameCasing.Camel ? prop.name : hyphenateAttr(prop.name); + return name === propName; + })?.commentMarkdown; + + const propKey = propDescription || createInternalItemId('componentProp', [isGlobal ? '*' : tag, propName]); attributes.push( { @@ -984,4 +990,4 @@ function tryGetEventName( return [true, name]; } return [false, name]; -} \ No newline at end of file +} diff --git a/packages/typescript-plugin/lib/requests/componentInfos.ts b/packages/typescript-plugin/lib/requests/componentInfos.ts index cb069cb09e..e1807813ea 100644 --- a/packages/typescript-plugin/lib/requests/componentInfos.ts +++ b/packages/typescript-plugin/lib/requests/componentInfos.ts @@ -47,7 +47,7 @@ export function getComponentProps( } } - const result = new Set(); + const result = new Map(); for (const sig of componentType.getCallSignatures()) { const propParam = sig.parameters[0]; @@ -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 }); } } } @@ -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( @@ -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'); +} diff --git a/test-workspace/component-meta/generic/component.vue b/test-workspace/component-meta/generic/component.vue index d5b2eebe11..b62b0ab3db 100644 --- a/test-workspace/component-meta/generic/component.vue +++ b/test-workspace/component-meta/generic/component.vue @@ -1,5 +1,13 @@ + `, ':msg')) + ).toMatchInlineSnapshot(` + { + "documentation": { + "kind": "plaintext", + "value": "The message to display + + ", + }, + "insertTextFormat": 2, + "kind": 5, + "label": ":msg", + "sortText": ":msg", + "textEdit": { + "newText": ":msg="$1"", + "range": { + "end": { + "character": 21, + "line": 2, + }, + "start": { + "character": 17, + "line": 2, + }, + }, + }, + } + `); + }); + const openedDocuments: TextDocument[] = []; afterEach(async () => { From 54038512469bf597275650a6698f9e1d0028c269 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Wed, 4 Sep 2024 22:40:25 +0800 Subject: [PATCH 5/8] Update vue-template.ts --- .../lib/plugins/vue-template.ts | 64 ++++++++++--------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/packages/language-service/lib/plugins/vue-template.ts b/packages/language-service/lib/plugins/vue-template.ts index 968eb8fafc..ad7f6d5bb9 100644 --- a/packages/language-service/lib/plugins/vue-template.ts +++ b/packages/language-service/lib/plugins/vue-template.ts @@ -434,12 +434,12 @@ export function create( if (builtInData.tags) { for (const tag of builtInData.tags) { - if (isInternalItemId(tag.name)) { + if (isItemKey(tag.name)) { continue; } if (specialTags.has(tag.name)) { - tag.name = createInternalItemId('specialTag', [tag.name]); + tag.name = parseItemKey('specialTag', tag.name, ''); } else if (casing.tag === TagNameCasing.Kebab) { tag.name = hyphenateTag(tag.name); @@ -579,7 +579,7 @@ export function create( const propNameBase = name.startsWith('on-') ? name.slice('on-'.length) : (name['on'.length].toLowerCase() + name.slice('onX'.length)); - const propKey = createInternalItemId('componentEvent', [isGlobal ? '*' : tag, propNameBase]); + const propKey = parseItemKey('componentEvent', isGlobal ? '*' : tag, propNameBase); attributes.push( { @@ -600,7 +600,7 @@ export function create( return name === propName; })?.commentMarkdown; - const propKey = propDescription || createInternalItemId('componentProp', [isGlobal ? '*' : tag, propName]); + const propKey = propDescription || parseItemKey('componentProp', isGlobal ? '*' : tag, propName); attributes.push( { @@ -622,7 +622,7 @@ export function create( for (const event of events) { const name = casing.attr === AttrNameCasing.Camel ? event : hyphenateAttr(event); - const propKey = createInternalItemId('componentEvent', [tag, name]); + const propKey = parseItemKey('componentEvent', tag, name); attributes.push( { @@ -653,7 +653,7 @@ export function create( for (const [isGlobal, model] of models) { const name = casing.attr === AttrNameCasing.Camel ? model : hyphenateAttr(model); - const propKey = createInternalItemId('componentProp', [isGlobal ? '*' : tag, name]); + const propKey = parseItemKey('componentProp', isGlobal ? '*' : tag, name); attributes.push({ name: 'v-model:' + name, @@ -763,10 +763,10 @@ export function create( completionList.items = completionList.items.filter(i => i !== item); } - const nameId = readInternalItemId(item.label); + const resolvedLabel = resolveItemKey(item.label); - if (nameId) { - const name = nameId.args[0]; + if (resolvedLabel) { + const name = resolvedLabel.tag; item.label = name; if (item.textEdit) { item.textEdit.newText = name; @@ -779,11 +779,11 @@ export function create( } } - const itemIdKey = typeof item.documentation === 'string' ? item.documentation : item.documentation?.value; - let itemId = itemIdKey ? readInternalItemId(itemIdKey) : undefined; + const itemKeyStr = typeof item.documentation === 'string' ? item.documentation : item.documentation?.value; + let resolvedDocumentation = itemKeyStr ? resolveItemKey(itemKeyStr) : undefined; - if (itemId) { - let [isEvent, name] = tryGetEventName(itemId); + if (resolvedDocumentation) { + let [isEvent, name] = tryGetEventName(resolvedDocumentation); if (isEvent) { name = 'on' + name; } @@ -804,9 +804,10 @@ export function create( * that without `internalItemId`. */ if (isVBind || isVBindAbbr) { - itemId = { + resolvedDocumentation = { type: 'componentProp', - args: ['^', name] + tag: '^', + prop: name, }; } else if (!originals.has(item.label)) { @@ -820,12 +821,12 @@ export function create( item.kind = 6 satisfies typeof vscode.CompletionItemKind.Variable; tokens.push('\u0000'); } - else if (itemId) { + else if (resolvedDocumentation) { - const isComponent = itemId.args[0] !== '*'; - const [isEvent, name] = tryGetEventName(itemId); + const isComponent = resolvedDocumentation.tag !== '*'; + const [isEvent, name] = tryGetEventName(resolvedDocumentation); - if (itemId.type === 'componentProp') { + if (resolvedDocumentation.type === 'componentProp') { if (isComponent || specialProps.has(name)) { item.kind = 5 satisfies typeof vscode.CompletionItemKind.Field; } @@ -949,20 +950,21 @@ export function create( } }; -function createInternalItemId(type: InternalItemId, args: string[]) { - return '__VLS_::' + type + '::' + args.join(','); +function parseItemKey(type: InternalItemId, tag: string, prop: string) { + return '__VLS_data=' + type + ',' + tag + ',' + prop; } -function isInternalItemId(key: string) { - return key.startsWith('__VLS_::'); +function isItemKey(key: string) { + return key.startsWith('__VLS_data='); } -function readInternalItemId(key: string) { - if (isInternalItemId(key)) { - const strs = key.split('::'); +function resolveItemKey(key: string) { + if (isItemKey(key)) { + const strs = key.slice('__VLS_data='.length).split(','); return { - type: strs[1] as InternalItemId, - args: strs[2].split(','), + type: strs[0] as InternalItemId, + tag: strs[1], + prop: strs[2], }; } } @@ -980,13 +982,13 @@ function getReplacement(list: html.CompletionList, doc: TextDocument) { } function tryGetEventName( - itemId: ReturnType & {} + itemKey: ReturnType & {} ): [isEvent: boolean, name: string] { - const name = hyphenateAttr(itemId.args[1]); + const name = hyphenateAttr(itemKey.prop); if (name.startsWith('on-')) { return [true, name.slice('on-'.length)]; } - else if (itemId.type === 'componentEvent') { + else if (itemKey.type === 'componentEvent') { return [true, name]; } return [false, name]; From 6a1b3b74b24ecb0eee3985996c0b2081de5fd108 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 5 Sep 2024 00:00:53 +0800 Subject: [PATCH 6/8] Combine HTML & TS docs --- extensions/vscode/src/common.ts | 2 +- .../lib/codegen/template/elementProps.ts | 5 +- .../lib/plugins/vue-template.ts | 107 ++++++++++++------ .../lib/requests/componentInfos.ts | 2 +- tsconfig.base.json | 5 +- 5 files changed, 77 insertions(+), 44 deletions(-) diff --git a/extensions/vscode/src/common.ts b/extensions/vscode/src/common.ts index f9e4b7662d..d45926e992 100644 --- a/extensions/vscode/src/common.ts +++ b/extensions/vscode/src/common.ts @@ -264,7 +264,7 @@ async function doActivate(context: vscode.ExtensionContext, createLc: CreateLang ]) { try { const res = await fetch(url); - onJson(await res.json()); + onJson(await res.json() as any); succeed = true; break; } catch { } diff --git a/packages/language-core/lib/codegen/template/elementProps.ts b/packages/language-core/lib/codegen/template/elementProps.ts index 39ceaf3230..ed6ff05454 100644 --- a/packages/language-core/lib/codegen/template/elementProps.ts +++ b/packages/language-core/lib/codegen/template/elementProps.ts @@ -210,13 +210,14 @@ export function* generateElementProps( ...ctx.codeFeatures.withoutHighlightAndCompletion, }; if (!options.vueCompilerOptions.strictTemplates) { + const verification = codeInfo.verification; codeInfo.verification = { shouldReport(_source, code) { if (String(code) === '2353' || String(code) === '2561') { return false; } - return typeof codeInfo.verification === 'object' - ? codeInfo.verification.shouldReport?.(_source, code) ?? true + return typeof verification === 'object' + ? verification.shouldReport?.(_source, code) ?? true : true; }, }; diff --git a/packages/language-service/lib/plugins/vue-template.ts b/packages/language-service/lib/plugins/vue-template.ts index ad7f6d5bb9..217ffd9a64 100644 --- a/packages/language-service/lib/plugins/vue-template.ts +++ b/packages/language-service/lib/plugins/vue-template.ts @@ -32,6 +32,7 @@ export function create( let extraCustomData: html.IHTMLDataProvider[] = []; let lastCompletionComponentNames = new Set(); + const tsDocumentations = new Map(); const onDidChangeCustomDataListeners = new Set<() => void>(); const onDidChangeCustomData = (listener: () => void): Disposable => { onDidChangeCustomDataListeners.add(listener); @@ -461,6 +462,8 @@ export function create( let components: string[] | undefined; let templateContextProps: string[] | undefined; + tsDocumentations.clear(); + updateExtraCustomData([ html.newHTMLDataProvider('vue-template-built-in', builtInData), { @@ -595,12 +598,15 @@ export function create( else { const propName = name; + const propKey = parseItemKey('componentProp', isGlobal ? '*' : tag, propName); const propDescription = propsInfo.find(prop => { const name = casing.attr === AttrNameCasing.Camel ? prop.name : hyphenateAttr(prop.name); return name === propName; })?.commentMarkdown; - const propKey = propDescription || parseItemKey('componentProp', isGlobal ? '*' : tag, propName); + if (propDescription) { + tsDocumentations.set(propName, propDescription); + } attributes.push( { @@ -755,18 +761,23 @@ export function create( } } - const originals = new Map(); + completionList.items = completionList.items.filter(item => !specialTags.has(item.label)); - for (const item of completionList.items) { + const htmlDocumentations = new Map(); - if (specialTags.has(item.label)) { - completionList.items = completionList.items.filter(i => i !== item); + for (const item of completionList.items) { + const documentation = typeof item.documentation === 'string' ? item.documentation : item.documentation?.value; + if (documentation && !isItemKey(documentation) && item.documentation) { + htmlDocumentations.set(item.label, documentation); } + } - const resolvedLabel = resolveItemKey(item.label); + for (const item of completionList.items) { + + const resolvedLabelKey = resolveItemKey(item.label); - if (resolvedLabel) { - const name = resolvedLabel.tag; + if (resolvedLabelKey) { + const name = resolvedLabelKey.tag; item.label = name; if (item.textEdit) { item.textEdit.newText = name; @@ -780,23 +791,39 @@ export function create( } const itemKeyStr = typeof item.documentation === 'string' ? item.documentation : item.documentation?.value; - let resolvedDocumentation = itemKeyStr ? resolveItemKey(itemKeyStr) : undefined; - if (resolvedDocumentation) { - let [isEvent, name] = tryGetEventName(resolvedDocumentation); + let resolvedKey = itemKeyStr ? resolveItemKey(itemKeyStr) : undefined; + if (resolvedKey) { + const documentations: string[] = []; + + if (tsDocumentations.has(resolvedKey.prop)) { + documentations.push(tsDocumentations.get(resolvedKey.prop)!); + } + + let { isEvent, propName } = getPropName(resolvedKey); if (isEvent) { - name = 'on' + name; + // click -> onclick + propName = 'on' + propName; + } + if (htmlDocumentations.has(propName)) { + documentations.push(htmlDocumentations.get(propName)!); + } + + if (documentations.length) { + item.documentation = { + kind: 'markdown', + value: documentations.join('\n\n'), + }; } - const original = originals.get(name); - item.documentation = original?.documentation; } else { - let name = item.label; - const isVBind = name.startsWith('v-bind:') ? ( - name = name.slice('v-bind:'.length), true + let propName = item.label; + + const isVBind = propName.startsWith('v-bind:') ? ( + propName = propName.slice('v-bind:'.length), true ) : false; - const isVBindAbbr = name.startsWith(':') && name !== ':' ? ( - name = name.slice(':'.length), true + const isVBindAbbr = propName.startsWith(':') && propName !== ':' ? ( + propName = propName.slice(':'.length), true ) : false; /** @@ -804,14 +831,22 @@ export function create( * that without `internalItemId`. */ if (isVBind || isVBindAbbr) { - resolvedDocumentation = { + resolvedKey = { type: 'componentProp', tag: '^', - prop: name, + prop: propName, }; } - else if (!originals.has(item.label)) { - originals.set(item.label, item); + + if (tsDocumentations.has(propName)) { + const originalDocumentation = typeof item.documentation === 'string' ? item.documentation : item.documentation?.value; + item.documentation = { + kind: 'markdown', + value: [ + tsDocumentations.get(propName)!, + originalDocumentation, + ].filter(str => !!str).join('\n\n'), + }; } } @@ -821,19 +856,19 @@ export function create( item.kind = 6 satisfies typeof vscode.CompletionItemKind.Variable; tokens.push('\u0000'); } - else if (resolvedDocumentation) { + else if (resolvedKey) { - const isComponent = resolvedDocumentation.tag !== '*'; - const [isEvent, name] = tryGetEventName(resolvedDocumentation); + const isComponent = resolvedKey.tag !== '*'; + const { isEvent, propName } = getPropName(resolvedKey); - if (resolvedDocumentation.type === 'componentProp') { - if (isComponent || specialProps.has(name)) { + if (resolvedKey.type === 'componentProp') { + if (isComponent || specialProps.has(propName)) { item.kind = 5 satisfies typeof vscode.CompletionItemKind.Field; } } else if (isEvent) { item.kind = 23 satisfies typeof vscode.CompletionItemKind.Event; - if (name.startsWith('vnode-')) { + if (propName.startsWith('vnode-')) { tokens.push('\u0004'); } } @@ -841,7 +876,7 @@ export function create( if ( isComponent || (isComponent && isEvent) - || specialProps.has(name) + || specialProps.has(propName) ) { tokens.push('\u0000'); @@ -861,7 +896,7 @@ export function create( tokens.push('\u0000'); } - if (specialProps.has(name)) { + if (specialProps.has(propName)) { tokens.push('\u0001'); } else { @@ -981,15 +1016,15 @@ function getReplacement(list: html.CompletionList, doc: TextDocument) { } } -function tryGetEventName( +function getPropName( itemKey: ReturnType & {} -): [isEvent: boolean, name: string] { +): { isEvent: boolean, propName: string; } { const name = hyphenateAttr(itemKey.prop); if (name.startsWith('on-')) { - return [true, name.slice('on-'.length)]; + return { isEvent: true, propName: name.slice('on-'.length) }; } else if (itemKey.type === 'componentEvent') { - return [true, name]; + return { isEvent: true, propName: name }; } - return [false, name]; + return { isEvent: false, propName: name }; } diff --git a/packages/typescript-plugin/lib/requests/componentInfos.ts b/packages/typescript-plugin/lib/requests/componentInfos.ts index ca4799e11e..9436fd9255 100644 --- a/packages/typescript-plugin/lib/requests/componentInfos.ts +++ b/packages/typescript-plugin/lib/requests/componentInfos.ts @@ -296,7 +296,7 @@ function searchVariableDeclarationNode( function generateCommentMarkdown(parts: ts.SymbolDisplayPart[], jsDocTags: ts.JSDocTagInfo[]) { const parsedComment = _symbolDisplayPartsToMarkdown(parts); const parsedJsDoc = _jsDocTagInfoToMarkdown(jsDocTags); - let result = [parsedComment, parsedJsDoc].join('\n\n'); + let result = [parsedComment, parsedJsDoc].filter(str => !!str).join('\n\n'); return result; } diff --git a/tsconfig.base.json b/tsconfig.base.json index 4e4108accd..a4770d7cff 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1,10 +1,7 @@ { "compilerOptions": { "target": "ES2021", - "lib": [ - "WebWorker", - "ES2021", - ], + "lib": [ "ES2021" ], "module": "Node16", "sourceMap": true, "composite": true, From 5b493603dd1d61f235a0b17fd1116be28ea6287d Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 5 Sep 2024 00:02:35 +0800 Subject: [PATCH 7/8] Update completions.spec.ts --- packages/language-server/tests/completions.spec.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/language-server/tests/completions.spec.ts b/packages/language-server/tests/completions.spec.ts index 315c7f2dd8..c8fa995d49 100644 --- a/packages/language-server/tests/completions.spec.ts +++ b/packages/language-server/tests/completions.spec.ts @@ -410,10 +410,8 @@ describe('Completions', async () => { ).toMatchInlineSnapshot(` { "documentation": { - "kind": "plaintext", - "value": "The message to display - - ", + "kind": "markdown", + "value": "The message to display", }, "insertTextFormat": 2, "kind": 5, From aa603f63cf6237d4fa59dcf08b5f9f3ce7734f73 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 5 Sep 2024 00:07:21 +0800 Subject: [PATCH 8/8] Update vue-template.ts --- packages/language-service/lib/plugins/vue-template.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/language-service/lib/plugins/vue-template.ts b/packages/language-service/lib/plugins/vue-template.ts index 217ffd9a64..ec836205a4 100644 --- a/packages/language-service/lib/plugins/vue-template.ts +++ b/packages/language-service/lib/plugins/vue-template.ts @@ -815,6 +815,9 @@ export function create( value: documentations.join('\n\n'), }; } + else { + item.documentation = undefined; + } } else { let propName = item.label;