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
This commit is contained in:
Aluan Haddad 2017-11-07 12:45:30 -05:00 committed by Mohamed Hegazy
parent bd2e97597d
commit b2b54cbf5c
9 changed files with 92 additions and 6 deletions

View File

@ -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 });

View File

@ -1,5 +1,6 @@
/// <reference path="fourslash.ts" />
// @AllowSyntheticDefaultImports: false
// @Module: system
// @Filename: a/f1.ts
//// [|export var x = 0;

View File

@ -0,0 +1,19 @@
/// <reference path="fourslash.ts" />
// @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();`
]);

View File

@ -0,0 +1,19 @@
/// <reference path="fourslash.ts" />
// @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();`
]);

View File

@ -0,0 +1,19 @@
/// <reference path="fourslash.ts" />
// @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();`
]);

View File

@ -1,5 +1,8 @@
/// <reference path="fourslash.ts" />
// @AllowSyntheticDefaultImports: false
// @Module: es2015
// @Filename: a/f1.ts
//// [|export function test() { };
//// bar1/*0*/.bar;|]

View File

@ -1,5 +1,8 @@
/// <reference path="fourslash.ts" />
// @AllowSyntheticDefaultImports: false
// @Module: esnext
// @Filename: a/f1.ts
//// [|import { bar } from "./foo";
////

View File

@ -1,6 +1,8 @@
/// <reference path="fourslash.ts" />
// @jsx: react
// @allowSyntheticDefaultImports: false
// @module: es2015
// @Filename: /node_modules/@types/react/index.d.ts
////export = React;

View File

@ -1,6 +1,8 @@
/// <reference path="fourslash.ts" />
// @jsx: react
// @allowSyntheticDefaultImports: false
// @module: es2015
// @Filename: /node_modules/@types/react/index.d.ts
////export = React;