Skip to content

Commit b47c1fd

Browse files
authored
Merge pull request #22593 from Kingwl/module-spelling-fix
add spelling suggestion support for module
2 parents 6b7bf5e + 58b147e commit b47c1fd

File tree

6 files changed

+36
-3
lines changed

6 files changed

+36
-3
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ namespace ts {
294294
getAllPossiblePropertiesOfTypes,
295295
getSuggestionForNonexistentProperty: (node, type) => getSuggestionForNonexistentProperty(node, type),
296296
getSuggestionForNonexistentSymbol: (location, name, meaning) => getSuggestionForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning),
297+
getSuggestionForNonexistentModule: (node, target) => getSuggestionForNonexistentModule(node, target),
297298
getBaseConstraintOfType,
298299
getDefaultFromTypeParameter: type => type && type.flags & TypeFlags.TypeParameter ? getDefaultFromTypeParameter(type as TypeParameter) : undefined,
299300
resolveName(name, location, meaning, excludeGlobals) {

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2901,6 +2901,7 @@ namespace ts {
29012901
getApparentType(type: Type): Type;
29022902
getSuggestionForNonexistentProperty(node: Identifier, containingType: Type): string | undefined;
29032903
getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined;
2904+
getSuggestionForNonexistentModule(node: Identifier, target: Symbol): string | undefined;
29042905
getBaseConstraintOfType(type: Type): Type | undefined;
29052906
getDefaultFromTypeParameter(type: Type): Type | undefined;
29062907

src/services/codefixes/fixSpelling.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,46 @@ namespace ts.codefix {
44
const errorCodes = [
55
Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2.code,
66
Diagnostics.Cannot_find_name_0_Did_you_mean_1.code,
7+
Diagnostics.Module_0_has_no_exported_member_1_Did_you_mean_2.code,
78
];
89
registerCodeFix({
910
errorCodes,
1011
getCodeActions(context) {
1112
const { sourceFile } = context;
12-
const info = getInfo(sourceFile, context.span.start, context.program.getTypeChecker());
13+
const info = getInfo(sourceFile, context.span.start, context);
1314
if (!info) return undefined;
1415
const { node, suggestion } = info;
1516
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, node, suggestion));
1617
return [createCodeFixAction(changes, [Diagnostics.Change_spelling_to_0, suggestion], fixId, Diagnostics.Fix_all_detected_spelling_errors)];
1718
},
1819
fixIds: [fixId],
1920
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => {
20-
const info = getInfo(diag.file!, diag.start!, context.program.getTypeChecker());
21+
const info = getInfo(diag.file!, diag.start!, context);
2122
if (info) doChange(changes, context.sourceFile, info.node, info.suggestion);
2223
}),
2324
});
2425

25-
function getInfo(sourceFile: SourceFile, pos: number, checker: TypeChecker): { node: Node, suggestion: string } | undefined {
26+
function getInfo(sourceFile: SourceFile, pos: number, context: CodeFixContextBase): { node: Node, suggestion: string } | undefined {
2627
// This is the identifier of the misspelled word. eg:
2728
// this.speling = 1;
2829
// ^^^^^^^
2930
const node = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); // TODO: GH#15852
31+
const checker = context.program.getTypeChecker();
3032

3133
let suggestion: string;
3234
if (isPropertyAccessExpression(node.parent) && node.parent.name === node) {
3335
Debug.assert(node.kind === SyntaxKind.Identifier);
3436
const containingType = checker.getTypeAtLocation(node.parent.expression);
3537
suggestion = checker.getSuggestionForNonexistentProperty(node as Identifier, containingType);
3638
}
39+
else if (isImportSpecifier(node.parent) && node.parent.name === node) {
40+
Debug.assert(node.kind === SyntaxKind.Identifier);
41+
const importDeclaration = findAncestor(node, isImportDeclaration);
42+
const resolvedSourceFile = getResolvedSourceFileFromImportDeclaration(sourceFile, context, importDeclaration);
43+
if (resolvedSourceFile && resolvedSourceFile.symbol) {
44+
suggestion = checker.getSuggestionForNonexistentModule(node as Identifier, resolvedSourceFile.symbol);
45+
}
46+
}
3747
else {
3848
const meaning = getMeaningFromLocation(node);
3949
const name = getTextOfNode(node);
@@ -61,4 +71,13 @@ namespace ts.codefix {
6171
}
6272
return flags;
6373
}
74+
75+
function getResolvedSourceFileFromImportDeclaration (sourceFile: SourceFile, context: CodeFixContextBase, importDeclaration: ImportDeclaration): SourceFile | undefined {
76+
if (!importDeclaration || !isStringLiteralLike(importDeclaration.moduleSpecifier)) return undefined;
77+
78+
const resolvedModule = getResolvedModule(sourceFile, importDeclaration.moduleSpecifier.text);
79+
if (!resolvedModule) return undefined;
80+
81+
return context.program.getSourceFile(resolvedModule.resolvedFileName);
82+
}
6483
}

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1825,6 +1825,7 @@ declare namespace ts {
18251825
getApparentType(type: Type): Type;
18261826
getSuggestionForNonexistentProperty(node: Identifier, containingType: Type): string | undefined;
18271827
getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined;
1828+
getSuggestionForNonexistentModule(node: Identifier, target: Symbol): string | undefined;
18281829
getBaseConstraintOfType(type: Type): Type | undefined;
18291830
getDefaultFromTypeParameter(type: Type): Type | undefined;
18301831
}

tests/baselines/reference/api/typescript.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1825,6 +1825,7 @@ declare namespace ts {
18251825
getApparentType(type: Type): Type;
18261826
getSuggestionForNonexistentProperty(node: Identifier, containingType: Type): string | undefined;
18271827
getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined;
1828+
getSuggestionForNonexistentModule(node: Identifier, target: Symbol): string | undefined;
18281829
getBaseConstraintOfType(type: Type): Type | undefined;
18291830
getDefaultFromTypeParameter(type: Type): Type | undefined;
18301831
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @Filename: f1.ts
4+
////export const fooooooooo = 1;
5+
6+
// @Filename: f2.ts
7+
////import {[|fooooooooa|]} from "./f1";
8+
9+
goTo.file("f2.ts")
10+
verify.rangeAfterCodeFix(`fooooooooo`);

0 commit comments

Comments
 (0)