feat: re-impl react class name fix

This commit is contained in:
Jack Works
2020-05-06 22:52:06 +08:00
parent c8abf6fe67
commit 5853d2ab69
4 changed files with 17 additions and 10 deletions

View File

@@ -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, "\"")) {

View File

@@ -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<T>(name: string, candidates: T[], getName: (candidate: T) => string | undefined): T | undefined {
export function getSpellingSuggestion<T>(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) {

View File

@@ -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;

View File

@@ -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);