Skip to content

Commit d3a2556

Browse files
committed
fix(42605): make Convert default export to named export avilable for export default assignment without equals
1 parent d9f5a85 commit d3a2556

File tree

5 files changed

+68
-7
lines changed

5 files changed

+68
-7
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37577,7 +37577,7 @@ namespace ts {
3757737577
return;
3757837578
}
3757937579
// Grammar checking
37580-
if (!checkGrammarDecoratorsAndModifiers(node) && hasEffectiveModifiers(node)) {
37580+
if (node.isExportEquals && !checkGrammarDecoratorsAndModifiers(node) && hasEffectiveModifiers(node)) {
3758137581
grammarErrorOnFirstToken(node, Diagnostics.An_export_assignment_cannot_have_modifiers);
3758237582
}
3758337583
if (node.expression.kind === SyntaxKind.Identifier) {

src/compiler/utilities.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4720,7 +4720,7 @@ namespace ts {
47204720
* NOTE: This function does not use `parent` pointers and will not include modifiers from JSDoc.
47214721
*/
47224722
export function getSyntacticModifierFlagsNoCache(node: Node): ModifierFlags {
4723-
let flags = modifiersToFlags(node.modifiers);
4723+
let flags = (isExportAssignment(node) && !node.isExportEquals) ? ModifierFlags.None : modifiersToFlags(node.modifiers);
47244724
if (node.flags & NodeFlags.NestedNamespace || (node.kind === SyntaxKind.Identifier && (<Identifier>node).isInJSDocNamespace)) {
47254725
flags |= ModifierFlags.Export;
47264726
}

src/services/findAllReferences.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1180,7 +1180,9 @@ namespace ts.FindAllReferences {
11801180
for (const indirectUser of indirectUsers) {
11811181
for (const node of getPossibleSymbolReferenceNodes(indirectUser, isDefaultExport ? "default" : exportName)) {
11821182
// Import specifiers should be handled by importSearches
1183-
if (isIdentifier(node) && !isImportOrExportSpecifier(node.parent) && checker.getSymbolAtLocation(node) === exportSymbol) {
1183+
const symbol = checker.getSymbolAtLocation(node);
1184+
const isExportDefaultAssignmentWithoutEquals = symbol && symbol.declarations && symbol.declarations[0] && isExportAssignment(symbol.declarations[0]) && !(symbol.declarations[0] as ExportAssignment).isExportEquals;
1185+
if (isIdentifier(node) && !isImportOrExportSpecifier(node.parent) && (symbol === exportSymbol || isExportDefaultAssignmentWithoutEquals)) {
11841186
cb(node);
11851187
}
11861188
}

src/services/refactors/convertExport.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ namespace ts.refactor {
4848
});
4949

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

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

70-
const flags = getSyntacticModifierFlags(exportNode);
70+
const flags = getSyntacticModifierFlags(exportNode) || ((isExportAssignment(exportNode) && !exportNode.isExportEquals) ? ModifierFlags.ExportDefault : ModifierFlags.None);
71+
7172
const wasDefault = !!(flags & ModifierFlags.Default);
7273
// If source file already has a default export, don't offer refactor.
7374
if (!(flags & ModifierFlags.Export) || !wasDefault && exportingModuleSymbol.exports!.has(InternalSymbolName.Default)) {
@@ -95,6 +96,11 @@ namespace ts.refactor {
9596
Debug.assert(!wasDefault, "Can't have a default flag here");
9697
return isIdentifier(decl.name) ? { exportNode: vs, exportName: decl.name, wasDefault, exportingModuleSymbol } : undefined;
9798
}
99+
case SyntaxKind.ExportAssignment: {
100+
const node = exportNode as ExportAssignment;
101+
const exp = node.expression as Identifier;
102+
return node.isExportEquals ? undefined : { exportNode: node, exportName: exp, wasDefault, exportingModuleSymbol };
103+
}
98104
default:
99105
return undefined;
100106
}
@@ -107,7 +113,16 @@ namespace ts.refactor {
107113

108114
function changeExport(exportingSourceFile: SourceFile, { wasDefault, exportNode, exportName }: ExportInfo, changes: textChanges.ChangeTracker, checker: TypeChecker): void {
109115
if (wasDefault) {
110-
changes.delete(exportingSourceFile, Debug.checkDefined(findModifier(exportNode, SyntaxKind.DefaultKeyword), "Should find a default keyword in modifier list"));
116+
if (isExportAssignment(exportNode) && !exportNode.isExportEquals) {
117+
const defaultKeyword = Debug.checkDefined(findChildOfKind(exportNode, SyntaxKind.DefaultKeyword, exportingSourceFile), "Should find an default keyword in child list");
118+
changes.delete(exportingSourceFile, defaultKeyword);
119+
const exp = exportNode.expression as Identifier;
120+
const spec = makeExportSpecifier(exp.text, exp.text);
121+
changes.replaceNode(exportingSourceFile, exp, factory.createNamedExports([spec]));
122+
}
123+
else {
124+
changes.delete(exportingSourceFile, Debug.checkDefined(findModifier(exportNode, SyntaxKind.DefaultKeyword), "Should find a default keyword in modifier list"));
125+
}
111126
}
112127
else {
113128
const exportKeyword = Debug.checkDefined(findModifier(exportNode, SyntaxKind.ExportKeyword), "Should find an export keyword in modifier list");
@@ -134,7 +149,7 @@ namespace ts.refactor {
134149
changes.insertNodeAfter(exportingSourceFile, exportNode, factory.createExportDefault(factory.createIdentifier(exportName.text)));
135150
break;
136151
default:
137-
Debug.assertNever(exportNode, `Unexpected exportNode kind ${(exportNode as ExportToConvert).kind}`);
152+
Debug.assertNever(exportNode as never, `Unexpected exportNode kind ${(exportNode as ExportToConvert).kind}`);
138153
}
139154
}
140155
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @Filename: /a.ts
4+
////const f = () => {};
5+
/////*a*/export default f;/*b*/
6+
7+
// @Filename: /b.ts
8+
////import f from "./a";
9+
////import { default as f } from "./a";
10+
////import { default as g } from "./a";
11+
////import f, * as a from "./a";
12+
////
13+
////export { default } from "./a";
14+
////export { default as f } from "./a";
15+
////export { default as i } from "./a";
16+
////
17+
////import * as a from "./a";
18+
////a.default();
19+
20+
goTo.select("a", "b");
21+
edit.applyRefactor({
22+
refactorName: "Convert export",
23+
actionName: "Convert default export to named export",
24+
actionDescription: "Convert default export to named export",
25+
newContent: {
26+
"/a.ts":
27+
`const f = () => {};
28+
export { f };`,
29+
30+
"/b.ts":
31+
`import { f } from "./a";
32+
import { f } from "./a";
33+
import { f as g } from "./a";
34+
import * as a from "./a";
35+
import { f } from "./a";
36+
37+
export { f as default } from "./a";
38+
export { f } from "./a";
39+
export { f as i } from "./a";
40+
41+
import * as a from "./a";
42+
a.f();`,
43+
},
44+
});

0 commit comments

Comments
 (0)