Skip to content

Commit 67673f3

Browse files
authored
moduleDetection: auto makes cjs files parse as modules, module: node sets moduleDetection: force (#49268)
1 parent 5b86612 commit 67673f3

15 files changed

+75
-7
lines changed

src/compiler/binder.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2834,12 +2834,14 @@ namespace ts {
28342834
}
28352835

28362836
function setCommonJsModuleIndicator(node: Node) {
2837-
if (file.externalModuleIndicator) {
2837+
if (file.externalModuleIndicator && file.externalModuleIndicator !== true) {
28382838
return false;
28392839
}
28402840
if (!file.commonJsModuleIndicator) {
28412841
file.commonJsModuleIndicator = node;
2842-
bindSourceFileAsExternalModule();
2842+
if (!file.externalModuleIndicator) {
2843+
bindSourceFileAsExternalModule();
2844+
}
28432845
}
28442846
return true;
28452847
}

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2747,7 +2747,7 @@ namespace ts {
27472747
return hasExportAssignmentSymbol(moduleSymbol);
27482748
}
27492749
// JS files have a synthetic default if they do not contain ES2015+ module syntax (export = is not valid in js) _and_ do not have an __esModule marker
2750-
return !file.externalModuleIndicator && !resolveExportByName(moduleSymbol, escapeLeadingUnderscores("__esModule"), /*sourceNode*/ undefined, dontResolveAlias);
2750+
return typeof file.externalModuleIndicator !== "object" && !resolveExportByName(moduleSymbol, escapeLeadingUnderscores("__esModule"), /*sourceNode*/ undefined, dontResolveAlias);
27512751
}
27522752

27532753
function getTargetOfImportClause(node: ImportClause, dontResolveAlias: boolean): Symbol | undefined {

src/compiler/utilities.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6302,8 +6302,9 @@ namespace ts {
63026302
*/
63036303
function isFileForcedToBeModuleByFormat(file: SourceFile): true | undefined {
63046304
// Excludes declaration files - they still require an explicit `export {}` or the like
6305-
// for back compat purposes.
6306-
return file.impliedNodeFormat === ModuleKind.ESNext && !file.isDeclarationFile ? true : undefined;
6305+
// for back compat purposes. The only non-declaration files _not_ forced to be a module are `.js` files
6306+
// that aren't esm-mode (meaning not in a `type: module` scope).
6307+
return (file.impliedNodeFormat === ModuleKind.ESNext || (fileExtensionIsOneOf(file.fileName, [Extension.Cjs, Extension.Cts]))) && !file.isDeclarationFile ? true : undefined;
63076308
}
63086309

63096310
export function getSetExternalModuleIndicator(options: CompilerOptions): (file: SourceFile) => void {
@@ -6312,7 +6313,7 @@ namespace ts {
63126313
case ModuleDetectionKind.Force:
63136314
// All non-declaration files are modules, declaration files still do the usual isFileProbablyExternalModule
63146315
return (file: SourceFile) => {
6315-
file.externalModuleIndicator = !file.isDeclarationFile || isFileProbablyExternalModule(file);
6316+
file.externalModuleIndicator = isFileProbablyExternalModule(file) || !file.isDeclarationFile || undefined;
63166317
};
63176318
case ModuleDetectionKind.Legacy:
63186319
// Files are modules if they have imports, exports, or import.meta
@@ -6372,7 +6373,8 @@ namespace ts {
63726373
}
63736374

63746375
export function getEmitModuleDetectionKind(options: CompilerOptions) {
6375-
return options.moduleDetection || ModuleDetectionKind.Auto;
6376+
return options.moduleDetection ||
6377+
(getEmitModuleKind(options) === ModuleKind.Node16 || getEmitModuleKind(options) === ModuleKind.NodeNext ? ModuleDetectionKind.Force : ModuleDetectionKind.Auto);
63766378
}
63776379

63786380
export function hasJsonModuleEmitEnabled(options: CompilerOptions) {

tests/baselines/reference/moduleResolutionWithoutExtension8.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@
33
import("./foo").then(x => x); // should error, ask for extension
44

55
//// [bar.cjs]
6+
"use strict";
7+
Object.defineProperty(exports, "__esModule", { value: true });
68
// Extensionless relative path dynamic import in a cjs module
79
import("./foo").then(x => x); // should error, ask for extension

tests/baselines/reference/nodeModulesAllowJsExportAssignment(module=node16).js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ module.exports = a;
3434
const a = {};
3535
module.exports = a;
3636
//// [file.js]
37+
"use strict";
38+
Object.defineProperty(exports, "__esModule", { value: true });
3739
// cjs format file
3840
const a = {};
3941
module.exports = a;

tests/baselines/reference/nodeModulesAllowJsExportAssignment(module=nodenext).js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ module.exports = a;
3434
const a = {};
3535
module.exports = a;
3636
//// [file.js]
37+
"use strict";
38+
Object.defineProperty(exports, "__esModule", { value: true });
3739
// cjs format file
3840
const a = {};
3941
module.exports = a;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//// [tests/cases/conformance/node/allowJs/nodeModulesAllowJsExportlessJsModuleDetectionAuto.ts] ////
2+
3+
//// [foo.cjs]
4+
// this file is a module despite having no imports
5+
//// [bar.js]
6+
// however this file is _not_ a module
7+
8+
//// [foo.cjs]
9+
"use strict";
10+
Object.defineProperty(exports, "__esModule", { value: true });
11+
// this file is a module despite having no imports
12+
//// [bar.js]
13+
// however this file is _not_ a module
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
=== tests/cases/conformance/node/allowJs/foo.cjs ===
2+
// this file is a module despite having no imports
3+
No type information for this code.=== tests/cases/conformance/node/allowJs/bar.js ===
4+
// however this file is _not_ a module
5+
No type information for this code.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
=== tests/cases/conformance/node/allowJs/foo.cjs ===
2+
// this file is a module despite having no imports
3+
No type information for this code.=== tests/cases/conformance/node/allowJs/bar.js ===
4+
// however this file is _not_ a module
5+
No type information for this code.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//// [tests/cases/conformance/node/allowJs/nodeModulesAllowJsExportlessJsModuleDetectionAuto.ts] ////
2+
3+
//// [foo.cjs]
4+
// this file is a module despite having no imports
5+
//// [bar.js]
6+
// however this file is _not_ a module
7+
8+
//// [foo.cjs]
9+
"use strict";
10+
Object.defineProperty(exports, "__esModule", { value: true });
11+
// this file is a module despite having no imports
12+
//// [bar.js]
13+
// however this file is _not_ a module
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
=== tests/cases/conformance/node/allowJs/foo.cjs ===
2+
// this file is a module despite having no imports
3+
No type information for this code.=== tests/cases/conformance/node/allowJs/bar.js ===
4+
// however this file is _not_ a module
5+
No type information for this code.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
=== tests/cases/conformance/node/allowJs/foo.cjs ===
2+
// this file is a module despite having no imports
3+
No type information for this code.=== tests/cases/conformance/node/allowJs/bar.js ===
4+
// however this file is _not_ a module
5+
No type information for this code.

tests/baselines/reference/tripleSlashTypesReferenceWithMissingExports(module=node16).js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,7 @@ interface GlobalThing { a: number }
1414
const a: GlobalThing = { a: 0 };
1515

1616
//// [usage.js]
17+
"use strict";
1718
/// <reference types="pkg" />
19+
Object.defineProperty(exports, "__esModule", { value: true });
1820
const a = { a: 0 };

tests/baselines/reference/tripleSlashTypesReferenceWithMissingExports(module=nodenext).js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,7 @@ interface GlobalThing { a: number }
1414
const a: GlobalThing = { a: 0 };
1515

1616
//// [usage.js]
17+
"use strict";
1718
/// <reference types="pkg" />
19+
Object.defineProperty(exports, "__esModule", { value: true });
1820
const a = { a: 0 };
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// @module: node16,nodenext
2+
// @allowJs: true
3+
// @outDir: ./out
4+
// @moduleDetection: auto
5+
// @filename: foo.cjs
6+
// this file is a module despite having no imports
7+
// @filename: bar.js
8+
// however this file is _not_ a module

0 commit comments

Comments
 (0)