Skip to content

Commit d9366f1

Browse files
committed
fix(typescript-plugin): prevent highlighting native element tags with same name as components (#5253)
1 parent 2043e6a commit d9366f1

File tree

3 files changed

+38
-14
lines changed

3 files changed

+38
-14
lines changed

packages/typescript-plugin/lib/common.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { forEachElementNode, hyphenateTag, Language, VueCompilerOptions, VueVirt
22
import { capitalize } from '@vue/shared';
33
import type * as ts from 'typescript';
44
import { _getComponentNames } from './requests/getComponentNames';
5+
import { _getElementNames } from './requests/getElementAttrs';
56
import type { RequestContext } from './requests/types';
67

78
const windowsPathReg = /\\/g;
@@ -229,6 +230,7 @@ export function getComponentSpans(
229230
const { typescript: ts, languageService } = this;
230231
const result: ts.TextSpan[] = [];
231232
const validComponentNames = _getComponentNames(ts, languageService, vueCode);
233+
const elements = new Set(_getElementNames(ts, languageService, vueCode));
232234
const components = new Set([
233235
...validComponentNames,
234236
...validComponentNames.map(hyphenateTag),
@@ -238,7 +240,7 @@ export function getComponentSpans(
238240
if (node.loc.end.offset <= spanTemplateRange.start || node.loc.start.offset >= (spanTemplateRange.start + spanTemplateRange.length)) {
239241
continue;
240242
}
241-
if (components.has(node.tag)) {
243+
if (components.has(node.tag) && !elements.has(node.tag)) {
242244
let start = node.loc.start.offset;
243245
if (template.lang === 'html') {
244246
start += '<'.length;

packages/typescript-plugin/lib/requests/getElementAttrs.ts

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as vue from '@vue/language-core';
1+
import { VueVirtualCode } from '@vue/language-core';
22
import type * as ts from 'typescript';
33
import type { RequestContext } from './types';
44

@@ -9,19 +9,19 @@ export function getElementAttrs(
99
) {
1010
const { typescript: ts, language, languageService, getFileId } = this;
1111
const volarFile = language.scripts.get(getFileId(fileName));
12-
if (!(volarFile?.generated?.root instanceof vue.VueVirtualCode)) {
12+
if (!(volarFile?.generated?.root instanceof VueVirtualCode)) {
1313
return;
1414
}
1515
const program = languageService.getProgram()!;
1616

17-
let tsSourceFile: ts.SourceFile | undefined;
18-
if (tsSourceFile = program.getSourceFile(fileName)) {
17+
const tsSourceFile = program.getSourceFile(fileName);
18+
if (tsSourceFile) {
1919
const checker = program.getTypeChecker();
2020
const typeNode = tsSourceFile.statements
2121
.filter(ts.isTypeAliasDeclaration)
2222
.find(node => node.name.getText() === '__VLS_IntrinsicElementsCompletion');
2323

24-
if (checker && typeNode) {
24+
if (typeNode) {
2525
const type = checker.getTypeFromTypeNode(typeNode.type);
2626
const el = type.getProperty(tagName);
2727

@@ -33,3 +33,25 @@ export function getElementAttrs(
3333
}
3434
return [];
3535
}
36+
37+
export function _getElementNames(
38+
ts: typeof import('typescript'),
39+
tsLs: ts.LanguageService,
40+
vueCode: VueVirtualCode
41+
) {
42+
const program = tsLs.getProgram()!;
43+
44+
const tsSourceFile = program.getSourceFile(vueCode.fileName);
45+
if (tsSourceFile) {
46+
const checker = program.getTypeChecker();
47+
const typeNode = tsSourceFile.statements
48+
.filter(ts.isTypeAliasDeclaration)
49+
.find(node => node.name.getText() === '__VLS_IntrinsicElementsCompletion');
50+
51+
if (typeNode) {
52+
const type = checker.getTypeFromTypeNode(typeNode.type);
53+
return type.getProperties().map(c => c.name);
54+
}
55+
}
56+
return [];
57+
}

packages/typescript-plugin/lib/requests/utils.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,11 @@ export function getVariableType(
5252
) {
5353
const program = languageService.getProgram()!;
5454

55-
let tsSourceFile: ts.SourceFile | undefined;
56-
if (tsSourceFile = program.getSourceFile(vueCode.fileName)) {
57-
const node = searchVariableDeclarationNode(ts, tsSourceFile, name);
55+
const tsSourceFile = program.getSourceFile(vueCode.fileName)
56+
if (tsSourceFile) {
5857
const checker = program.getTypeChecker();
59-
if (checker && node) {
58+
const node = searchVariableDeclarationNode(ts, tsSourceFile, name);
59+
if (node) {
6060
return {
6161
node: node,
6262
type: checker.getTypeAtLocation(node),
@@ -70,16 +70,16 @@ function searchVariableDeclarationNode(
7070
sourceFile: ts.SourceFile,
7171
name: string
7272
) {
73-
let componentsNode: ts.Node | undefined;
73+
let result: ts.Node | undefined;
7474
walk(sourceFile);
75-
return componentsNode;
75+
return result;
7676

7777
function walk(node: ts.Node) {
78-
if (componentsNode) {
78+
if (result) {
7979
return;
8080
}
8181
else if (ts.isVariableDeclaration(node) && node.name.getText() === name) {
82-
componentsNode = node;
82+
result = node;
8383
}
8484
else {
8585
node.forEachChild(walk);

0 commit comments

Comments
 (0)