-
Notifications
You must be signed in to change notification settings - Fork 12.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix error message for type-only import of ES module from CJS (#59711)
- Loading branch information
1 parent
3abe069
commit a86b5e2
Showing
12 changed files
with
284 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 109 additions & 0 deletions
109
src/services/codefixes/addMissingResolutionModeImportAttribute.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import { | ||
codeFixAll, | ||
createCodeFixAction, | ||
registerCodeFix, | ||
} from "../_namespaces/ts.codefix.js"; | ||
import { | ||
Debug, | ||
Diagnostics, | ||
factory, | ||
findAncestor, | ||
getQuotePreference, | ||
getTokenAtPosition, | ||
isImportDeclaration, | ||
isImportTypeNode, | ||
LanguageServiceHost, | ||
ModuleKind, | ||
or, | ||
Program, | ||
QuotePreference, | ||
resolveModuleName, | ||
SourceFile, | ||
SyntaxKind, | ||
textChanges, | ||
tryGetModuleSpecifierFromDeclaration, | ||
UserPreferences, | ||
} from "../_namespaces/ts.js"; | ||
|
||
const fixId = "addMissingResolutionModeImportAttribute"; | ||
const errorCodes = [ | ||
Diagnostics.Type_only_import_of_an_ECMAScript_module_from_a_CommonJS_module_must_have_a_resolution_mode_attribute.code, | ||
Diagnostics.Type_import_of_an_ECMAScript_module_from_a_CommonJS_module_must_have_a_resolution_mode_attribute.code, | ||
]; | ||
|
||
registerCodeFix({ | ||
errorCodes, | ||
getCodeActions: function getCodeActionsToAddMissingResolutionModeImportAttribute(context) { | ||
const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span.start, context.program, context.host, context.preferences)); | ||
return [createCodeFixAction(fixId, changes, Diagnostics.Add_resolution_mode_import_attribute, fixId, Diagnostics.Add_resolution_mode_import_attribute_to_all_type_only_imports_that_need_it)]; | ||
}, | ||
fixIds: [fixId], | ||
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file, diag.start, context.program, context.host, context.preferences)), | ||
}); | ||
|
||
function makeChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number, program: Program, host: LanguageServiceHost, preferences: UserPreferences) { | ||
const token = getTokenAtPosition(sourceFile, pos); | ||
const importNode = findAncestor(token, or(isImportDeclaration, isImportTypeNode))!; | ||
Debug.assert(!!importNode, "Expected position to be owned by an ImportDeclaration or ImportType."); | ||
const useSingleQuotes = getQuotePreference(sourceFile, preferences) === QuotePreference.Single; | ||
const moduleSpecifier = tryGetModuleSpecifierFromDeclaration(importNode); | ||
const canUseImportMode = !moduleSpecifier || (resolveModuleName( | ||
moduleSpecifier.text, | ||
sourceFile.fileName, | ||
program.getCompilerOptions(), | ||
host, | ||
program.getModuleResolutionCache(), | ||
/*redirectedReference*/ undefined, | ||
ModuleKind.ESNext, | ||
).resolvedModule?.resolvedFileName === program.getResolvedModuleFromModuleSpecifier( | ||
moduleSpecifier, | ||
sourceFile, | ||
)?.resolvedModule?.resolvedFileName); | ||
|
||
const attributes = importNode.attributes | ||
? factory.updateImportAttributes( | ||
importNode.attributes, | ||
factory.createNodeArray([ | ||
...importNode.attributes.elements, | ||
factory.createImportAttribute( | ||
factory.createStringLiteral("resolution-mode", useSingleQuotes), | ||
factory.createStringLiteral(canUseImportMode ? "import" : "require", useSingleQuotes), | ||
), | ||
], importNode.attributes.elements.hasTrailingComma), | ||
importNode.attributes.multiLine, | ||
) | ||
: factory.createImportAttributes( | ||
factory.createNodeArray([ | ||
factory.createImportAttribute( | ||
factory.createStringLiteral("resolution-mode", useSingleQuotes), | ||
factory.createStringLiteral(canUseImportMode ? "import" : "require", useSingleQuotes), | ||
), | ||
]), | ||
); | ||
if (importNode.kind === SyntaxKind.ImportDeclaration) { | ||
changeTracker.replaceNode( | ||
sourceFile, | ||
importNode, | ||
factory.updateImportDeclaration( | ||
importNode, | ||
importNode.modifiers, | ||
importNode.importClause, | ||
importNode.moduleSpecifier, | ||
attributes, | ||
), | ||
); | ||
} | ||
else { | ||
changeTracker.replaceNode( | ||
sourceFile, | ||
importNode, | ||
factory.updateImportTypeNode( | ||
importNode, | ||
importNode.argument, | ||
attributes, | ||
importNode.qualifier, | ||
importNode.typeArguments, | ||
), | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
tests/baselines/reference/typeOnlyESMImportFromCJS.errors.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
common.cts(1,21): error TS1541: Type-only import of an ECMAScript module from a CommonJS module must have a 'resolution-mode' attribute. | ||
common.cts(4,25): error TS1542: Type import of an ECMAScript module from a CommonJS module must have a 'resolution-mode' attribute. | ||
|
||
|
||
==== module.mts (0 errors) ==== | ||
export {}; | ||
|
||
==== common.cts (2 errors) ==== | ||
import type {} from "./module.mts"; | ||
~~~~~~~~~~~~~~ | ||
!!! error TS1541: Type-only import of an ECMAScript module from a CommonJS module must have a 'resolution-mode' attribute. | ||
import type {} from "./module.mts" with { "resolution-mode": "import" }; | ||
import type {} from "./module.mts" with { "resolution-mode": "require" }; | ||
type _1 = typeof import("./module.mts"); | ||
~~~~~~~~~~~~~~ | ||
!!! error TS1542: Type import of an ECMAScript module from a CommonJS module must have a 'resolution-mode' attribute. | ||
type _2 = typeof import("./module.mts", { with: { "resolution-mode": "import" } }); | ||
type _3 = typeof import("./module.mts", { with: { "resolution-mode": "require" } }); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
//// [tests/cases/conformance/externalModules/typeOnly/typeOnlyESMImportFromCJS.ts] //// | ||
|
||
//// [module.mts] | ||
export {}; | ||
|
||
//// [common.cts] | ||
import type {} from "./module.mts"; | ||
import type {} from "./module.mts" with { "resolution-mode": "import" }; | ||
import type {} from "./module.mts" with { "resolution-mode": "require" }; | ||
type _1 = typeof import("./module.mts"); | ||
type _2 = typeof import("./module.mts", { with: { "resolution-mode": "import" } }); | ||
type _3 = typeof import("./module.mts", { with: { "resolution-mode": "require" } }); | ||
|
||
|
||
//// [module.mjs] | ||
export {}; | ||
//// [common.cjs] | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); |
19 changes: 19 additions & 0 deletions
19
tests/baselines/reference/typeOnlyESMImportFromCJS.symbols
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
//// [tests/cases/conformance/externalModules/typeOnly/typeOnlyESMImportFromCJS.ts] //// | ||
|
||
=== module.mts === | ||
|
||
export {}; | ||
|
||
=== common.cts === | ||
import type {} from "./module.mts"; | ||
import type {} from "./module.mts" with { "resolution-mode": "import" }; | ||
import type {} from "./module.mts" with { "resolution-mode": "require" }; | ||
type _1 = typeof import("./module.mts"); | ||
>_1 : Symbol(_1, Decl(common.cts, 2, 73)) | ||
|
||
type _2 = typeof import("./module.mts", { with: { "resolution-mode": "import" } }); | ||
>_2 : Symbol(_2, Decl(common.cts, 3, 40)) | ||
|
||
type _3 = typeof import("./module.mts", { with: { "resolution-mode": "require" } }); | ||
>_3 : Symbol(_3, Decl(common.cts, 4, 83)) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
//// [tests/cases/conformance/externalModules/typeOnly/typeOnlyESMImportFromCJS.ts] //// | ||
|
||
=== module.mts === | ||
|
||
export {}; | ||
|
||
=== common.cts === | ||
import type {} from "./module.mts"; | ||
import type {} from "./module.mts" with { "resolution-mode": "import" }; | ||
import type {} from "./module.mts" with { "resolution-mode": "require" }; | ||
type _1 = typeof import("./module.mts"); | ||
>_1 : typeof import("module", { with: { "resolution-mode": "import" } }) | ||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
type _2 = typeof import("./module.mts", { with: { "resolution-mode": "import" } }); | ||
>_2 : typeof import("module", { with: { "resolution-mode": "import" } }) | ||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
type _3 = typeof import("./module.mts", { with: { "resolution-mode": "require" } }); | ||
>_3 : typeof import("module", { with: { "resolution-mode": "import" } }) | ||
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
12 changes: 12 additions & 0 deletions
12
tests/cases/conformance/externalModules/typeOnly/typeOnlyESMImportFromCJS.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// @module: nodenext | ||
|
||
// @Filename: module.mts | ||
export {}; | ||
|
||
// @Filename: common.cts | ||
import type {} from "./module.mts"; | ||
import type {} from "./module.mts" with { "resolution-mode": "import" }; | ||
import type {} from "./module.mts" with { "resolution-mode": "require" }; | ||
type _1 = typeof import("./module.mts"); | ||
type _2 = typeof import("./module.mts", { with: { "resolution-mode": "import" } }); | ||
type _3 = typeof import("./module.mts", { with: { "resolution-mode": "require" } }); |
57 changes: 57 additions & 0 deletions
57
tests/cases/fourslash/codeFixMissingResolutionModeImportAttribute.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/// <reference path='fourslash.ts' /> | ||
|
||
// @module: nodenext | ||
|
||
// @Filename: /package.json | ||
//// { "type": "module" } | ||
|
||
// @Filename: /module.ts | ||
//// export {}; | ||
|
||
// @Filename: /common1.cts | ||
//// [|import type { } from "./module.ts"/*1*/;|] | ||
|
||
// @Filename: /common2.cts | ||
//// [|import type { } from "./module.ts"/*2*/ with { "type": "typescript" };|] | ||
|
||
// @Filename: /common3.cts | ||
//// [|import type { } from "./module"/*3*/;|] | ||
|
||
// @Filename: /common4.cts | ||
//// [|type _1 = typeof import("./module.ts"/*4*/);|] | ||
|
||
goTo.marker("1"); | ||
verify.codeFix({ | ||
index: 0, | ||
errorCode: ts.Diagnostics.Type_only_import_of_an_ECMAScript_module_from_a_CommonJS_module_must_have_a_resolution_mode_attribute.code, | ||
applyChanges: false, | ||
description: "Add 'resolution-mode' import attribute", | ||
newRangeContent: `import type { } from "./module.ts" with { "resolution-mode": "import" };`, | ||
}); | ||
|
||
goTo.marker("2"); | ||
verify.codeFix({ | ||
index: 0, | ||
errorCode: ts.Diagnostics.Type_only_import_of_an_ECMAScript_module_from_a_CommonJS_module_must_have_a_resolution_mode_attribute.code, | ||
applyChanges: false, | ||
description: "Add 'resolution-mode' import attribute", | ||
newRangeContent: `import type { } from "./module.ts" with { "type": "typescript", "resolution-mode": "import" };`, | ||
}); | ||
|
||
goTo.marker("3"); | ||
verify.codeFix({ | ||
index: 0, | ||
errorCode: ts.Diagnostics.Type_only_import_of_an_ECMAScript_module_from_a_CommonJS_module_must_have_a_resolution_mode_attribute.code, | ||
applyChanges: false, | ||
description: "Add 'resolution-mode' import attribute", | ||
newRangeContent: `import type { } from "./module" with { "resolution-mode": "require" };`, | ||
}); | ||
|
||
goTo.marker("4"); | ||
verify.codeFix({ | ||
index: 0, | ||
errorCode: ts.Diagnostics.Type_import_of_an_ECMAScript_module_from_a_CommonJS_module_must_have_a_resolution_mode_attribute.code, | ||
applyChanges: false, | ||
description: "Add 'resolution-mode' import attribute", | ||
newRangeContent: `type _1 = typeof import("./module.ts", { with: { "resolution-mode": "import" } });`, | ||
}); |