diff --git a/src/services/codefixes/requireInTs.ts b/src/services/codefixes/requireInTs.ts index f087722dbb047..500a88aad8999 100644 --- a/src/services/codefixes/requireInTs.ts +++ b/src/services/codefixes/requireInTs.ts @@ -10,10 +10,12 @@ import { factory, first, getAllowSyntheticDefaultImports, + getQuotePreference, getTokenAtPosition, Identifier, ImportSpecifier, isIdentifier, + isNoSubstitutionTemplateLiteral, isObjectBindingPattern, isRequireCall, isVariableDeclaration, @@ -21,10 +23,12 @@ import { NamedImports, ObjectBindingPattern, Program, + QuotePreference, SourceFile, StringLiteralLike, textChanges, tryCast, + UserPreferences, VariableStatement, } from "../_namespaces/ts.js"; @@ -33,7 +37,7 @@ const errorCodes = [Diagnostics.require_call_may_be_converted_to_an_import.code] registerCodeFix({ errorCodes, getCodeActions(context) { - const info = getInfo(context.sourceFile, context.program, context.span.start); + const info = getInfo(context.sourceFile, context.program, context.span.start, context.preferences); if (!info) { return undefined; } @@ -43,7 +47,7 @@ registerCodeFix({ fixIds: [fixId], getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { - const info = getInfo(diag.file, context.program, diag.start); + const info = getInfo(diag.file, context.program, diag.start, context.preferences); if (info) { doChange(changes, context.sourceFile, info); } @@ -51,13 +55,13 @@ registerCodeFix({ }); function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, info: Info) { - const { allowSyntheticDefaults, defaultImportName, namedImports, statement, required } = info; + const { allowSyntheticDefaults, defaultImportName, namedImports, statement, moduleSpecifier } = info; changes.replaceNode( sourceFile, statement, defaultImportName && !allowSyntheticDefaults - ? factory.createImportEqualsDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, defaultImportName, factory.createExternalModuleReference(required)) - : factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, defaultImportName, namedImports), required, /*attributes*/ undefined), + ? factory.createImportEqualsDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, defaultImportName, factory.createExternalModuleReference(moduleSpecifier)) + : factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, defaultImportName, namedImports), moduleSpecifier, /*attributes*/ undefined), ); } @@ -66,25 +70,27 @@ interface Info { readonly defaultImportName: Identifier | undefined; readonly namedImports: NamedImports | undefined; readonly statement: VariableStatement; - readonly required: StringLiteralLike; + readonly moduleSpecifier: StringLiteralLike; } -function getInfo(sourceFile: SourceFile, program: Program, pos: number): Info | undefined { +function getInfo(sourceFile: SourceFile, program: Program, pos: number, preferences: UserPreferences): Info | undefined { const { parent } = getTokenAtPosition(sourceFile, pos); if (!isRequireCall(parent, /*requireStringLiteralLikeArgument*/ true)) { Debug.failBadSyntaxKind(parent); } const decl = cast(parent.parent, isVariableDeclaration); + const quotePreference = getQuotePreference(sourceFile, preferences); const defaultImportName = tryCast(decl.name, isIdentifier); const namedImports = isObjectBindingPattern(decl.name) ? tryCreateNamedImportsFromObjectBindingPattern(decl.name) : undefined; if (defaultImportName || namedImports) { + const moduleSpecifier = first(parent.arguments); return { allowSyntheticDefaults: getAllowSyntheticDefaultImports(program.getCompilerOptions()), defaultImportName, namedImports, statement: cast(decl.parent.parent, isVariableStatement), - required: first(parent.arguments), + moduleSpecifier: isNoSubstitutionTemplateLiteral(moduleSpecifier) ? factory.createStringLiteral(moduleSpecifier.text, quotePreference === QuotePreference.Single) : moduleSpecifier, }; } } diff --git a/tests/cases/fourslash/codeFixRequireInTs4.ts b/tests/cases/fourslash/codeFixRequireInTs4.ts new file mode 100644 index 0000000000000..85a7ccb2a3c47 --- /dev/null +++ b/tests/cases/fourslash/codeFixRequireInTs4.ts @@ -0,0 +1,10 @@ +/// + +// @Filename: /a.ts +////const foo = require(`foo`); + +verify.codeFix({ + description: ts.Diagnostics.Convert_require_to_import.message, + newFileContent: 'import foo = require("foo");', +}); + diff --git a/tests/cases/fourslash/codeFixRequireInTs5.ts b/tests/cases/fourslash/codeFixRequireInTs5.ts new file mode 100644 index 0000000000000..8a45cf9a1ecae --- /dev/null +++ b/tests/cases/fourslash/codeFixRequireInTs5.ts @@ -0,0 +1,8 @@ +/// + +// @Filename: /a.ts +////const a = 1; +////const b = 2; +////const foo = require(`foo${a}${b}`); + +verify.not.codeFixAvailable();