Skip to content

Commit 123ae53

Browse files
author
Andy
authored
convertToEs6Module: Replace 'module.exports =' with 'export default' without replacing nodes (microsoft#23948)
1 parent a50001c commit 123ae53

File tree

3 files changed

+40
-39
lines changed

3 files changed

+40
-39
lines changed

src/services/codefixes/convertToEs6Module.ts

+13-33
Original file line numberDiff line numberDiff line change
@@ -192,13 +192,17 @@ namespace ts.codefix {
192192
changes.deleteNode(sourceFile, assignment.parent);
193193
}
194194
else {
195-
let newNodes = isObjectLiteralExpression(right) ? tryChangeModuleExportsObject(right) : undefined;
196-
let changedToDefaultExport = false;
197-
if (!newNodes) {
198-
([newNodes, changedToDefaultExport] = convertModuleExportsToExportDefault(right, checker));
195+
const replacement = isObjectLiteralExpression(right) ? tryChangeModuleExportsObject(right)
196+
: isRequireCall(right, /*checkArgumentIsStringLiteralLike*/ true) ? convertReExportAll(right.arguments[0], checker)
197+
: undefined;
198+
if (replacement) {
199+
changes.replaceNodeWithNodes(sourceFile, assignment.parent, replacement[0]);
200+
return replacement[1];
201+
}
202+
else {
203+
changes.replaceRangeWithText(sourceFile, createTextRange(left.getStart(sourceFile), right.pos), "export default");
204+
return true;
199205
}
200-
changes.replaceNodeWithNodes(sourceFile, assignment.parent, newNodes);
201-
return changedToDefaultExport;
202206
}
203207
}
204208
else if (isExportsOrModuleExportsOrAlias(sourceFile, left.expression)) {
@@ -212,8 +216,8 @@ namespace ts.codefix {
212216
* Convert `module.exports = { ... }` to individual exports..
213217
* We can't always do this if the module has interesting members -- then it will be a default export instead.
214218
*/
215-
function tryChangeModuleExportsObject(object: ObjectLiteralExpression): ReadonlyArray<Statement> | undefined {
216-
return mapAllOrFail(object.properties, prop => {
219+
function tryChangeModuleExportsObject(object: ObjectLiteralExpression): [ReadonlyArray<Statement>, ModuleExportsChanged] | undefined {
220+
const statements = mapAllOrFail(object.properties, prop => {
217221
switch (prop.kind) {
218222
case SyntaxKind.GetAccessor:
219223
case SyntaxKind.SetAccessor:
@@ -229,6 +233,7 @@ namespace ts.codefix {
229233
Debug.assertNever(prop);
230234
}
231235
});
236+
return statements && [statements, true];
232237
}
233238

234239
function convertNamedExport(
@@ -256,31 +261,6 @@ namespace ts.codefix {
256261
}
257262
}
258263

259-
function convertModuleExportsToExportDefault(exported: Expression, checker: TypeChecker): [ReadonlyArray<Statement>, ModuleExportsChanged] {
260-
const modifiers = [createToken(SyntaxKind.ExportKeyword), createToken(SyntaxKind.DefaultKeyword)];
261-
switch (exported.kind) {
262-
case SyntaxKind.FunctionExpression:
263-
case SyntaxKind.ArrowFunction: {
264-
// `module.exports = function f() {}` --> `export default function f() {}`
265-
const fn = exported as FunctionExpression | ArrowFunction;
266-
return [[functionExpressionToDeclaration(fn.name && fn.name.text, modifiers, fn)], true];
267-
}
268-
case SyntaxKind.ClassExpression: {
269-
// `module.exports = class C {}` --> `export default class C {}`
270-
const cls = exported as ClassExpression;
271-
return [[classExpressionToDeclaration(cls.name && cls.name.text, modifiers, cls)], true];
272-
}
273-
case SyntaxKind.CallExpression:
274-
if (isRequireCall(exported, /*checkArgumentIsStringLiteralLike*/ true)) {
275-
return convertReExportAll(exported.arguments[0], checker);
276-
}
277-
// falls through
278-
default:
279-
// `module.exports = 0;` --> `export default 0;`
280-
return [[createExportAssignment(/*decorators*/ undefined, /*modifiers*/ undefined, /*isExportEquals*/ false, exported)], true];
281-
}
282-
}
283-
284264
function convertReExportAll(reExported: StringLiteralLike, checker: TypeChecker): [ReadonlyArray<Statement>, ModuleExportsChanged] {
285265
// `module.exports = require("x");` ==> `export * from "x"; export { default } from "x";`
286266
const moduleSpecifier = reExported.text;

tests/cases/fourslash/refactorConvertToEs6Module_export_moduleDotExports.ts

+4-6
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,9 @@
1515
verify.codeFix({
1616
description: "Convert to ES6 module",
1717
newFileContent:
18-
`export default function() { }
19-
export default function f() { }
20-
export default class {
21-
}
22-
export default class C {
23-
}
18+
`export default function() {}
19+
export default function f() {}
20+
export default class {}
21+
export default class C {}
2422
export default 0;`,
2523
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @allowJs: true
4+
// @target: esnext
5+
6+
// @Filename: /a.js
7+
////const b = require("./b");
8+
////module.exports = class C {
9+
//// m() {
10+
//// b.x;
11+
//// }
12+
////};
13+
14+
verify.codeFix({
15+
description: "Convert to ES6 module",
16+
newFileContent:
17+
`import { x } from "./b";
18+
export default class C {
19+
m() {
20+
x;
21+
}
22+
};`,
23+
});

0 commit comments

Comments
 (0)