Skip to content

Commit fb5f855

Browse files
committed
Avoid convertExport when there's a non-identifier or a bogus one
Fixes microsoft#44105
1 parent 7954f0c commit fb5f855

File tree

3 files changed

+43
-5
lines changed

3 files changed

+43
-5
lines changed

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6397,6 +6397,10 @@
63976397
"category": "Message",
63986398
"code": 95163
63996399
},
6400+
"Can only convert named export": {
6401+
"category": "Message",
6402+
"code": 95164
6403+
},
64006404

64016405
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
64026406
"category": "Error",

src/services/refactors/convertExport.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ namespace ts.refactor {
5757
};
5858

5959
function getInfo(context: RefactorContext, considerPartialSpans = true): ExportInfo | RefactorErrorInfo | undefined {
60-
const { file } = context;
60+
const { file, program } = context;
6161
const span = getRefactorContextSpan(context);
6262
const token = getTokenAtPosition(file, span.start);
6363
const exportNode = !!(token.parent && getSyntacticModifierFlags(token.parent) & ModifierFlags.Export) && considerPartialSpans ? token.parent : getParentNodeInSpan(token, file, span);
@@ -75,6 +75,11 @@ namespace ts.refactor {
7575
return { error: getLocaleSpecificMessage(Diagnostics.This_file_already_has_a_default_export) };
7676
}
7777

78+
const checker = program.getTypeChecker();
79+
const noSymbolError = (id: Node) =>
80+
(isIdentifier(id) && checker.getSymbolAtLocation(id)) ? undefined
81+
: { error: getLocaleSpecificMessage(Diagnostics.Can_only_convert_named_export) };
82+
7883
switch (exportNode.kind) {
7984
case SyntaxKind.FunctionDeclaration:
8085
case SyntaxKind.ClassDeclaration:
@@ -83,7 +88,9 @@ namespace ts.refactor {
8388
case SyntaxKind.TypeAliasDeclaration:
8489
case SyntaxKind.ModuleDeclaration: {
8590
const node = exportNode as FunctionDeclaration | ClassDeclaration | InterfaceDeclaration | EnumDeclaration | TypeAliasDeclaration | NamespaceDeclaration;
86-
return node.name && isIdentifier(node.name) ? { exportNode: node, exportName: node.name, wasDefault, exportingModuleSymbol } : undefined;
91+
if (!node.name) return undefined;
92+
return noSymbolError(node.name)
93+
|| { exportNode: node, exportName: node.name, wasDefault, exportingModuleSymbol };
8794
}
8895
case SyntaxKind.VariableStatement: {
8996
const vs = exportNode as VariableStatement;
@@ -94,12 +101,14 @@ namespace ts.refactor {
94101
const decl = first(vs.declarationList.declarations);
95102
if (!decl.initializer) return undefined;
96103
Debug.assert(!wasDefault, "Can't have a default flag here");
97-
return isIdentifier(decl.name) ? { exportNode: vs, exportName: decl.name, wasDefault, exportingModuleSymbol } : undefined;
104+
return noSymbolError(decl.name)
105+
|| { exportNode: vs, exportName: decl.name as Identifier, wasDefault, exportingModuleSymbol };
98106
}
99107
case SyntaxKind.ExportAssignment: {
100108
const node = exportNode as ExportAssignment;
101-
const exp = node.expression as Identifier;
102-
return node.isExportEquals ? undefined : { exportNode: node, exportName: exp, wasDefault, exportingModuleSymbol };
109+
if (node.isExportEquals) return undefined;
110+
return noSymbolError(node.expression)
111+
|| { exportNode: node, exportName: node.expression as Identifier, wasDefault, exportingModuleSymbol };
103112
}
104113
default:
105114
return undefined;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @allowJs: true
4+
5+
// @Filename: /a.js
6+
/////*[| |]*/ /** x */ export default 1;
7+
8+
// @Filename: /b.js
9+
/////*[| |]*/ /** x */ export default (1);
10+
11+
// @Filename: /c.js
12+
/////*[| |]*/ /** x */ export default x;
13+
14+
goTo.eachRange(r => {
15+
goTo.selectRange(r);
16+
verify.not.refactorAvailable("Convert export");
17+
});
18+
19+
// goTo.selectRange(test.ranges()[0]);
20+
// edit.applyRefactor({
21+
// refactorName: "Convert export",
22+
// actionName: "Convert default export to named export",
23+
// actionDescription: "Convert default export to named export",
24+
// newContent: { "/a.js": `...` },
25+
// });

0 commit comments

Comments
 (0)