From 328d130e82dbed852098ee127431dcf5de14035a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=EC=A7=80=EC=9B=90?= Date: Mon, 10 Jul 2023 23:06:32 +0900 Subject: [PATCH] Fix export as default not auto importing (#54871) --- src/services/utilities.ts | 25 +++++++++++++------ .../importNameCodeFixExportAsDefault.ts | 18 +++++++++++++ ...ameCodeFixExportAsDefaultExistingImport.ts | 13 ++++++++++ 3 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 tests/cases/fourslash/importNameCodeFixExportAsDefault.ts create mode 100644 tests/cases/fourslash/importNameCodeFixExportAsDefaultExistingImport.ts diff --git a/src/services/utilities.ts b/src/services/utilities.ts index be896d9d5ca..4d94041411e 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -3971,12 +3971,14 @@ export function getNamesForExportedSymbol(symbol: Symbol, scriptTarget: ScriptTa /** @internal */ export function getNameForExportedSymbol(symbol: Symbol, scriptTarget: ScriptTarget | undefined, preferCapitalized?: boolean) { if (needsNameFromDeclaration(symbol)) { - // Name of "export default foo;" is "foo". Name of "export default 0" is the filename converted to camelCase. + // Names for default exports: + // - export default foo => foo + // - export { foo as default } => foo + // - export default 0 => filename converted to camelCase return getDefaultLikeExportNameFromDeclaration(symbol) || codefix.moduleSymbolToValidIdentifier(getSymbolParentOrFail(symbol), scriptTarget, !!preferCapitalized); } return symbol.name; - } function needsNameFromDeclaration(symbol: Symbol) { @@ -3984,11 +3986,18 @@ function needsNameFromDeclaration(symbol: Symbol) { } function getDefaultLikeExportNameFromDeclaration(symbol: Symbol): string | undefined { - return firstDefined(symbol.declarations, d => - isExportAssignment(d) - ? tryCast(skipOuterExpressions(d.expression), isIdentifier)?.text - : tryCast(getNameOfDeclaration(d), isIdentifier)?.text - ); + return firstDefined(symbol.declarations, d => { + // "export default" in this case. See `ExportAssignment`for more details. + if (isExportAssignment(d)) { + return tryCast(skipOuterExpressions(d.expression), isIdentifier)?.text; + } + // "export { ~ as default }" + if (isExportSpecifier(d) && d.symbol.flags === SymbolFlags.Alias) { + return tryCast(d.propertyName, isIdentifier)?.text; + } + // GH#52694 + return tryCast(getNameOfDeclaration(d), isIdentifier)?.text; + }); } function getSymbolParentOrFail(symbol: Symbol) { @@ -4219,4 +4228,4 @@ export function fileShouldUseJavaScriptRequire(file: SourceFile | string, progra } } return preferRequire; -} \ No newline at end of file +} diff --git a/tests/cases/fourslash/importNameCodeFixExportAsDefault.ts b/tests/cases/fourslash/importNameCodeFixExportAsDefault.ts new file mode 100644 index 00000000000..5cc0b995210 --- /dev/null +++ b/tests/cases/fourslash/importNameCodeFixExportAsDefault.ts @@ -0,0 +1,18 @@ +/// + +// @Filename: /foo.ts +////const foo = 'foo' +////export { foo as default } + +// @Filename: /index.ts +//// foo/**/ + +verify.applyCodeActionFromCompletion("", { + name: "foo", + source: "/foo", + description: `Add import from "./foo"`, + newFileContent: `import foo from "./foo";\n\nfoo`, + preferences: { + includeCompletionsForModuleExports: true + } +}); diff --git a/tests/cases/fourslash/importNameCodeFixExportAsDefaultExistingImport.ts b/tests/cases/fourslash/importNameCodeFixExportAsDefaultExistingImport.ts new file mode 100644 index 00000000000..cd789161798 --- /dev/null +++ b/tests/cases/fourslash/importNameCodeFixExportAsDefaultExistingImport.ts @@ -0,0 +1,13 @@ +/// + +//// import [|{ v1, v2, v3 }|] from "./module"; +//// v4/*0*/(); + +// @Filename: module.ts +//// const v4 = 5; +//// export { v4 as default }; +//// export const v1 = 5; +//// export const v2 = 5; +//// export const v3 = 5; + +verify.importFixAtPosition([`v4, { v1, v2, v3 }`]);