fix(38081): allow transforming object binding to named imports
This commit is contained in:
parent
1d1c1673bf
commit
bc502c8c3c
|
@ -5,25 +5,68 @@ namespace ts.codefix {
|
||||||
registerCodeFix({
|
registerCodeFix({
|
||||||
errorCodes,
|
errorCodes,
|
||||||
getCodeActions(context) {
|
getCodeActions(context) {
|
||||||
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, context.span.start, context.program));
|
const info = getInfo(context.sourceFile, context.program, context.span.start);
|
||||||
|
if (!info) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, info));
|
||||||
return [createCodeFixAction(fixId, changes, Diagnostics.Convert_require_to_import, fixId, Diagnostics.Convert_all_require_to_import)];
|
return [createCodeFixAction(fixId, changes, Diagnostics.Convert_require_to_import, fixId, Diagnostics.Convert_all_require_to_import)];
|
||||||
},
|
},
|
||||||
fixIds: [fixId],
|
fixIds: [fixId],
|
||||||
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => doChange(changes, diag.file, diag.start, context.program)),
|
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => {
|
||||||
|
const info = getInfo(diag.file, context.program, diag.start);
|
||||||
|
if (info) {
|
||||||
|
doChange(changes, context.sourceFile, info);
|
||||||
|
}
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number, program: Program) {
|
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, info: Info) {
|
||||||
const { statement, name, required } = getInfo(sourceFile, pos);
|
const { allowSyntheticDefaults, defaultImportName, namedImports, statement, required } = info;
|
||||||
changes.replaceNode(sourceFile, statement, getAllowSyntheticDefaultImports(program.getCompilerOptions())
|
changes.replaceNode(sourceFile, statement, defaultImportName && !allowSyntheticDefaults
|
||||||
? createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createImportClause(name, /*namedBindings*/ undefined), required)
|
? createImportEqualsDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, defaultImportName, createExternalModuleReference(required))
|
||||||
: createImportEqualsDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, name, createExternalModuleReference(required)));
|
: createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createImportClause(defaultImportName, namedImports), required));
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Info { readonly statement: VariableStatement; readonly name: Identifier; readonly required: StringLiteralLike; }
|
interface Info {
|
||||||
function getInfo(sourceFile: SourceFile, pos: number): Info {
|
readonly allowSyntheticDefaults: boolean;
|
||||||
|
readonly defaultImportName: Identifier | undefined;
|
||||||
|
readonly namedImports: NamedImports | undefined;
|
||||||
|
readonly statement: VariableStatement;
|
||||||
|
readonly required: StringLiteralLike;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInfo(sourceFile: SourceFile, program: Program, pos: number): Info | undefined {
|
||||||
const { parent } = getTokenAtPosition(sourceFile, pos);
|
const { parent } = getTokenAtPosition(sourceFile, pos);
|
||||||
if (!isRequireCall(parent, /*checkArgumentIsStringLiteralLike*/ true)) throw Debug.failBadSyntaxKind(parent);
|
if (!isRequireCall(parent, /*checkArgumentIsStringLiteralLike*/ true)) {
|
||||||
|
throw Debug.failBadSyntaxKind(parent);
|
||||||
|
}
|
||||||
|
|
||||||
const decl = cast(parent.parent, isVariableDeclaration);
|
const decl = cast(parent.parent, isVariableDeclaration);
|
||||||
return { statement: cast(decl.parent.parent, isVariableStatement), name: cast(decl.name, isIdentifier), required: parent.arguments[0] };
|
const defaultImportName = tryCast(decl.name, isIdentifier);
|
||||||
|
const namedImports = isObjectBindingPattern(decl.name) ? tryCreateNamedImportsFromObjectBindingPattern(decl.name) : undefined;
|
||||||
|
if (defaultImportName || namedImports) {
|
||||||
|
return {
|
||||||
|
allowSyntheticDefaults: getAllowSyntheticDefaultImports(program.getCompilerOptions()),
|
||||||
|
defaultImportName,
|
||||||
|
namedImports,
|
||||||
|
statement: cast(decl.parent.parent, isVariableStatement),
|
||||||
|
required: first(parent.arguments)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function tryCreateNamedImportsFromObjectBindingPattern(node: ObjectBindingPattern): NamedImports | undefined {
|
||||||
|
const importSpecifiers: ImportSpecifier[] = [];
|
||||||
|
for (const element of node.elements) {
|
||||||
|
if (!isIdentifier(element.name) || element.initializer) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
importSpecifiers.push(createImportSpecifier(tryCast(element.propertyName, isIdentifier), element.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (importSpecifiers.length) {
|
||||||
|
return createNamedImports(importSpecifiers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ verify.getSuggestionDiagnostics([{
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
verify.codeFix({
|
verify.codeFix({
|
||||||
description: "Convert 'require' to 'import'",
|
description: ts.Diagnostics.Convert_require_to_import.message,
|
||||||
newFileContent:
|
newFileContent: 'import a = require("a");',
|
||||||
`import a = require("a");`,
|
|
||||||
});
|
});
|
9
tests/cases/fourslash/codeFixRequireInTs2.ts
Normal file
9
tests/cases/fourslash/codeFixRequireInTs2.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/// <reference path='fourslash.ts' />
|
||||||
|
|
||||||
|
// @Filename: /a.ts
|
||||||
|
////const { a, b, c } = [|require("a")|];
|
||||||
|
|
||||||
|
verify.codeFix({
|
||||||
|
description: ts.Diagnostics.Convert_require_to_import.message,
|
||||||
|
newFileContent: 'import { a, b, c } from "a";',
|
||||||
|
});
|
6
tests/cases/fourslash/codeFixRequireInTs3.ts
Normal file
6
tests/cases/fourslash/codeFixRequireInTs3.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
/// <reference path='fourslash.ts' />
|
||||||
|
|
||||||
|
// @Filename: /a.ts
|
||||||
|
////const { a, b: { c } } = [|require("a")|];
|
||||||
|
|
||||||
|
verify.not.codeFixAvailable();
|
|
@ -3,11 +3,15 @@
|
||||||
// @Filename: /a.ts
|
// @Filename: /a.ts
|
||||||
////const a = [|require("a")|];
|
////const a = [|require("a")|];
|
||||||
////const b = [|require("b")|];
|
////const b = [|require("b")|];
|
||||||
|
////const { c } = [|require("c")|];
|
||||||
|
////const { d } = [|require("d")|];
|
||||||
|
|
||||||
verify.codeFixAll({
|
verify.codeFixAll({
|
||||||
fixId: "requireInTs",
|
fixId: "requireInTs",
|
||||||
fixAllDescription: "Convert all 'require' to 'import'",
|
fixAllDescription: ts.Diagnostics.Convert_all_require_to_import.message,
|
||||||
newFileContent:
|
newFileContent:
|
||||||
`import a = require("a");
|
`import a = require("a");
|
||||||
import b = require("b");`,
|
import b = require("b");
|
||||||
|
import { c } from "c";
|
||||||
|
import { d } from "d";`,
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
/// <reference path='fourslash.ts' />
|
/// <reference path='fourslash.ts' />
|
||||||
|
|
||||||
// @allowSyntheticDefaultImports: true
|
// @allowSyntheticDefaultImports: true
|
||||||
|
|
||||||
// @Filename: /a.ts
|
// @Filename: /a.ts
|
||||||
////const a = [|require("a")|];
|
////const a = [|require("a")|];
|
||||||
|
|
||||||
verify.codeFix({
|
verify.codeFix({
|
||||||
description: "Convert 'require' to 'import'",
|
description: ts.Diagnostics.Convert_require_to_import.message,
|
||||||
newFileContent: `import a from "a";`,
|
newFileContent: 'import a from "a";',
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
/// <reference path='fourslash.ts' />
|
||||||
|
|
||||||
|
// @allowSyntheticDefaultImports: true
|
||||||
|
// @Filename: /a.ts
|
||||||
|
////const a = [|require("a")|];
|
||||||
|
////const b = [|require("b")|];
|
||||||
|
////const { c } = [|require("c")|];
|
||||||
|
////const { d } = [|require("d")|];
|
||||||
|
|
||||||
|
verify.codeFixAll({
|
||||||
|
fixId: "requireInTs",
|
||||||
|
fixAllDescription: ts.Diagnostics.Convert_all_require_to_import.message,
|
||||||
|
newFileContent:
|
||||||
|
`import a from "a";
|
||||||
|
import b from "b";
|
||||||
|
import { c } from "c";
|
||||||
|
import { d } from "d";`,
|
||||||
|
});
|
Loading…
Reference in a new issue