mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-17 01:49:57 -05:00
Merge pull request #37907 from Jack-Works/feat/class-to-classname
feat: add a codefix to fix class to className in react & add spelling suggest for JSX attributes
This commit is contained in:
@@ -606,6 +606,7 @@ namespace ts {
|
||||
getAllPossiblePropertiesOfTypes,
|
||||
getSuggestedSymbolForNonexistentProperty,
|
||||
getSuggestionForNonexistentProperty,
|
||||
getSuggestedSymbolForNonexistentJSXAttribute,
|
||||
getSuggestedSymbolForNonexistentSymbol: (location, name, meaning) => getSuggestedSymbolForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning),
|
||||
getSuggestionForNonexistentSymbol: (location, name, meaning) => getSuggestionForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning),
|
||||
getSuggestedSymbolForNonexistentModule,
|
||||
@@ -16313,18 +16314,25 @@ namespace ts {
|
||||
if (isJsxAttributes(errorNode) || isJsxOpeningLikeElement(errorNode) || isJsxOpeningLikeElement(errorNode.parent)) {
|
||||
// JsxAttributes has an object-literal flag and undergo same type-assignablity check as normal object-literal.
|
||||
// However, using an object-literal error message will be very confusing to the users so we give different a message.
|
||||
// TODO: Spelling suggestions for excess jsx attributes (needs new diagnostic messages)
|
||||
if (prop.valueDeclaration && isJsxAttribute(prop.valueDeclaration) && getSourceFileOfNode(errorNode) === getSourceFileOfNode(prop.valueDeclaration.name)) {
|
||||
// Note that extraneous children (as in `<NoChild>extra</NoChild>`) don't pass this check,
|
||||
// since `children` is a SyntaxKind.PropertySignature instead of a SyntaxKind.JsxAttribute.
|
||||
errorNode = prop.valueDeclaration.name;
|
||||
}
|
||||
reportError(Diagnostics.Property_0_does_not_exist_on_type_1, symbolToString(prop), typeToString(errorTarget));
|
||||
const propName = symbolToString(prop);
|
||||
const suggestionSymbol = getSuggestedSymbolForNonexistentJSXAttribute(propName, errorTarget);
|
||||
const suggestion = suggestionSymbol ? symbolToString(suggestionSymbol) : undefined;
|
||||
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));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// use the property's value declaration if the property is assigned inside the literal itself
|
||||
const objectLiteralDeclaration = source.symbol && firstOrUndefined(source.symbol.declarations);
|
||||
let suggestion;
|
||||
let suggestion: string | undefined;
|
||||
if (prop.valueDeclaration && findAncestor(prop.valueDeclaration, d => d === objectLiteralDeclaration) && getSourceFileOfNode(objectLiteralDeclaration) === getSourceFileOfNode(errorNode)) {
|
||||
const propDeclaration = prop.valueDeclaration as ObjectLiteralElementLike;
|
||||
Debug.assertNode(propDeclaration, isObjectLiteralElementLike);
|
||||
@@ -24877,6 +24885,15 @@ namespace ts {
|
||||
return getSpellingSuggestionForName(isString(name) ? name : idText(name), getPropertiesOfType(containingType), SymbolFlags.Value);
|
||||
}
|
||||
|
||||
function getSuggestedSymbolForNonexistentJSXAttribute(name: Identifier | PrivateIdentifier | string, containingType: Type): Symbol | undefined {
|
||||
const strName = isString(name) ? name : idText(name);
|
||||
const properties = getPropertiesOfType(containingType);
|
||||
const jsxSpecific = strName === "for" ? find(properties, x => symbolName(x) === "htmlFor")
|
||||
: strName === "class" ? find(properties, x => symbolName(x) === "className")
|
||||
: undefined;
|
||||
return jsxSpecific ?? getSpellingSuggestionForName(strName, properties, SymbolFlags.Value);
|
||||
}
|
||||
|
||||
function getSuggestionForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): string | undefined {
|
||||
const suggestion = getSuggestedSymbolForNonexistentProperty(name, containingType);
|
||||
return suggestion && symbolName(suggestion);
|
||||
@@ -28223,7 +28240,7 @@ namespace ts {
|
||||
error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_a_property_reference);
|
||||
return booleanType;
|
||||
}
|
||||
if (expr.kind === SyntaxKind.PropertyAccessExpression && isPrivateIdentifier(expr.name)) {
|
||||
if (isPropertyAccessExpression(expr) && isPrivateIdentifier(expr.name)) {
|
||||
error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_private_identifier);
|
||||
}
|
||||
const links = getNodeLinks(expr);
|
||||
|
||||
@@ -4010,6 +4010,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 */ getSuggestedSymbolForNonexistentJSXAttribute(name: Identifier | string, containingType: Type): 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;
|
||||
|
||||
Reference in New Issue
Block a user