Separate delete-all-imports from other delete-all (#41105)

This fixes the first part of #32196
This commit is contained in:
Nathan Shively-Sanders
2020-11-02 14:18:50 -08:00
committed by GitHub
parent 53bc006752
commit ae81add083
4 changed files with 147 additions and 8 deletions

View File

@@ -5959,6 +5959,10 @@
"category": "Message",
"code": 95144
},
"Delete all unused imports": {
"category": "Message",
"code": 95145
},
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
"category": "Error",

View File

@@ -3,6 +3,7 @@ namespace ts.codefix {
const fixName = "unusedIdentifier";
const fixIdPrefix = "unusedIdentifier_prefix";
const fixIdDelete = "unusedIdentifier_delete";
const fixIdDeleteImports = "unusedIdentifier_deleteImports";
const fixIdInfer = "unusedIdentifier_infer";
const errorCodes = [
Diagnostics._0_is_declared_but_its_value_is_never_read.code,
@@ -32,7 +33,13 @@ namespace ts.codefix {
const importDecl = tryGetFullImport(token);
if (importDecl) {
const changes = textChanges.ChangeTracker.with(context, t => t.delete(sourceFile, importDecl));
return [createDeleteFix(changes, [Diagnostics.Remove_import_from_0, showModuleSpecifier(importDecl)])];
return [createCodeFixAction(fixName, changes, [Diagnostics.Remove_import_from_0, showModuleSpecifier(importDecl)], fixIdDeleteImports, Diagnostics.Delete_all_unused_imports)];
}
else if (isImport(token)) {
const deletion = textChanges.ChangeTracker.with(context, t => tryDeleteDeclaration(sourceFile, token, t, checker, sourceFiles, /*isFixAll*/ false));
if (deletion.length) {
return [createCodeFixAction(fixName, deletion, [Diagnostics.Remove_unused_declaration_for_Colon_0, token.getText(sourceFile)], fixIdDeleteImports, Diagnostics.Delete_all_unused_imports)];
}
}
if (isObjectBindingPattern(token.parent)) {
@@ -82,7 +89,7 @@ namespace ts.codefix {
return result;
},
fixIds: [fixIdPrefix, fixIdDelete, fixIdInfer],
fixIds: [fixIdPrefix, fixIdDelete, fixIdDeleteImports, fixIdInfer],
getAllCodeActions: context => {
const { sourceFile, program } = context;
const checker = program.getTypeChecker();
@@ -93,14 +100,20 @@ namespace ts.codefix {
case fixIdPrefix:
tryPrefixDeclaration(changes, diag.code, sourceFile, token);
break;
case fixIdDelete: {
if (token.kind === SyntaxKind.InferKeyword) {
break; // Can't delete
}
case fixIdDeleteImports: {
const importDecl = tryGetFullImport(token);
if (importDecl) {
changes.delete(sourceFile, importDecl);
}
else if (isImport(token)) {
tryDeleteDeclaration(sourceFile, token, changes, checker, sourceFiles, /*isFixAll*/ true);
}
break;
}
case fixIdDelete: {
if (token.kind === SyntaxKind.InferKeyword || isImport(token)) {
break; // Can't delete
}
else if (isJSDocTemplateTag(token)) {
changes.delete(sourceFile, token);
}
@@ -147,6 +160,11 @@ namespace ts.codefix {
changes.delete(sourceFile, Debug.checkDefined(cast(token.parent, isDeclarationWithTypeParameterChildren).typeParameters, "The type parameter to delete should exist"));
}
function isImport(token: Node) {
return token.kind === SyntaxKind.ImportKeyword
|| token.kind === SyntaxKind.Identifier && (token.parent.kind === SyntaxKind.ImportSpecifier || token.parent.kind === SyntaxKind.ImportClause);
}
// Sometimes the diagnostic span is an entire ImportDeclaration, so we should remove the whole thing.
function tryGetFullImport(token: Node): ImportDeclaration | undefined {
return token.kind === SyntaxKind.ImportKeyword ? tryCast(token.parent, isImportDeclaration) : undefined;