-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Code fix for missing imports #11768
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Code fix for missing imports #11768
Changes from 1 commit
0389207
eb46886
80d7f5c
a6807ab
1502f75
e72f0c8
d273308
35d668a
eb892d3
6d024dc
26cd24a
a282fc0
1f82ce7
d83c292
7568f6f
aa2891c
055d20f
11ea6b3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,7 @@ namespace ts.codefix { | |
} | ||
} | ||
|
||
const currentTokenMeaning = getMeaningFromLocation(token); | ||
for (const moduleSymbol of allPotentialModules) { | ||
context.cancellationToken.throwIfCancellationRequested(); | ||
|
||
|
@@ -28,8 +29,6 @@ namespace ts.codefix { | |
continue; | ||
} | ||
|
||
const currentTokenMeaning = getMeaningFromLocation(token); | ||
|
||
// check the default export | ||
const defaultExport = moduleExports["default"]; | ||
if (defaultExport) { | ||
|
@@ -85,58 +84,30 @@ namespace ts.codefix { | |
} | ||
|
||
function getCodeActionForExistingImport(declaration: ImportDeclaration | ImportEqualsDeclaration): CodeAction { | ||
let namespacePrefix: string; | ||
let moduleSpecifier: string; | ||
if (declaration.kind === SyntaxKind.ImportDeclaration) { | ||
const namedBindings = declaration.importClause && declaration.importClause.namedBindings; | ||
if (namedBindings && namedBindings.kind === SyntaxKind.NamespaceImport) { | ||
namespacePrefix = (<NamespaceImport>namedBindings).name.getText(); | ||
if (namedBindings) { | ||
if (namedBindings.kind === SyntaxKind.NamespaceImport) { | ||
return getCodeActionForNamespaceImport(namedBindings.name.getText()); | ||
} | ||
/** | ||
* If the existing import declaration already has a named import list, just | ||
* insert the identifier into that list. | ||
*/ | ||
const textChange = getTextChangeForImportList(namedBindings); | ||
return createCodeAction( | ||
Diagnostics.Add_0_to_existing_import_declaration_from_1, | ||
[name, declaration.moduleSpecifier.getText()], | ||
textChange.newText, | ||
textChange.span, | ||
sourceFile.fileName | ||
); | ||
} | ||
|
||
moduleSpecifier = declaration.moduleSpecifier.getText(); | ||
} | ||
else { | ||
namespacePrefix = declaration.name.getText(); | ||
moduleSpecifier = declaration.moduleReference.getText(); | ||
// insert a new import statement in a new lines | ||
return getCodeActionForNewImport(declaration.moduleSpecifier.getText(), declaration.getEnd()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand why this is here. You already have an existing import for the module, why would you need to add another statement importing from the same module? Is this only if the existing statement contains a namespace import, and you want to add an import list import? (Is that valid/recommended?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes it is used when we want to add a new import list, while the existing one is a namespace import. And in the latest implementation, when you have: import * as ns from "module";
foo // foo is a member from ns We provide two options: import * as ns from "module";
import { foo } from "module";
foo // foo is a member from ns The user can choose from these two. It is valid code, and as we cannot delete any user's code, I think these are the only options. |
||
} | ||
|
||
/** | ||
* Cases: | ||
* import * as ns from "mod" | ||
* import default, * as ns from "mod" | ||
* import ns = require("mod") | ||
* | ||
* Because there is no import list, we alter the reference to include the | ||
* namespace instead of altering the import declaration. For example, "foo" would | ||
* become "ns.foo" | ||
*/ | ||
if (namespacePrefix) { | ||
return createCodeAction( | ||
Diagnostics.Change_0_to_1, | ||
[name, `${namespacePrefix}.${name}`], | ||
`${namespacePrefix}.`, | ||
{ start: token.getStart(), length: 0 }, | ||
8000 sourceFile.fileName | ||
); | ||
} | ||
/** | ||
* If the existing import declaration already has a named import list, just | ||
* insert the identifier into that list. | ||
*/ | ||
else if (declaration.kind === SyntaxKind.ImportDeclaration && | ||
declaration.importClause && | ||
declaration.importClause.namedBindings && | ||
declaration.importClause.namedBindings.kind === SyntaxKind.NamedImports) { | ||
const textChange = getTextChangeForImportList(declaration.importClause.namedBindings); | ||
return createCodeAction( | ||
Diagnostics.Add_0_to_existing_import_declaration_from_1, | ||
[name, moduleSpecifier], | ||
textChange.newText, | ||
textChange.span, | ||
sourceFile.fileName | ||
); | ||
} | ||
return getCodeActionForNewImport(moduleSpecifier, declaration.getEnd()); | ||
return getCodeActionForNamespaceImport(declaration.name.getText()); | ||
|
||
function getTextChangeForImportList(importList: NamedImports): TextChange { | ||
if (importList.elements.length === 0) { | ||
|
@@ -174,6 +145,26 @@ namespace ts.codefix { | |
span: { start: insertPoint, length: 0 } | ||
}; | ||
} | ||
|
||
function getCodeActionForNamespaceImport(namespacePrefix: string): CodeAction { | ||
/** | ||
* Cases: | ||
* import * as ns from "mod" | ||
* import default, * as ns from "mod" | ||
* import ns = require("mod") | ||
* | ||
* Because there is no import list, we alter the reference to include the | ||
* namespace instead of altering the import declaration. For example, "foo" would | ||
* become "ns.foo" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i would rather we add a new import defalcation regardless. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I ended up providing two code actions to the user, and he/she can do either one. I think C# has the same behavior. |
||
*/ | ||
return createCodeAction( | ||
Diagnostics.Change_0_to_1, | ||
[name, `${namespacePrefix}.${name}`], | ||
`${namespacePrefix}.`, | ||
{ start: token.getStart(), length: 0 }, | ||
sourceFile.fileName | ||
); | ||
} | ||
} | ||
|
||
function getCodeActionForNewImport(moduleSpecifier?: string, insertPos?: number): CodeAction { | ||
|
@@ -260,7 +251,6 @@ namespace ts.codefix { | |
relativeName = removeFileExtension(relativeName); | ||
|
||
if (options.paths) { | ||
// TODO: handle longest match support | ||
for (const key in options.paths) { | ||
for (const pattern of options.paths[key]) { | ||
const indexOfStar = pattern.indexOf("*"); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need to handel the
default
import case, if you already have: