diff --git a/src/services/codefixes/fixReactClassNameAndHTMLFor.ts b/src/services/codefixes/fixReactClassNameAndHTMLFor.ts new file mode 100644 index 00000000000..aa3a92a6a1d --- /dev/null +++ b/src/services/codefixes/fixReactClassNameAndHTMLFor.ts @@ -0,0 +1,60 @@ +/* @internal */ +namespace ts.codefix { + const fixID = "fixReactClassNameAndHTMLFor"; + const errorCodes = [Diagnostics.Type_0_is_not_assignable_to_type_1.code]; + registerCodeFix({ + errorCodes, + getCodeActions: context => { + const { jsx } = context.program.getCompilerOptions(); + if (jsx !== JsxEmit.React) { + return undefined; + } + const { sourceFile, span } = context; + const node = getTokenAtPosition(sourceFile, span.start); + if (!shouldFix(node)) return undefined; + const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, node)); + return [createCodeFixAction(fixID, changes, [Diagnostics.Did_you_mean_0, getCorrectName(node)], fixID, Diagnostics.Fix_all_detected_spelling_errors)]; + }, + fixIds: [fixID], + getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { + const node = getTokenAtPosition(context.sourceFile, diag.start); + if (!shouldFix(node)) return; + doChange(changes, context.sourceFile, node); + }), + }); + + function doChange(changeTracker: textChanges.ChangeTracker, sf: SourceFile, node: Identifier) { + changeTracker.replaceNode(sf, node, createIdentifier(getCorrectName(node))); + } + + function getCorrectName(node: Identifier) { + const text = node.text; + if (text === "class") return "className"; + if (text === "for") return "htmlFor"; + return Debug.fail(); + } + + function shouldFix(node: Node): node is Identifier { + //