diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts index 8e1d0ac2f29..ef0025d2b25 100644 --- a/src/services/codefixes/fixAddMissingMember.ts +++ b/src/services/codefixes/fixAddMissingMember.ts @@ -1,7 +1,8 @@ /* @internal */ namespace ts.codefix { registerCodeFix({ - errorCodes: [Diagnostics.Property_0_does_not_exist_on_type_1.code], + errorCodes: [Diagnostics.Property_0_does_not_exist_on_type_1.code, + Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2.code], getCodeActions: getActionsForAddMissingMember }); @@ -135,4 +136,4 @@ namespace ts.codefix { return actions; } } -} \ No newline at end of file +} diff --git a/src/services/codefixes/fixSpelling.ts b/src/services/codefixes/fixSpelling.ts new file mode 100644 index 00000000000..b58dab95002 --- /dev/null +++ b/src/services/codefixes/fixSpelling.ts @@ -0,0 +1,53 @@ +/* @internal */ +namespace ts.codefix { + registerCodeFix({ + errorCodes: [Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2.code, + Diagnostics.Cannot_find_name_0_Did_you_mean_1.code], + getCodeActions: getActionsForCorrectSpelling + }); + + function getActionsForCorrectSpelling(context: CodeFixContext): CodeAction[] | undefined { + const sourceFile = context.sourceFile; + + // This is the identifier of the misspelled word. eg: + // this.speling = 1; + // ^^^^^^^ + const node = getTokenAtPosition(sourceFile, context.span.start); + const checker = context.program.getTypeChecker(); + let suggestion: string; + if (node.kind === SyntaxKind.Identifier && isPropertyAccessExpression(node.parent)) { + const containingType = checker.getTypeAtLocation(node.parent.expression); + suggestion = checker.getSuggestionForNonexistentProperty(node as Identifier, containingType); + } + else { + const meaning = getMeaningFromLocation(node); + suggestion = checker.getSuggestionForNonexistentSymbol(node, getTextOfNode(node), convertSemanticMeaningToSymbolFlags(meaning)); + } + if (suggestion) { + return [{ + description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Change_spelling_to_0), [suggestion]), + changes: [{ + fileName: sourceFile.fileName, + textChanges: [{ + span: { start: node.getStart(), length: node.getWidth() }, + newText: suggestion + }], + }], + }]; + } + } + + function convertSemanticMeaningToSymbolFlags(meaning: SemanticMeaning): SymbolFlags { + let flags = 0; + if (meaning & SemanticMeaning.Namespace) { + flags |= SymbolFlags.Namespace; + } + if (meaning & SemanticMeaning.Type) { + flags |= SymbolFlags.Type; + } + if (meaning & SemanticMeaning.Value) { + flags |= SymbolFlags.Value; + } + return flags; + } +} diff --git a/src/services/codefixes/fixes.ts b/src/services/codefixes/fixes.ts index ae1643dfa3b..c2e2509a28e 100644 --- a/src/services/codefixes/fixes.ts +++ b/src/services/codefixes/fixes.ts @@ -1,5 +1,6 @@ /// /// +/// /// /// /// diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 78c27a1276b..0bc18ce7667 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -116,6 +116,7 @@ namespace ts.codefix { registerCodeFix({ errorCodes: [ Diagnostics.Cannot_find_name_0.code, + Diagnostics.Cannot_find_name_0_Did_you_mean_1.code, Diagnostics.Cannot_find_namespace_0.code, Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead.code ], diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index 978195a31f6..fd7269d46dd 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -82,6 +82,7 @@ "formatting/tokenRange.ts", "codeFixProvider.ts", "codefixes/fixAddMissingMember.ts", + "codefixes/fixSpelling.ts", "codefixes/fixExtendsInterfaceBecomesImplements.ts", "codefixes/fixClassIncorrectlyImplementsInterface.ts", "codefixes/fixClassDoesntImplementInheritedAbstractMember.ts", @@ -94,4 +95,4 @@ "codefixes/unusedIdentifierFixes.ts", "codefixes/disableJsDiagnostics.ts" ] -} \ No newline at end of file +}