From 440d6fc1be4282bc18ff276fe3dbc47b4e8b983a Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Sun, 23 Oct 2022 16:07:25 +0800 Subject: [PATCH] fix: avoid declaring component as variable close #2030 --- .../src/generators/template.ts | 95 +++++++++++++------ .../vue-language-core/src/utils/localTypes.ts | 2 +- .../src/languageService.ts | 30 ++++-- 3 files changed, 85 insertions(+), 42 deletions(-) diff --git a/vue-language-tools/vue-language-core/src/generators/template.ts b/vue-language-tools/vue-language-core/src/generators/template.ts index 34b33cdc0..2bffa33c5 100644 --- a/vue-language-tools/vue-language-core/src/generators/template.ts +++ b/vue-language-tools/vue-language-core/src/generators/template.ts @@ -153,6 +153,8 @@ export function generate( const data: Record = {}; + codeGen.push(`let __VLS_templateComponents!: {\n`); + for (const tagName in tagNames) { if (isIntrinsicElement(vueCompilerOptions.experimentalRuntimeMode, tagName)) @@ -162,10 +164,29 @@ export function generate( if (isNamespacedTag) continue; + const names = new Set([ + // order is important: https://github.com/johnsoncodehk/volar/issues/2010 + capitalize(camelize(tagName)), + camelize(tagName), + tagName, + ]); + const varName = capitalize(camelize(tagName.replace(/:/g, '-'))); + + codeGen.push(`${varName}: import('./__VLS_types.js').GetComponents `'${name}'`).join(', ')}>;\n`); + + data[tagName] = varName; + } + + codeGen.push(`};\n`); + + for (const tagName in tagNames) { + + const varName = data[tagName]; + if (!varName) + continue; + const tagOffsets = tagNames[tagName]; const tagRanges: [number, number][] = tagOffsets.map(offset => [offset, offset + tagName.length]); - const var_componentVar = capitalize(camelize(tagName.replace(/:/g, '-'))); - const names = new Set([ // order is important: https://github.com/johnsoncodehk/volar/issues/2010 capitalize(camelize(tagName)), @@ -173,8 +194,6 @@ export function generate( tagName, ]); - codeGen.push(`let ${var_componentVar}!: import('./__VLS_types.js').GetComponents `'${name}'`).join(', ')}>;\n`); - for (const name of names) { for (const tagRange of tagRanges) { codeGen.push('__VLS_components'); @@ -194,7 +213,22 @@ export function generate( } codeGen.push('\n'); - data[tagName] = var_componentVar; + codeGen.push(`[`); + for (const tagRange of tagRanges) { + codeGen.push([ + varName, + 'template', + tagRange, + { + completion: { + additional: true, + autoImportOnly: true, + }, + }, + ]); + codeGen.push(','); + } + codeGen.push(`];\n`); } return data; @@ -422,7 +456,6 @@ export function generate( const _isIntrinsicElement = isIntrinsicElement(vueCompilerOptions.experimentalRuntimeMode, node.tag); const _isNamespacedTag = node.tag.indexOf('.') >= 0; - const tagText = componentVars[node.tag] ?? node.tag; if (vueCompilerOptions.jsxTemplates) { @@ -438,8 +471,11 @@ export function generate( }; codeGen.push(`<`); + if (componentVars[node.tag]) { + codeGen.push(`__VLS_templateComponents.`); + } codeGen.push([ - tagText, + componentVars[node.tag] ?? node.tag, 'template', [startTagOffset, startTagOffset + node.tag.length], tagCapabilities, @@ -453,8 +489,11 @@ export function generate( } else { codeGen.push(`>;\n`); + codeGen.push(`let ${var_props}!: import('./__VLS_types.js').ComponentProps;\n`); codeGen.push([ - tagText, + node.tag, 'template', [startTagOffset, startTagOffset + node.tag.length], capabilitiesSet.all, @@ -524,7 +563,7 @@ export function generate( if (endTagOffset !== undefined) { codeGen.push([ - tagText, + node.tag, 'template', [endTagOffset, endTagOffset + node.tag.length], capabilitiesSet.all, @@ -535,32 +574,26 @@ export function generate( else { codeGen.push(`let ${var_props}!: import('./__VLS_types.js').ComponentProps;\n`); if (endTagOffset !== undefined) { + if (componentVars[node.tag]) { + codeGen.push(`__VLS_templateComponents.`); + } codeGen.push([ - tagText, + componentVars[node.tag] ?? node.tag, 'template', [endTagOffset, endTagOffset + node.tag.length], - { - ...capabilitiesSet.tagHover, - completion: { - additional: true, - autoImportOnly: true, - }, - }, + capabilitiesSet.tagHover, ]); codeGen.push(`;\n`); } @@ -675,9 +708,9 @@ export function generate( codeGen.push(`JSX.IntrinsicElements['${node.tag}'];\n`); } else { - codeGen.push(`import('./__VLS_types.js').InstanceProps;\n`);; + codeGen.push(`import('./__VLS_types.js').InstanceProps;\n`);; } - codeGen.push(`const __VLS_${elementIndex++}: import('./__VLS_types.js').EventObject = ( T extends (...args: any) => any ? (T extends (...args: any) => { props: infer Props } ? Props : {}) : T extends new (...args: any) => any ? (T extends new (...args: any) => { $props: infer Props } ? Props : {}) - : T; // IntrinsicElement + : T // IntrinsicElement ); export type InstanceProps = I extends { $props: infer Props } ? Props & Record : C & Record; export type EventObject = { diff --git a/vue-language-tools/vue-language-service/src/languageService.ts b/vue-language-tools/vue-language-service/src/languageService.ts index a51be3744..f2abec08d 100644 --- a/vue-language-tools/vue-language-service/src/languageService.ts +++ b/vue-language-tools/vue-language-service/src/languageService.ts @@ -58,7 +58,25 @@ export function getLanguageServicePlugins( }, complete: { ..._tsPlugin.complete, + async on(document, position, context) { + const result = await _tsPlugin.complete!.on!(document, position, context); + if (result) { + const map = apis.context.documents.sourceMapFromEmbeddedDocumentUri(document.uri); + const doc = map ? apis.context.documents.get(map.sourceDocument.uri) : undefined; + if (map && doc?.file instanceof vue.VueSourceFile) { + if (map.toSourcePosition(position, data => typeof data.completion === 'object' && !!data.completion.autoImportOnly)) { + result.items.forEach(item => { + item.data.__isComponentAutoImport = true; + }); + } + } + } + return result; + }, async resolve(item) { + if (item.textEdit?.newText === 'IconCone') { + console.log(item.textEdit); + } item = await _tsPlugin.complete!.resolve!(item); if ( @@ -76,22 +94,14 @@ export function getLanguageServicePlugins( } const data: Data = item.data; - if (data && item.additionalTextEdits?.length && item.textEdit) { + if (item.data?.__isComponentAutoImport && data && item.additionalTextEdits?.length && item.textEdit) { const map = apis.context.documents.sourceMapFromEmbeddedDocumentUri(data.uri); const doc = map ? apis.context.documents.get(map.sourceDocument.uri) : undefined; if (map && doc?.file instanceof vue.VueSourceFile) { - let isComponentAutoImport = false; - for (const [_, mapping] of map.toSourceOffsets(data.offset)) { - if (typeof mapping.data.completion === 'object' && mapping.data.completion.autoImportOnly) { - isComponentAutoImport = true; - break; - } - } - const sfc = doc.file.sfc; const componentName = item.textEdit.newText; const textDoc = doc.getDocument(); - if (isComponentAutoImport && sfc.scriptAst && sfc.script) { + if (sfc.scriptAst && sfc.script) { const ts = context.typescript.module; const _scriptRanges = vue.scriptRanges.parseScriptRanges(ts, sfc.scriptAst, !!sfc.scriptSetup, true); const exportDefault = _scriptRanges.exportDefault;