Skip to content

Commit

Permalink
fix(42605): support refactoring for export default assignment without…
Browse files Browse the repository at this point in the history
… equal (#42936)
  • Loading branch information
Zuckjet authored Apr 5, 2021
1 parent cf8798d commit f621d67
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 5 deletions.
4 changes: 3 additions & 1 deletion src/services/findAllReferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1180,7 +1180,9 @@ namespace ts.FindAllReferences {
for (const indirectUser of indirectUsers) {
for (const node of getPossibleSymbolReferenceNodes(indirectUser, isDefaultExport ? "default" : exportName)) {
// Import specifiers should be handled by importSearches
if (isIdentifier(node) && !isImportOrExportSpecifier(node.parent) && checker.getSymbolAtLocation(node) === exportSymbol) {
const symbol = checker.getSymbolAtLocation(node);
const hasExportAssignmentDeclaration = some(symbol?.declarations, d => tryCast(d, isExportAssignment) ? true : false);
if (isIdentifier(node) && !isImportOrExportSpecifier(node.parent) && (symbol === exportSymbol || hasExportAssignmentDeclaration)) {
cb(node);
}
}
Expand Down
21 changes: 17 additions & 4 deletions src/services/refactors/convertExport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ namespace ts.refactor {
});

// If a VariableStatement, will have exactly one VariableDeclaration, with an Identifier for a name.
type ExportToConvert = FunctionDeclaration | ClassDeclaration | InterfaceDeclaration | EnumDeclaration | NamespaceDeclaration | TypeAliasDeclaration | VariableStatement;
type ExportToConvert = FunctionDeclaration | ClassDeclaration | InterfaceDeclaration | EnumDeclaration | NamespaceDeclaration | TypeAliasDeclaration | VariableStatement | ExportAssignment;
interface ExportInfo {
readonly exportNode: ExportToConvert;
readonly exportName: Identifier; // This is exportNode.name except for VariableStatement_s.
Expand All @@ -67,7 +67,8 @@ namespace ts.refactor {

const exportingModuleSymbol = isSourceFile(exportNode.parent) ? exportNode.parent.symbol : exportNode.parent.parent.symbol;

const flags = getSyntacticModifierFlags(exportNode);
const flags = getSyntacticModifierFlags(exportNode) || ((isExportAssignment(exportNode) && !exportNode.isExportEquals) ? ModifierFlags.ExportDefault : ModifierFlags.None);

const wasDefault = !!(flags & ModifierFlags.Default);
// If source file already has a default export, don't offer refactor.
if (!(flags & ModifierFlags.Export) || !wasDefault && exportingModuleSymbol.exports!.has(InternalSymbolName.Default)) {
Expand Down Expand Up @@ -95,6 +96,11 @@ namespace ts.refactor {
Debug.assert(!wasDefault, "Can't have a default flag here");
return isIdentifier(decl.name) ? { exportNode: vs, exportName: decl.name, wasDefault, exportingModuleSymbol } : undefined;
}
case SyntaxKind.ExportAssignment: {
const node = exportNode as ExportAssignment;
const exp = node.expression as Identifier;
return node.isExportEquals ? undefined : { exportNode: node, exportName: exp, wasDefault, exportingModuleSymbol };
}
default:
return undefined;
}
Expand All @@ -107,7 +113,14 @@ namespace ts.refactor {

function changeExport(exportingSourceFile: SourceFile, { wasDefault, exportNode, exportName }: ExportInfo, changes: textChanges.ChangeTracker, checker: TypeChecker): void {
if (wasDefault) {
changes.delete(exportingSourceFile, Debug.checkDefined(findModifier(exportNode, SyntaxKind.DefaultKeyword), "Should find a default keyword in modifier list"));
if (isExportAssignment(exportNode) && !exportNode.isExportEquals) {
const exp = exportNode.expression as Identifier;
const spec = makeExportSpecifier(exp.text, exp.text);
changes.replaceNode(exportingSourceFile, exportNode, factory.createExportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*isTypeOnly*/ false, factory.createNamedExports([spec])));
}
else {
changes.delete(exportingSourceFile, Debug.checkDefined(findModifier(exportNode, SyntaxKind.DefaultKeyword), "Should find a default keyword in modifier list"));
}
}
else {
const exportKeyword = Debug.checkDefined(findModifier(exportNode, SyntaxKind.ExportKeyword), "Should find an export keyword in modifier list");
Expand All @@ -134,7 +147,7 @@ namespace ts.refactor {
changes.insertNodeAfter(exportingSourceFile, exportNode, factory.createExportDefault(factory.createIdentifier(exportName.text)));
break;
default:
Debug.assertNever(exportNode, `Unexpected exportNode kind ${(exportNode as ExportToConvert).kind}`);
Debug.fail(`Unexpected exportNode kind ${(exportNode as ExportToConvert).kind}`);
}
}
}
Expand Down
44 changes: 44 additions & 0 deletions tests/cases/fourslash/refactorConvertExport_defaultToNamed2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/// <reference path='fourslash.ts' />

// @Filename: /a.ts
////const f = () => {};
/////*a*/export default f;/*b*/

// @Filename: /b.ts
////import f from "./a";
////import { default as f } from "./a";
////import { default as g } from "./a";
////import f, * as a from "./a";
////
////export { default } from "./a";
////export { default as f } from "./a";
////export { default as i } from "./a";
////
////import * as a from "./a";
////a.default();

goTo.select("a", "b");
edit.applyRefactor({
refactorName: "Convert export",
actionName: "Convert default export to named export",
actionDescription: "Convert default export to named export",
newContent: {
"/a.ts":
`const f = () => {};
export { f };`,

"/b.ts":
`import { f } from "./a";
import { f } from "./a";
import { f as g } from "./a";
import * as a from "./a";
import { f } from "./a";
export { f as default } from "./a";
export { f } from "./a";
export { f as i } from "./a";
import * as a from "./a";
a.f();`,
},
});

0 comments on commit f621d67

Please sign in to comment.