diff --git a/packages/language-server/node.ts b/packages/language-server/node.ts index c167ca80f8..ef95fa749b 100644 --- a/packages/language-server/node.ts +++ b/packages/language-server/node.ts @@ -62,6 +62,9 @@ connection.onInitialize(params => { getElementAttrs(...args) { return connection.sendRequest(options.typescript.requestForwardingCommand!, ['vue:getElementAttrs', args]); }, + getElementNames(...args) { + return connection.sendRequest(options.typescript.requestForwardingCommand!, ['vue:getElementNames', args]); + }, getImportPathForFile(...args) { return connection.sendRequest(options.typescript.requestForwardingCommand!, ['vue:getImportPathForFile', args]); }, diff --git a/packages/language-service/index.ts b/packages/language-service/index.ts index 69ee339662..fa33001292 100644 --- a/packages/language-service/index.ts +++ b/packages/language-service/index.ts @@ -38,6 +38,7 @@ import { getComponentEvents } from '@vue/typescript-plugin/lib/requests/getCompo import { getComponentNames } from '@vue/typescript-plugin/lib/requests/getComponentNames'; import { getComponentProps } from '@vue/typescript-plugin/lib/requests/getComponentProps'; import { getElementAttrs } from '@vue/typescript-plugin/lib/requests/getElementAttrs'; +import { getElementNames } from '@vue/typescript-plugin/lib/requests/getElementNames'; import { getImportPathForFile } from '@vue/typescript-plugin/lib/requests/getImportPathForFile'; import { getPropertiesAtLocation } from '@vue/typescript-plugin/lib/requests/getPropertiesAtLocation'; import type { RequestContext } from '@vue/typescript-plugin/lib/requests/types'; @@ -131,6 +132,9 @@ export function getFullLanguageServicePlugins(ts: typeof import('typescript')) { async getElementAttrs(...args) { return await getElementAttrs.apply(requestContext, args); }, + async getElementNames(...args) { + return await getElementNames.apply(requestContext, args); + }, async getQuickInfoAtPosition(fileName, position) { const languageService = context.getLanguageService(); const uri = context.project.typescript!.uriConverter.asUri(fileName); diff --git a/packages/language-service/lib/plugins/vue-missing-props-hints.ts b/packages/language-service/lib/plugins/vue-missing-props-hints.ts index 9d75668e56..d8b6d6ca17 100644 --- a/packages/language-service/lib/plugins/vue-missing-props-hints.ts +++ b/packages/language-service/lib/plugins/vue-missing-props-hints.ts @@ -17,6 +17,7 @@ export function create( }, create(context) { const tsPluginClient = getTsPluginClient?.(context); + let intrinsicElementNames: Set; return { @@ -59,6 +60,10 @@ export function create( const components = await tsPluginClient?.getComponentNames(root.fileName) ?? []; const componentProps: Record = {}; + intrinsicElementNames ??= new Set( + await tsPluginClient?.getElementNames(root.fileName) ?? [] + ); + let token: html.TokenType; let current: { unburnedRequiredProps: string[]; @@ -69,6 +74,10 @@ export function create( while ((token = scanner.scan()) !== html.TokenType.EOS) { if (token === html.TokenType.StartTag) { const tagName = scanner.getTokenText(); + if (intrinsicElementNames.has(tagName)) { + continue; + } + const checkTag = tagName.includes('.') ? tagName : components.find(component => component === tagName || hyphenateTag(component) === tagName); diff --git a/packages/typescript-plugin/index.ts b/packages/typescript-plugin/index.ts index 8994a3856f..3de52a7b59 100644 --- a/packages/typescript-plugin/index.ts +++ b/packages/typescript-plugin/index.ts @@ -8,6 +8,7 @@ import { getComponentEvents } from './lib/requests/getComponentEvents'; import { getComponentNames } from './lib/requests/getComponentNames'; import { getComponentProps } from './lib/requests/getComponentProps'; import { getElementAttrs } from './lib/requests/getElementAttrs'; +import { getElementNames } from './lib/requests/getElementNames'; import { getImportPathForFile } from './lib/requests/getImportPathForFile'; import { getPropertiesAtLocation } from './lib/requests/getPropertiesAtLocation'; import { getQuickInfoAtPosition } from './lib/requests/getQuickInfoAtPosition'; @@ -120,6 +121,11 @@ const plugin = createLanguageServicePlugin( response: getElementAttrs.apply(getRequestContext(args[0]), args), }; }); + session.addProtocolHandler('vue:getElementNames', ({ arguments: args }) => { + return { + response: getElementNames.apply(getRequestContext(args[0]), args), + }; + }); projectService.logger.info('Vue specific commands are successfully added.'); } diff --git a/packages/typescript-plugin/lib/common.ts b/packages/typescript-plugin/lib/common.ts index bdd382d7cf..865c9557a9 100644 --- a/packages/typescript-plugin/lib/common.ts +++ b/packages/typescript-plugin/lib/common.ts @@ -1,7 +1,8 @@ import { forEachElementNode, hyphenateTag, Language, VueCompilerOptions, VueVirtualCode } from '@vue/language-core'; import { capitalize } from '@vue/shared'; import type * as ts from 'typescript'; -import { _getComponentNames, _getElementNames } from './requests/getComponentNames'; +import { _getComponentNames } from './requests/getComponentNames'; +import { _getElementNames } from './requests/getElementNames'; import type { RequestContext } from './requests/types'; const windowsPathReg = /\\/g; diff --git a/packages/typescript-plugin/lib/requests/getComponentNames.ts b/packages/typescript-plugin/lib/requests/getComponentNames.ts index 39f2951193..8cc1040c17 100644 --- a/packages/typescript-plugin/lib/requests/getComponentNames.ts +++ b/packages/typescript-plugin/lib/requests/getComponentNames.ts @@ -31,15 +31,3 @@ export function _getComponentNames( names.push(getSelfComponentName(vueCode.fileName)); return names; } - -export function _getElementNames( - ts: typeof import('typescript'), - tsLs: ts.LanguageService, - vueCode: VueVirtualCode -) { - return getVariableType(ts, tsLs, vueCode, '__VLS_elements') - ?.type - ?.getProperties() - .map(c => c.name) - ?? []; -} diff --git a/packages/typescript-plugin/lib/requests/getElementNames.ts b/packages/typescript-plugin/lib/requests/getElementNames.ts new file mode 100644 index 0000000000..06062ef688 --- /dev/null +++ b/packages/typescript-plugin/lib/requests/getElementNames.ts @@ -0,0 +1,29 @@ +import { VueVirtualCode } from '@vue/language-core'; +import type * as ts from 'typescript'; +import type { RequestContext } from './types'; +import { getVariableType } from './utils'; + +export function getElementNames( + this: RequestContext, + fileName: string +) { + const { typescript: ts, language, languageService, getFileId } = this; + const volarFile = language.scripts.get(getFileId(fileName)); + if (!(volarFile?.generated?.root instanceof VueVirtualCode)) { + return; + } + const vueCode = volarFile.generated.root; + return _getElementNames(ts, languageService, vueCode); +} + +export function _getElementNames( + ts: typeof import('typescript'), + tsLs: ts.LanguageService, + vueCode: VueVirtualCode +) { + return getVariableType(ts, tsLs, vueCode, '__VLS_elements') + ?.type + ?.getProperties() + .map(c => c.name) + ?? []; +} diff --git a/packages/typescript-plugin/lib/requests/index.ts b/packages/typescript-plugin/lib/requests/index.ts index 687c48ce0f..9b8fa5bd8e 100644 --- a/packages/typescript-plugin/lib/requests/index.ts +++ b/packages/typescript-plugin/lib/requests/index.ts @@ -10,4 +10,5 @@ export type Requests = { getComponentEvents: ToRequest; getComponentDirectives: ToRequest; getElementAttrs: ToRequest; + getElementNames: ToRequest; };