From a8ee22f73dc25ef75b592143ab98b255c112b331 Mon Sep 17 00:00:00 2001 From: Sang <11912225+hantatsang@users.noreply.github.com> Date: Wed, 31 Mar 2021 09:24:31 +1100 Subject: [PATCH] "fix(services): convert to es6 module generate invalid code with .default" (#43309) --- src/services/codefixes/convertToEs6Module.ts | 28 +++++++++++++------ ...vertToEs6Module_import_es6DefaultImport.ts | 19 +++++++++++++ 2 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 tests/cases/fourslash/refactorConvertToEs6Module_import_es6DefaultImport.ts diff --git a/src/services/codefixes/convertToEs6Module.ts b/src/services/codefixes/convertToEs6Module.ts index 963f8923ee6..e15c507a4ef 100644 --- a/src/services/codefixes/convertToEs6Module.ts +++ b/src/services/codefixes/convertToEs6Module.ts @@ -436,7 +436,9 @@ namespace ts.codefix { /** * Convert `import x = require("x").` - * Also converts uses like `x.y()` to `y()` and uses a named import. + * Also: + * - Convert `x.default()` to `x()` to handle ES6 default export + * - Converts uses like `x.y()` to `y()` and uses a named import. */ function convertSingleIdentifierImport(name: Identifier, moduleSpecifier: StringLiteralLike, checker: TypeChecker, identifiers: Identifiers, quotePreference: QuotePreference): ConvertedImports { const nameSymbol = checker.getSymbolAtLocation(name); @@ -454,15 +456,23 @@ namespace ts.codefix { const { parent } = use; if (isPropertyAccessExpression(parent)) { - const { expression, name: { text: propertyName } } = parent; - Debug.assert(expression === use, "Didn't expect expression === use"); // Else shouldn't have been in `collectIdentifiers` - let idName = namedBindingsNames.get(propertyName); - if (idName === undefined) { - idName = makeUniqueName(propertyName, identifiers); - namedBindingsNames.set(propertyName, idName); - } + const { name: { text: propertyName } } = parent; + if (propertyName === "default") { + needDefaultImport = true; - (useSitesToUnqualify ??= new Map()).set(parent, factory.createIdentifier(idName)); + const importDefaultName = use.getText(); + (useSitesToUnqualify ??= new Map()).set(parent, factory.createIdentifier(importDefaultName)); + } + else { + Debug.assert(parent.expression === use, "Didn't expect expression === use"); // Else shouldn't have been in `collectIdentifiers` + let idName = namedBindingsNames.get(propertyName); + if (idName === undefined) { + idName = makeUniqueName(propertyName, identifiers); + namedBindingsNames.set(propertyName, idName); + } + + (useSitesToUnqualify ??= new Map()).set(parent, factory.createIdentifier(idName)); + } } else { needDefaultImport = true; diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_import_es6DefaultImport.ts b/tests/cases/fourslash/refactorConvertToEs6Module_import_es6DefaultImport.ts new file mode 100644 index 00000000000..9fe26a24010 --- /dev/null +++ b/tests/cases/fourslash/refactorConvertToEs6Module_import_es6DefaultImport.ts @@ -0,0 +1,19 @@ +/// + +// @allowJs: true +// @target: esnext + +// @Filename: /a.js +////const x = require('x'); +////x.default(); +////const y = require('y').default; +////y(); + +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: +`import x from 'x'; +x(); +import y from 'y'; +y();`, +});