add spelling suggestion support for module

This commit is contained in:
王文璐
2018-03-15 10:00:21 +08:00
parent d1d69602ae
commit 58b147e4c4
6 changed files with 36 additions and 3 deletions

View File

@@ -294,6 +294,7 @@ namespace ts {
getAllPossiblePropertiesOfTypes,
getSuggestionForNonexistentProperty: (node, type) => getSuggestionForNonexistentProperty(node, type),
getSuggestionForNonexistentSymbol: (location, name, meaning) => getSuggestionForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning),
getSuggestionForNonexistentModule: (node, target) => getSuggestionForNonexistentModule(node, target),
getBaseConstraintOfType,
getDefaultFromTypeParameter: type => type && type.flags & TypeFlags.TypeParameter ? getDefaultFromTypeParameter(type as TypeParameter) : undefined,
resolveName(name, location, meaning, excludeGlobals) {

View File

@@ -2890,6 +2890,7 @@ namespace ts {
getApparentType(type: Type): Type;
getSuggestionForNonexistentProperty(node: Identifier, containingType: Type): string | undefined;
getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined;
getSuggestionForNonexistentModule(node: Identifier, target: Symbol): string | undefined;
getBaseConstraintOfType(type: Type): Type | undefined;
getDefaultFromTypeParameter(type: Type): Type | undefined;

View File

@@ -4,12 +4,13 @@ namespace ts.codefix {
const 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,
Diagnostics.Module_0_has_no_exported_member_1_Did_you_mean_2.code,
];
registerCodeFix({
errorCodes,
getCodeActions(context) {
const { sourceFile } = context;
const info = getInfo(sourceFile, context.span.start, context.program.getTypeChecker());
const info = getInfo(sourceFile, context.span.start, context);
if (!info) return undefined;
const { node, suggestion } = info;
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, node, suggestion));
@@ -18,16 +19,17 @@ namespace ts.codefix {
},
fixIds: [fixId],
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => {
const info = getInfo(diag.file!, diag.start!, context.program.getTypeChecker());
const info = getInfo(diag.file!, diag.start!, context);
if (info) doChange(changes, context.sourceFile, info.node, info.suggestion);
}),
});
function getInfo(sourceFile: SourceFile, pos: number, checker: TypeChecker): { node: Node, suggestion: string } | undefined {
function getInfo(sourceFile: SourceFile, pos: number, context: CodeFixContextBase): { node: Node, suggestion: string } | undefined {
// This is the identifier of the misspelled word. eg:
// this.speling = 1;
// ^^^^^^^
const node = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); // TODO: GH#15852
const checker = context.program.getTypeChecker();
let suggestion: string;
if (isPropertyAccessExpression(node.parent) && node.parent.name === node) {
@@ -35,6 +37,14 @@ namespace ts.codefix {
const containingType = checker.getTypeAtLocation(node.parent.expression);
suggestion = checker.getSuggestionForNonexistentProperty(node as Identifier, containingType);
}
else if (isImportSpecifier(node.parent) && node.parent.name === node) {
Debug.assert(node.kind === SyntaxKind.Identifier);
const importDeclaration = findAncestor(node, isImportDeclaration);
const resolvedSourceFile = getResolvedSourceFileFromImportDeclaration(sourceFile, context, importDeclaration);
if (resolvedSourceFile && resolvedSourceFile.symbol) {
suggestion = checker.getSuggestionForNonexistentModule(node as Identifier, resolvedSourceFile.symbol);
}
}
else {
const meaning = getMeaningFromLocation(node);
const name = getTextOfNode(node);
@@ -62,4 +72,13 @@ namespace ts.codefix {
}
return flags;
}
function getResolvedSourceFileFromImportDeclaration (sourceFile: SourceFile, context: CodeFixContextBase, importDeclaration: ImportDeclaration): SourceFile | undefined {
if (!importDeclaration || !isStringLiteralLike(importDeclaration.moduleSpecifier)) return undefined;
const resolvedModule = getResolvedModule(sourceFile, importDeclaration.moduleSpecifier.text);
if (!resolvedModule) return undefined;
return context.program.getSourceFile(resolvedModule.resolvedFileName);
}
}

View File

@@ -1820,6 +1820,7 @@ declare namespace ts {
getApparentType(type: Type): Type;
getSuggestionForNonexistentProperty(node: Identifier, containingType: Type): string | undefined;
getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined;
getSuggestionForNonexistentModule(node: Identifier, target: Symbol): string | undefined;
getBaseConstraintOfType(type: Type): Type | undefined;
getDefaultFromTypeParameter(type: Type): Type | undefined;
}

View File

@@ -1820,6 +1820,7 @@ declare namespace ts {
getApparentType(type: Type): Type;
getSuggestionForNonexistentProperty(node: Identifier, containingType: Type): string | undefined;
getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined;
getSuggestionForNonexistentModule(node: Identifier, target: Symbol): string | undefined;
getBaseConstraintOfType(type: Type): Type | undefined;
getDefaultFromTypeParameter(type: Type): Type | undefined;
}

View File

@@ -0,0 +1,10 @@
/// <reference path='fourslash.ts' />
// @Filename: f1.ts
////export const fooooooooo = 1;
// @Filename: f2.ts
////import {[|fooooooooa|]} from "./f1";
goTo.file("f2.ts")
verify.rangeAfterCodeFix(`fooooooooo`);