Skip to content

Commit 383319d

Browse files
authored
Merge pull request #25423 from Microsoft/defaultExportName
Handle getting name of default export that's an alias
2 parents 2059c36 + b1e916c commit 383319d

File tree

2 files changed

+57
-22
lines changed

2 files changed

+57
-22
lines changed

src/services/codefixes/importFixes.ts

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ namespace ts.codefix {
188188
const useNamespace = tryUseExistingNamespaceImport(existingImports, symbolName, symbolToken, checker);
189189
const addToExisting = tryAddToExistingImport(existingImports);
190190
// Don't bother providing an action to add a new import if we can add to an existing one.
191-
const addImport = addToExisting ? [addToExisting] : getCodeActionsForAddImport(exportInfos, existingImports, program, sourceFile, host, preferences);
191+
const addImport = addToExisting ? [addToExisting] : getFixesForAddImport(exportInfos, existingImports, program, sourceFile, host, preferences);
192192
return [...(useNamespace ? [useNamespace] : emptyArray), ...addImport];
193193
}
194194

@@ -261,7 +261,7 @@ namespace ts.codefix {
261261
return flatten<FixAddNewImport>(choicesForEachExportingModule.sort((a, b) => first(a).moduleSpecifier.length - first(b).moduleSpecifier.length));
262262
}
263263

264-
function getCodeActionsForAddImport(
264+
function getFixesForAddImport(
265265
exportInfos: ReadonlyArray<SymbolExportInfo>,
266266
existingImports: ReadonlyArray<FixAddToExistingImportInfo>,
267267
program: Program,
@@ -376,13 +376,9 @@ namespace ts.codefix {
376376
// check the default export
377377
const defaultExport = checker.tryGetMemberInModuleExports(InternalSymbolName.Default, moduleSymbol);
378378
if (defaultExport) {
379-
const localSymbol = getLocalSymbolForExportDefault(defaultExport);
380-
if ((
381-
localSymbol && localSymbol.escapedName === symbolName ||
382-
getEscapedNameForExportDefault(defaultExport) === symbolName ||
383-
moduleSymbolToValidIdentifier(moduleSymbol, program.getCompilerOptions().target!) === symbolName
384-
) && symbolHasMeaning(localSymbol || defaultExport, currentTokenMeaning)) {
385-
addSymbol(moduleSymbol, localSymbol || defaultExport, ImportKind.Default);
379+
const info = getDefaultExportInfo(defaultExport, moduleSymbol, program);
380+
if (info && info.name === symbolName && symbolHasMeaning(info.symbolForMeaning, currentTokenMeaning)) {
381+
addSymbol(moduleSymbol, defaultExport, ImportKind.Default);
386382
}
387383
}
388384

@@ -391,22 +387,41 @@ namespace ts.codefix {
391387
if (exportSymbolWithIdenticalName && symbolHasMeaning(exportSymbolWithIdenticalName, currentTokenMeaning)) {
392388
addSymbol(moduleSymbol, exportSymbolWithIdenticalName, ImportKind.Named);
393389
}
390+
});
391+
return originalSymbolToExportInfos;
392+
}
394393

395-
function getEscapedNameForExportDefault(symbol: Symbol): __String | undefined {
396-
return symbol.declarations && firstDefined(symbol.declarations, declaration => {
397-
if (isExportAssignment(declaration)) {
398-
if (isIdentifier(declaration.expression)) {
399-
return declaration.expression.escapedText;
400-
}
401-
}
402-
else if (isExportSpecifier(declaration)) {
403-
Debug.assert(declaration.name.escapedText === InternalSymbolName.Default);
404-
return declaration.propertyName && declaration.propertyName.escapedText;
405-
}
406-
});
394+
function getDefaultExportInfo(defaultExport: Symbol, moduleSymbol: Symbol, program: Program): { readonly symbolForMeaning: Symbol, readonly name: string } | undefined {
395+
const checker = program.getTypeChecker();
396+
397+
const localSymbol = getLocalSymbolForExportDefault(defaultExport);
398+
if (localSymbol) return { symbolForMeaning: localSymbol, name: localSymbol.name };
399+
400+
const name = getNameForExportDefault(defaultExport);
401+
if (name !== undefined) return { symbolForMeaning: defaultExport, name };
402+
403+
if (defaultExport.flags & SymbolFlags.Alias) {
404+
const aliased = checker.getAliasedSymbol(defaultExport);
405+
return getDefaultExportInfo(aliased, Debug.assertDefined(aliased.parent), program);
406+
}
407+
else {
408+
const moduleName = moduleSymbolToValidIdentifier(moduleSymbol, program.getCompilerOptions().target!);
409+
return moduleName === undefined ? undefined : { symbolForMeaning: defaultExport, name: moduleName };
410+
}
411+
}
412+
413+
function getNameForExportDefault(symbol: Symbol): string | undefined {
414+
return symbol.declarations && firstDefined(symbol.declarations, declaration => {
415+
if (isExportAssignment(declaration)) {
416+
if (isIdentifier(declaration.expression)) {
417+
return declaration.expression.text;
418+
}
419+
}
420+
else if (isExportSpecifier(declaration)) {
421+
Debug.assert(declaration.name.text === InternalSymbolName.Default);
422+
return declaration.propertyName && declaration.propertyName.text;
407423
}
408424
});
409-
return originalSymbolToExportInfos;
410425
}
411426

412427
function codeActionForFix(context: textChanges.TextChangesContext, sourceFile: SourceFile, symbolName: string, fix: ImportFix, quotePreference: QuotePreference): CodeFixAction {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @Filename: /a.ts
4+
////export default function foo(): void {}
5+
6+
// @Filename: /b.ts
7+
////export { default } from "./a";
8+
9+
// @Filename: /user.ts
10+
////[|foo;|]
11+
12+
goTo.file("/user.ts");
13+
verify.importFixAtPosition([
14+
`import foo from "./a";
15+
16+
foo;`,
17+
`import foo from "./b";
18+
19+
foo;`,
20+
]);

0 commit comments

Comments
 (0)