From 5853d2ab69b04501fb14e3d0f52d4fb4dcdbfa13 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Wed, 6 May 2020 22:52:06 +0800 Subject: [PATCH] feat: re-impl react class name fix --- src/compiler/checker.ts | 14 +++++++------- src/compiler/core.ts | 9 ++++++++- src/compiler/types.ts | 2 +- src/services/codefixes/fixSpelling.ts | 2 +- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1c859580e15..6a8a695e4ae 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16322,7 +16322,7 @@ namespace ts { errorNode = prop.valueDeclaration.name; } const propName = symbolToString(prop); - const suggestion = getSuggestionForNonexistentProperty(propName, errorTarget); + const suggestion = getSuggestionForNonexistentProperty(propName, errorTarget, true); if (suggestion) reportError(Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2, propName, typeToString(errorTarget), suggestion); else reportError(Diagnostics.Property_0_does_not_exist_on_type_1, propName, typeToString(errorTarget)); } @@ -24878,12 +24878,12 @@ namespace ts { return prop !== undefined && prop.valueDeclaration && hasSyntacticModifier(prop.valueDeclaration, ModifierFlags.Static); } - function getSuggestedSymbolForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): Symbol | undefined { - return getSpellingSuggestionForName(isString(name) ? name : idText(name), getPropertiesOfType(containingType), SymbolFlags.Value); + function getSuggestedSymbolForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type, isJSX = false): Symbol | undefined { + return getSpellingSuggestionForName(isString(name) ? name : idText(name), getPropertiesOfType(containingType), SymbolFlags.Value, isJSX); } - function getSuggestionForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): string | undefined { - const suggestion = getSuggestedSymbolForNonexistentProperty(name, containingType); + function getSuggestionForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type, isJSX = false): string | undefined { + const suggestion = getSuggestedSymbolForNonexistentProperty(name, containingType, isJSX); return suggestion && symbolName(suggestion); } @@ -24956,8 +24956,8 @@ namespace ts { * (0.4 allows 1 substitution/transposition for every 5 characters, * and 1 insertion/deletion at 3 characters) */ - function getSpellingSuggestionForName(name: string, symbols: Symbol[], meaning: SymbolFlags): Symbol | undefined { - return getSpellingSuggestion(name, symbols, getCandidateName); + function getSpellingSuggestionForName(name: string, symbols: Symbol[], meaning: SymbolFlags, isJSX = false): Symbol | undefined { + return getSpellingSuggestion(name, symbols, getCandidateName, isJSX); function getCandidateName(candidate: Symbol) { const candidateName = symbolName(candidate); if (startsWith(candidateName, "\"")) { diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 4be5998d6f3..d175a364955 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -1817,7 +1817,7 @@ namespace ts { * (0.4 allows 1 substitution/transposition for every 5 characters, * and 1 insertion/deletion at 3 characters) */ - export function getSpellingSuggestion(name: string, candidates: T[], getName: (candidate: T) => string | undefined): T | undefined { + export function getSpellingSuggestion(name: string, candidates: T[], getName: (candidate: T) => string | undefined, isJSX = false): T | undefined { const maximumLengthDifference = Math.min(2, Math.floor(name.length * 0.34)); let bestDistance = Math.floor(name.length * 0.4) + 1; // If the best result isn't better than this, don't bother. let bestCandidate: T | undefined; @@ -1825,6 +1825,13 @@ namespace ts { const nameLowerCase = name.toLowerCase(); for (const candidate of candidates) { const candidateName = getName(candidate); + if (isJSX) { + const htmlFor = name === "for" && candidateName === "htmlFor"; + const className = name === "class" && candidateName === "className"; + if (htmlFor || className) { + return candidate; + } + } if (candidateName !== undefined && Math.abs(candidateName.length - nameLowerCase.length) <= maximumLengthDifference) { const candidateNameLowerCase = candidateName.toLowerCase(); if (candidateNameLowerCase === nameLowerCase) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c9facd108a4..efcab0babed 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -4009,7 +4009,7 @@ namespace ts { */ /* @internal */ tryGetMemberInModuleExportsAndProperties(memberName: string, moduleSymbol: Symbol): Symbol | undefined; getApparentType(type: Type): Type; - /* @internal */ getSuggestedSymbolForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): Symbol | undefined; + /* @internal */ getSuggestedSymbolForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type, isJSX?: boolean): Symbol | undefined; /* @internal */ getSuggestionForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): string | undefined; /* @internal */ getSuggestedSymbolForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): Symbol | undefined; /* @internal */ getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined; diff --git a/src/services/codefixes/fixSpelling.ts b/src/services/codefixes/fixSpelling.ts index 98f42f2068a..70a89e2c272 100644 --- a/src/services/codefixes/fixSpelling.ts +++ b/src/services/codefixes/fixSpelling.ts @@ -56,7 +56,7 @@ namespace ts.codefix { Debug.assertNode(node, isIdentifier, "Expected an identifier for JSX attribute"); const tag = findAncestor(node, isJsxOpeningLikeElement)!; const props = checker.getContextualTypeForArgumentAtIndex(tag, 0); - suggestedSymbol = checker.getSuggestedSymbolForNonexistentProperty(node, props!); + suggestedSymbol = checker.getSuggestedSymbolForNonexistentProperty(node, props!, true); } else { const meaning = getMeaningFromLocation(node);