From b2b54cbf5c41397135a2642510fa4af12af95fd4 Mon Sep 17 00:00:00 2001 From: Aluan Haddad Date: Tue, 7 Nov 2017 12:45:30 -0500 Subject: [PATCH] Import fix add import require support (#19802) * import fix: suggest import..require where supported if synthetic defaults are unavailable * Add tests for import..require fix when targeting CommonJS, AMD, and UMD modules * fix failing tests --- src/services/codefixes/importFixes.ts | 30 +++++++++++++++---- ...xNewImportAllowSyntheticDefaultImports2.ts | 1 + ...xNewImportAllowSyntheticDefaultImports3.ts | 19 ++++++++++++ ...xNewImportAllowSyntheticDefaultImports4.ts | 19 ++++++++++++ ...xNewImportAllowSyntheticDefaultImports5.ts | 19 ++++++++++++ .../fourslash/importNameCodeFixUMDGlobal0.ts | 3 ++ .../fourslash/importNameCodeFixUMDGlobal1.ts | 3 ++ .../importNameCodeFixUMDGlobalReact0.ts | 2 ++ .../importNameCodeFixUMDGlobalReact1.ts | 2 ++ 9 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 tests/cases/fourslash/importNameCodeFixNewImportAllowSyntheticDefaultImports3.ts create mode 100644 tests/cases/fourslash/importNameCodeFixNewImportAllowSyntheticDefaultImports4.ts create mode 100644 tests/cases/fourslash/importNameCodeFixNewImportAllowSyntheticDefaultImports5.ts diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index a7f0e2e0814..e0e57801cf8 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -180,7 +180,8 @@ namespace ts.codefix { export const enum ImportKind { Named, Default, - Namespace + Namespace, + Equals } export function getCodeActionForImport(moduleSymbol: Symbol, context: ImportCodeFixOptions): ImportCodeAction[] { @@ -252,11 +253,17 @@ namespace ts.codefix { const moduleSpecifierWithoutQuotes = stripQuotes(moduleSpecifier); const quotedModuleSpecifier = createStringLiteralWithQuoteStyle(sourceFile, moduleSpecifierWithoutQuotes); - const importDecl = createImportDeclaration( + const importDecl = kind !== ImportKind.Equals + ? createImportDeclaration( /*decorators*/ undefined, /*modifiers*/ undefined, - createImportClauseOfKind(kind, symbolName), - quotedModuleSpecifier); + createImportClauseOfKind(kind, symbolName), + quotedModuleSpecifier) + : createImportEqualsDeclaration( + /*decorators*/ undefined, + /*modifiers*/ undefined, + createIdentifier(symbolName), + createExternalModuleReference(quotedModuleSpecifier)); const changes = ChangeTracker.with(context, changeTracker => { if (lastImportDeclaration) { @@ -267,8 +274,10 @@ namespace ts.codefix { } }); - const actionFormat = kind === ImportKind.Namespace - ? Diagnostics.Import_Asterisk_as_0_from_1 + const actionFormat = kind === ImportKind.Equals + ? Diagnostics.Import_0_require_1 + : kind === ImportKind.Namespace + ? Diagnostics.Import_Asterisk_as_0_from_1 : Diagnostics.Import_0_from_1; // if this file doesn't have any import statements, insert an import statement and then insert a new line @@ -601,6 +610,9 @@ namespace ts.codefix { return namedBindings ? undefined : ChangeTracker.with(context, t => t.replaceNode(sourceFile, importClause, createImportClause(name, createNamespaceImport(createIdentifier(symbolName))))); + case ImportKind.Equals: + return undefined; + default: Debug.assertNever(kind); } @@ -659,6 +671,12 @@ namespace ts.codefix { if (allowSyntheticDefaultImports) { return getCodeActionForImport(symbol, { ...context, symbolName, kind: ImportKind.Default }); } + const moduleKind = getEmitModuleKind(compilerOptions); + + // When a synthetic `default` is unavailable, use `import..require` if the module kind supports it. + if (moduleKind === ModuleKind.AMD || moduleKind === ModuleKind.CommonJS || moduleKind === ModuleKind.UMD) { + return getCodeActionForImport(symbol, { ...context, symbolName, kind: ImportKind.Equals }); + } // Fall back to the `import * as ns` style import. return getCodeActionForImport(symbol, { ...context, symbolName, kind: ImportKind.Namespace }); diff --git a/tests/cases/fourslash/importNameCodeFixNewImportAllowSyntheticDefaultImports2.ts b/tests/cases/fourslash/importNameCodeFixNewImportAllowSyntheticDefaultImports2.ts index 3421d603297..f6ba985715e 100644 --- a/tests/cases/fourslash/importNameCodeFixNewImportAllowSyntheticDefaultImports2.ts +++ b/tests/cases/fourslash/importNameCodeFixNewImportAllowSyntheticDefaultImports2.ts @@ -1,5 +1,6 @@ /// // @AllowSyntheticDefaultImports: false +// @Module: system // @Filename: a/f1.ts //// [|export var x = 0; diff --git a/tests/cases/fourslash/importNameCodeFixNewImportAllowSyntheticDefaultImports3.ts b/tests/cases/fourslash/importNameCodeFixNewImportAllowSyntheticDefaultImports3.ts new file mode 100644 index 00000000000..bc0ba6d8163 --- /dev/null +++ b/tests/cases/fourslash/importNameCodeFixNewImportAllowSyntheticDefaultImports3.ts @@ -0,0 +1,19 @@ +/// +// @AllowSyntheticDefaultImports: false +// @Module: commonjs + +// @Filename: a/f1.ts +//// [|export var x = 0; +//// bar/*0*/();|] + +// @Filename: a/foo.d.ts +//// declare function bar(): number; +//// export = bar; +//// export as namespace bar; + +verify.importFixAtPosition([ +`import bar = require("./foo"); + +export var x = 0; +bar();` +]); \ No newline at end of file diff --git a/tests/cases/fourslash/importNameCodeFixNewImportAllowSyntheticDefaultImports4.ts b/tests/cases/fourslash/importNameCodeFixNewImportAllowSyntheticDefaultImports4.ts new file mode 100644 index 00000000000..c8ce87db71a --- /dev/null +++ b/tests/cases/fourslash/importNameCodeFixNewImportAllowSyntheticDefaultImports4.ts @@ -0,0 +1,19 @@ +/// +// @AllowSyntheticDefaultImports: false +// @Module: amd + +// @Filename: a/f1.ts +//// [|export var x = 0; +//// bar/*0*/();|] + +// @Filename: a/foo.d.ts +//// declare function bar(): number; +//// export = bar; +//// export as namespace bar; + +verify.importFixAtPosition([ +`import bar = require("./foo"); + +export var x = 0; +bar();` +]); \ No newline at end of file diff --git a/tests/cases/fourslash/importNameCodeFixNewImportAllowSyntheticDefaultImports5.ts b/tests/cases/fourslash/importNameCodeFixNewImportAllowSyntheticDefaultImports5.ts new file mode 100644 index 00000000000..7830faaacc8 --- /dev/null +++ b/tests/cases/fourslash/importNameCodeFixNewImportAllowSyntheticDefaultImports5.ts @@ -0,0 +1,19 @@ +/// +// @AllowSyntheticDefaultImports: false +// @Module: umd + +// @Filename: a/f1.ts +//// [|export var x = 0; +//// bar/*0*/();|] + +// @Filename: a/foo.d.ts +//// declare function bar(): number; +//// export = bar; +//// export as namespace bar; + +verify.importFixAtPosition([ +`import bar = require("./foo"); + +export var x = 0; +bar();` +]); \ No newline at end of file diff --git a/tests/cases/fourslash/importNameCodeFixUMDGlobal0.ts b/tests/cases/fourslash/importNameCodeFixUMDGlobal0.ts index 3c780dc0af6..3208a41bba1 100644 --- a/tests/cases/fourslash/importNameCodeFixUMDGlobal0.ts +++ b/tests/cases/fourslash/importNameCodeFixUMDGlobal0.ts @@ -1,5 +1,8 @@ /// +// @AllowSyntheticDefaultImports: false +// @Module: es2015 + // @Filename: a/f1.ts //// [|export function test() { }; //// bar1/*0*/.bar;|] diff --git a/tests/cases/fourslash/importNameCodeFixUMDGlobal1.ts b/tests/cases/fourslash/importNameCodeFixUMDGlobal1.ts index 96671ad6f91..1beebb0477c 100644 --- a/tests/cases/fourslash/importNameCodeFixUMDGlobal1.ts +++ b/tests/cases/fourslash/importNameCodeFixUMDGlobal1.ts @@ -1,5 +1,8 @@ /// +// @AllowSyntheticDefaultImports: false +// @Module: esnext + // @Filename: a/f1.ts //// [|import { bar } from "./foo"; //// diff --git a/tests/cases/fourslash/importNameCodeFixUMDGlobalReact0.ts b/tests/cases/fourslash/importNameCodeFixUMDGlobalReact0.ts index 260c34d10a6..5b6df7a5173 100644 --- a/tests/cases/fourslash/importNameCodeFixUMDGlobalReact0.ts +++ b/tests/cases/fourslash/importNameCodeFixUMDGlobalReact0.ts @@ -1,6 +1,8 @@ /// // @jsx: react +// @allowSyntheticDefaultImports: false +// @module: es2015 // @Filename: /node_modules/@types/react/index.d.ts ////export = React; diff --git a/tests/cases/fourslash/importNameCodeFixUMDGlobalReact1.ts b/tests/cases/fourslash/importNameCodeFixUMDGlobalReact1.ts index ccd69c50199..669db55342b 100644 --- a/tests/cases/fourslash/importNameCodeFixUMDGlobalReact1.ts +++ b/tests/cases/fourslash/importNameCodeFixUMDGlobalReact1.ts @@ -1,6 +1,8 @@ /// // @jsx: react +// @allowSyntheticDefaultImports: false +// @module: es2015 // @Filename: /node_modules/@types/react/index.d.ts ////export = React;