Skip to content

Commit bf39ecc

Browse files
authored
fix(59304): Convert to ESM uses template strings instead of string literals (microsoft#59306)
1 parent 66a762f commit bf39ecc

File tree

3 files changed

+32
-8
lines changed

3 files changed

+32
-8
lines changed

src/services/codefixes/requireInTs.ts

+14-8
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,25 @@ import {
1010
factory,
1111
first,
1212
getAllowSyntheticDefaultImports,
13+
getQuotePreference,
1314
getTokenAtPosition,
1415
Identifier,
1516
ImportSpecifier,
1617
isIdentifier,
18+
isNoSubstitutionTemplateLiteral,
1719
isObjectBindingPattern,
1820
isRequireCall,
1921
isVariableDeclaration,
2022
isVariableStatement,
2123
NamedImports,
2224
ObjectBindingPattern,
2325
Program,
26+
QuotePreference,
2427
SourceFile,
2528
StringLiteralLike,
2629
textChanges,
2730
tryCast,
31+
UserPreferences,
2832
VariableStatement,
2933
} from "../_namespaces/ts.js";
3034

@@ -33,7 +37,7 @@ const errorCodes = [Diagnostics.require_call_may_be_converted_to_an_import.code]
3337
registerCodeFix({
3438
errorCodes,
3539
getCodeActions(context) {
36-
const info = getInfo(context.sourceFile, context.program, context.span.start);
40+
const info = getInfo(context.sourceFile, context.program, context.span.start, context.preferences);
3741
if (!info) {
3842
return undefined;
3943
}
@@ -43,21 +47,21 @@ registerCodeFix({
4347
fixIds: [fixId],
4448
getAllCodeActions: context =>
4549
codeFixAll(context, errorCodes, (changes, diag) => {
46-
const info = getInfo(diag.file, context.program, diag.start);
50+
const info = getInfo(diag.file, context.program, diag.start, context.preferences);
4751
if (info) {
4852
doChange(changes, context.sourceFile, info);
4953
}
5054
}),
5155
});
5256

5357
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, info: Info) {
54-
const { allowSyntheticDefaults, defaultImportName, namedImports, statement, required } = info;
58+
const { allowSyntheticDefaults, defaultImportName, namedImports, statement, moduleSpecifier } = info;
5559
changes.replaceNode(
5660
sourceFile,
5761
statement,
5862
defaultImportName && !allowSyntheticDefaults
59-
? factory.createImportEqualsDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, defaultImportName, factory.createExternalModuleReference(required))
60-
: factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, defaultImportName, namedImports), required, /*attributes*/ undefined),
63+
? factory.createImportEqualsDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, defaultImportName, factory.createExternalModuleReference(moduleSpecifier))
64+
: factory.createImportDeclaration(/*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, defaultImportName, namedImports), moduleSpecifier, /*attributes*/ undefined),
6165
);
6266
}
6367

@@ -66,25 +70,27 @@ interface Info {
6670
readonly defaultImportName: Identifier | undefined;
6771
readonly namedImports: NamedImports | undefined;
6872
readonly statement: VariableStatement;
69-
readonly required: StringLiteralLike;
73+
readonly moduleSpecifier: StringLiteralLike;
7074
}
7175

72-
function getInfo(sourceFile: SourceFile, program: Program, pos: number): Info | undefined {
76+
function getInfo(sourceFile: SourceFile, program: Program, pos: number, preferences: UserPreferences): Info | undefined {
7377
const { parent } = getTokenAtPosition(sourceFile, pos);
7478
if (!isRequireCall(parent, /*requireStringLiteralLikeArgument*/ true)) {
7579
Debug.failBadSyntaxKind(parent);
7680
}
7781

7882
const decl = cast(parent.parent, isVariableDeclaration);
83+
const quotePreference = getQuotePreference(sourceFile, preferences);
7984
const defaultImportName = tryCast(decl.name, isIdentifier);
8085
const namedImports = isObjectBindingPattern(decl.name) ? tryCreateNamedImportsFromObjectBindingPattern(decl.name) : undefined;
8186
if (defaultImportName || namedImports) {
87+
const moduleSpecifier = first(parent.arguments);
8288
return {
8389
allowSyntheticDefaults: getAllowSyntheticDefaultImports(program.getCompilerOptions()),
8490
defaultImportName,
8591
namedImports,
8692
statement: cast(decl.parent.parent, isVariableStatement),
87-
required: first(parent.arguments),
93+
moduleSpecifier: isNoSubstitutionTemplateLiteral(moduleSpecifier) ? factory.createStringLiteral(moduleSpecifier.text, quotePreference === QuotePreference.Single) : moduleSpecifier,
8894
};
8995
}
9096
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @Filename: /a.ts
4+
////const foo = require(`foo`);
5+
6+
verify.codeFix({
7+
description: ts.Diagnostics.Convert_require_to_import.message,
8+
newFileContent: 'import foo = require("foo");',
9+
});
10+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @Filename: /a.ts
4+
////const a = 1;
5+
////const b = 2;
6+
////const foo = require(`foo${a}${b}`);
7+
8+
verify.not.codeFixAvailable();

0 commit comments

Comments
 (0)