Skip to content

Commit 585a9af

Browse files
authored
Respect package.json "type" and module-format-specific file extensions in more module modes (microsoft#57896)
1 parent 6431a30 commit 585a9af

File tree

1,444 files changed

+76135
-14338
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,444 files changed

+76135
-14338
lines changed

src/compiler/_namespaces/ts.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export * from "../transformers/generators";
5555
export * from "../transformers/module/module";
5656
export * from "../transformers/module/system";
5757
export * from "../transformers/module/esnextAnd2015";
58-
export * from "../transformers/module/node";
58+
export * from "../transformers/module/impliedNodeFormatDependent";
5959
export * from "../transformers/declarations/diagnostics";
6060
export * from "../transformers/declarations";
6161
export * from "../transformer";

src/compiler/checker.ts

+63-34
Large diffs are not rendered by default.

src/compiler/diagnosticMessages.json

+4
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,10 @@
967967
"category": "Error",
968968
"code": 1292
969969
},
970+
"ESM syntax is not allowed in a CommonJS module when 'module' is set to 'preserve'.": {
971+
"category": "Error",
972+
"code": 1293
973+
},
970974

971975
"'with' statements are not allowed in an async function block.": {
972976
"category": "Error",

src/compiler/emitter.ts

+3
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ import {
130130
getEmitFlags,
131131
getEmitHelpers,
132132
getEmitModuleKind,
133+
getEmitModuleResolutionKind,
133134
getEmitScriptTarget,
134135
getExternalModuleName,
135136
getIdentifierTypeArguments,
@@ -800,6 +801,7 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi
800801
newLine: compilerOptions.newLine,
801802
noEmitHelpers: compilerOptions.noEmitHelpers,
802803
module: getEmitModuleKind(compilerOptions),
804+
moduleResolution: getEmitModuleResolutionKind(compilerOptions),
803805
target: getEmitScriptTarget(compilerOptions),
804806
sourceMap: compilerOptions.sourceMap,
805807
inlineSourceMap: compilerOptions.inlineSourceMap,
@@ -867,6 +869,7 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi
867869
newLine: compilerOptions.newLine,
868870
noEmitHelpers: true,
869871
module: compilerOptions.module,
872+
moduleResolution: compilerOptions.moduleResolution,
870873
target: compilerOptions.target,
871874
sourceMap: !forceDtsEmit && compilerOptions.declarationMap,
872875
inlineSourceMap: compilerOptions.inlineSourceMap,

src/compiler/factory/utilities.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,12 @@ import {
5353
getAllAccessorDeclarations,
5454
getEmitFlags,
5555
getEmitHelpers,
56+
getEmitModuleFormatOfFileWorker,
5657
getEmitModuleKind,
5758
getESModuleInterop,
5859
getExternalModuleName,
5960
getExternalModuleNameFromPath,
61+
getImpliedNodeFormatForEmitWorker,
6062
getJSDocType,
6163
getJSDocTypeTag,
6264
getModifiers,
@@ -712,7 +714,7 @@ export function createExternalHelpersImportDeclarationIfNeeded(nodeFactory: Node
712714
if (compilerOptions.importHelpers && isEffectiveExternalModule(sourceFile, compilerOptions)) {
713715
let namedBindings: NamedImportBindings | undefined;
714716
const moduleKind = getEmitModuleKind(compilerOptions);
715-
if ((moduleKind >= ModuleKind.ES2015 && moduleKind <= ModuleKind.ESNext) || sourceFile.impliedNodeFormat === ModuleKind.ESNext) {
717+
if ((moduleKind >= ModuleKind.ES2015 && moduleKind <= ModuleKind.ESNext) || getImpliedNodeFormatForEmitWorker(sourceFile, compilerOptions) === ModuleKind.ESNext) {
716718
// use named imports
717719
const helpers = getEmitHelpers(sourceFile);
718720
if (helpers) {
@@ -769,10 +771,8 @@ export function getOrCreateExternalHelpersModuleNameIfNeeded(factory: NodeFactor
769771
return externalHelpersModuleName;
770772
}
771773

772-
const moduleKind = getEmitModuleKind(compilerOptions);
773774
let create = (hasExportStarsToExportValues || (getESModuleInterop(compilerOptions) && hasImportStarOrImportDefault))
774-
&& moduleKind !== ModuleKind.System
775-
&& (moduleKind < ModuleKind.ES2015 || node.impliedNodeFormat === ModuleKind.CommonJS);
775+
&& getEmitModuleFormatOfFileWorker(node, compilerOptions) < ModuleKind.System;
776776
if (!create) {
777777
const helpers = getEmitHelpers(node);
778778
if (helpers) {

src/compiler/moduleSpecifiers.ts

+24-13
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ import {
3636
getBaseFileName,
3737
GetCanonicalFileName,
3838
getConditions,
39+
getDefaultResolutionModeForFileWorker,
3940
getDirectoryPath,
4041
getEmitModuleResolutionKind,
41-
getModeForResolutionAtIndex,
4242
getModuleNameStringLiteralAt,
4343
getModuleSpecifierEndingPreference,
4444
getNodeModulePathParts,
@@ -136,12 +136,13 @@ export interface ModuleSpecifierPreferences {
136136
/**
137137
* @param syntaxImpliedNodeFormat Used when the import syntax implies ESM or CJS irrespective of the mode of the file.
138138
*/
139-
getAllowedEndingsInPreferredOrder(syntaxImpliedNodeFormat?: SourceFile["impliedNodeFormat"]): ModuleSpecifierEnding[];
139+
getAllowedEndingsInPreferredOrder(syntaxImpliedNodeFormat?: ResolutionMode): ModuleSpecifierEnding[];
140140
}
141141

142142
/** @internal */
143143
export function getModuleSpecifierPreferences(
144144
{ importModuleSpecifierPreference, importModuleSpecifierEnding }: UserPreferences,
145+
host: Pick<ModuleSpecifierResolutionHost, "getDefaultResolutionModeForFile">,
145146
compilerOptions: CompilerOptions,
146147
importingSourceFile: Pick<SourceFile, "fileName" | "impliedNodeFormat">,
147148
oldImportSpecifier?: string,
@@ -156,8 +157,10 @@ export function getModuleSpecifierPreferences(
156157
importModuleSpecifierPreference === "project-relative" ? RelativePreference.ExternalNonRelative :
157158
RelativePreference.Shortest,
158159
getAllowedEndingsInPreferredOrder: syntaxImpliedNodeFormat => {
159-
const preferredEnding = syntaxImpliedNodeFormat !== importingSourceFile.impliedNodeFormat ? getPreferredEnding(syntaxImpliedNodeFormat) : filePreferredEnding;
160-
if ((syntaxImpliedNodeFormat ?? importingSourceFile.impliedNodeFormat) === ModuleKind.ESNext) {
160+
const impliedNodeFormat = getDefaultResolutionModeForFile(importingSourceFile, host, compilerOptions);
161+
const preferredEnding = syntaxImpliedNodeFormat !== impliedNodeFormat ? getPreferredEnding(syntaxImpliedNodeFormat) : filePreferredEnding;
162+
const moduleResolution = getEmitModuleResolutionKind(compilerOptions);
163+
if ((syntaxImpliedNodeFormat ?? impliedNodeFormat) === ModuleKind.ESNext && ModuleResolutionKind.Node16 <= moduleResolution && moduleResolution <= ModuleResolutionKind.NodeNext) {
161164
if (shouldAllowImportingTsExtension(compilerOptions, importingSourceFile.fileName)) {
162165
return [ModuleSpecifierEnding.TsExtension, ModuleSpecifierEnding.JsExtension];
163166
}
@@ -197,7 +200,7 @@ export function getModuleSpecifierPreferences(
197200
}
198201
return getModuleSpecifierEndingPreference(
199202
importModuleSpecifierEnding,
200-
resolutionMode ?? importingSourceFile.impliedNodeFormat,
203+
resolutionMode ?? getDefaultResolutionModeForFile(importingSourceFile, host, compilerOptions),
201204
compilerOptions,
202205
isFullSourceFile(importingSourceFile) ? importingSourceFile : undefined,
203206
);
@@ -218,7 +221,7 @@ export function updateModuleSpecifier(
218221
oldImportSpecifier: string,
219222
options: ModuleSpecifierOptions = {},
220223
): string | undefined {
221-
const res = getModuleSpecifierWorker(compilerOptions, importingSourceFile, importingSourceFileName, toFileName, host, getModuleSpecifierPreferences({}, compilerOptions, importingSourceFile, oldImportSpecifier), {}, options);
224+
const res = getModuleSpecifierWorker(compilerOptions, importingSourceFile, importingSourceFileName, toFileName, host, getModuleSpecifierPreferences({}, host, compilerOptions, importingSourceFile, oldImportSpecifier), {}, options);
222225
if (res === oldImportSpecifier) return undefined;
223226
return res;
224227
}
@@ -238,7 +241,7 @@ export function getModuleSpecifier(
238241
host: ModuleSpecifierResolutionHost,
239242
options: ModuleSpecifierOptions = {},
240243
): string {
241-
return getModuleSpecifierWorker(compilerOptions, importingSourceFile, importingSourceFileName, toFileName, host, getModuleSpecifierPreferences({}, compilerOptions, importingSourceFile), {}, options);
244+
return getModuleSpecifierWorker(compilerOptions, importingSourceFile, importingSourceFileName, toFileName, host, getModuleSpecifierPreferences({}, host, compilerOptions, importingSourceFile), {}, options);
242245
}
243246

244247
/** @internal */
@@ -268,7 +271,7 @@ function getModuleSpecifierWorker(
268271
const info = getInfo(importingSourceFileName, host);
269272
const modulePaths = getAllModulePaths(info, toFileName, host, userPreferences, options);
270273
return firstDefined(modulePaths, modulePath => tryGetModuleNameAsNodeModule(modulePath, info, importingSourceFile, host, compilerOptions, userPreferences, /*packageNameOnly*/ undefined, options.overrideImportMode)) ||
271-
getLocalModuleSpecifier(toFileName, info, compilerOptions, host, options.overrideImportMode || importingSourceFile.impliedNodeFormat, preferences);
274+
getLocalModuleSpecifier(toFileName, info, compilerOptions, host, options.overrideImportMode || getDefaultResolutionModeForFile(importingSourceFile, host, compilerOptions), preferences);
272275
}
273276

274277
/** @internal */
@@ -388,7 +391,7 @@ export function getLocalModuleSpecifierBetweenFileNames(
388391
compilerOptions,
389392
host,
390393
importMode,
391-
getModuleSpecifierPreferences({}, compilerOptions, importingFile),
394+
getModuleSpecifierPreferences({}, host, compilerOptions, importingFile),
392395
);
393396
}
394397

@@ -402,15 +405,19 @@ function computeModuleSpecifiers(
402405
forAutoImport: boolean,
403406
): readonly string[] {
404407
const info = getInfo(importingSourceFile.fileName, host);
405-
const preferences = getModuleSpecifierPreferences(userPreferences, compilerOptions, importingSourceFile);
408+
const preferences = getModuleSpecifierPreferences(userPreferences, host, compilerOptions, importingSourceFile);
406409
const existingSpecifier = isFullSourceFile(importingSourceFile) && forEach(modulePaths, modulePath =>
407410
forEach(
408411
host.getFileIncludeReasons().get(toPath(modulePath.path, host.getCurrentDirectory(), info.getCanonicalFileName)),
409412
reason => {
410413
if (reason.kind !== FileIncludeKind.Import || reason.file !== importingSourceFile.path) return undefined;
411414
// If the candidate import mode doesn't match the mode we're generating for, don't consider it
412415
// TODO: maybe useful to keep around as an alternative option for certain contexts where the mode is overridable
413-
if (importingSourceFile.impliedNodeFormat && importingSourceFile.impliedNodeFormat !== getModeForResolutionAtIndex(importingSourceFile, reason.index, compilerOptions)) return undefined;
416+
const existingMode = host.getModeForResolutionAtIndex(importingSourceFile, reason.index);
417+
const targetMode = options.overrideImportMode ?? host.getDefaultResolutionModeForFile(importingSourceFile);
418+
if (existingMode !== targetMode && existingMode !== undefined && targetMode !== undefined) {
419+
return undefined;
420+
}
414421
const specifier = getModuleNameStringLiteralAt(importingSourceFile, reason.index).text;
415422
// If the preference is for non relative and the module specifier is relative, ignore it
416423
return preferences.relativePreference !== RelativePreference.NonRelative || !pathIsRelative(specifier) ?
@@ -1047,7 +1054,7 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan
10471054

10481055
// Simplify the full file path to something that can be resolved by Node.
10491056

1050-
const preferences = getModuleSpecifierPreferences(userPreferences, options, importingSourceFile);
1057+
const preferences = getModuleSpecifierPreferences(userPreferences, host, options, importingSourceFile);
10511058
const allowedEndings = preferences.getAllowedEndingsInPreferredOrder();
10521059
let moduleSpecifier = path;
10531060
let isPackageRootPath = false;
@@ -1107,7 +1114,7 @@ function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCan
11071114
const cachedPackageJson = host.getPackageJsonInfoCache?.()?.getPackageJsonInfo(packageJsonPath);
11081115
if (isPackageJsonInfo(cachedPackageJson) || cachedPackageJson === undefined && host.fileExists(packageJsonPath)) {
11091116
const packageJsonContent: Record<string, any> | undefined = cachedPackageJson?.contents.packageJsonContent || tryParseJson(host.readFile!(packageJsonPath)!);
1110-
const importMode = overrideMode || importingSourceFile.impliedNodeFormat;
1117+
const importMode = overrideMode || getDefaultResolutionModeForFile(importingSourceFile, host, options);
11111118
if (getResolvePackageJsonExports(options)) {
11121119
// The package name that we found in node_modules could be different from the package
11131120
// name in the package.json content via url/filepath dependency specifiers. We need to
@@ -1302,3 +1309,7 @@ function getRelativePathIfInSameVolume(path: string, directoryPath: string, getC
13021309
function isPathRelativeToParent(path: string): boolean {
13031310
return startsWith(path, "..");
13041311
}
1312+
1313+
function getDefaultResolutionModeForFile(file: Pick<SourceFile, "fileName" | "impliedNodeFormat" | "packageJsonScope">, host: Pick<ModuleSpecifierResolutionHost, "getDefaultResolutionModeForFile">, compilerOptions: CompilerOptions) {
1314+
return isFullSourceFile(file) ? host.getDefaultResolutionModeForFile(file) : getDefaultResolutionModeForFileWorker(file, compilerOptions);
1315+
}

0 commit comments

Comments
 (0)