diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 10e40cf4cecbd..3cefcf33bf2a8 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -2834,12 +2834,14 @@ namespace ts { } function setCommonJsModuleIndicator(node: Node) { - if (file.externalModuleIndicator) { + if (file.externalModuleIndicator && file.externalModuleIndicator !== true) { return false; } if (!file.commonJsModuleIndicator) { file.commonJsModuleIndicator = node; - bindSourceFileAsExternalModule(); + if (!file.externalModuleIndicator) { + bindSourceFileAsExternalModule(); + } } return true; } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b16ef4991a9f6..413600e0dcede 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2747,7 +2747,7 @@ namespace ts { return hasExportAssignmentSymbol(moduleSymbol); } // 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 - return !file.externalModuleIndicator && !resolveExportByName(moduleSymbol, escapeLeadingUnderscores("__esModule"), /*sourceNode*/ undefined, dontResolveAlias); + return typeof file.externalModuleIndicator !== "object" && !resolveExportByName(moduleSymbol, escapeLeadingUnderscores("__esModule"), /*sourceNode*/ undefined, dontResolveAlias); } function getTargetOfImportClause(node: ImportClause, dontResolveAlias: boolean): Symbol | undefined { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 5850d36971828..a4cb8f9d8a5ee 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -6312,8 +6312,9 @@ namespace ts { */ function isFileForcedToBeModuleByFormat(file: SourceFile): true | undefined { // Excludes declaration files - they still require an explicit `export {}` or the like - // for back compat purposes. - return file.impliedNodeFormat === ModuleKind.ESNext && !file.isDeclarationFile ? true : undefined; + // for back compat purposes. The only non-declaration files _not_ forced to be a module are `.js` files + // that aren't esm-mode (meaning not in a `type: module` scope). + return (file.impliedNodeFormat === ModuleKind.ESNext || (fileExtensionIsOneOf(file.fileName, [Extension.Cjs, Extension.Cts]))) && !file.isDeclarationFile ? true : undefined; } export function getSetExternalModuleIndicator(options: CompilerOptions): (file: SourceFile) => void { @@ -6322,7 +6323,7 @@ namespace ts { case ModuleDetectionKind.Force: // All non-declaration files are modules, declaration files still do the usual isFileProbablyExternalModule return (file: SourceFile) => { - file.externalModuleIndicator = !file.isDeclarationFile || isFileProbablyExternalModule(file); + file.externalModuleIndicator = isFileProbablyExternalModule(file) || !file.isDeclarationFile || undefined; }; case ModuleDetectionKind.Legacy: // Files are modules if they have imports, exports, or import.meta @@ -6382,7 +6383,8 @@ namespace ts { } export function getEmitModuleDetectionKind(options: CompilerOptions) { - return options.moduleDetection || ModuleDetectionKind.Auto; + return options.moduleDetection || + (getEmitModuleKind(options) === ModuleKind.Node16 || getEmitModuleKind(options) === ModuleKind.NodeNext ? ModuleDetectionKind.Force : ModuleDetectionKind.Auto); } export function hasJsonModuleEmitEnabled(options: CompilerOptions) { diff --git a/tests/baselines/reference/moduleResolutionWithoutExtension8.js b/tests/baselines/reference/moduleResolutionWithoutExtension8.js index 593f3668b3c73..7410092fdbcbb 100644 --- a/tests/baselines/reference/moduleResolutionWithoutExtension8.js +++ b/tests/baselines/reference/moduleResolutionWithoutExtension8.js @@ -3,5 +3,7 @@ import("./foo").then(x => x); // should error, ask for extension //// [bar.cjs] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); // Extensionless relative path dynamic import in a cjs module import("./foo").then(x => x); // should error, ask for extension diff --git a/tests/baselines/reference/nodeModulesAllowJsExportAssignment(module=node16).js b/tests/baselines/reference/nodeModulesAllowJsExportAssignment(module=node16).js index 10d6da622e9a4..7eb839f9e4697 100644 --- a/tests/baselines/reference/nodeModulesAllowJsExportAssignment(module=node16).js +++ b/tests/baselines/reference/nodeModulesAllowJsExportAssignment(module=node16).js @@ -34,6 +34,8 @@ module.exports = a; const a = {}; module.exports = a; //// [file.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); // cjs format file const a = {}; module.exports = a; diff --git a/tests/baselines/reference/nodeModulesAllowJsExportAssignment(module=nodenext).js b/tests/baselines/reference/nodeModulesAllowJsExportAssignment(module=nodenext).js index 10d6da622e9a4..7eb839f9e4697 100644 --- a/tests/baselines/reference/nodeModulesAllowJsExportAssignment(module=nodenext).js +++ b/tests/baselines/reference/nodeModulesAllowJsExportAssignment(module=nodenext).js @@ -34,6 +34,8 @@ module.exports = a; const a = {}; module.exports = a; //// [file.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); // cjs format file const a = {}; module.exports = a; diff --git a/tests/baselines/reference/nodeModulesAllowJsExportlessJsModuleDetectionAuto(module=node16).js b/tests/baselines/reference/nodeModulesAllowJsExportlessJsModuleDetectionAuto(module=node16).js new file mode 100644 index 0000000000000..e3ca6368e77fb --- /dev/null +++ b/tests/baselines/reference/nodeModulesAllowJsExportlessJsModuleDetectionAuto(module=node16).js @@ -0,0 +1,13 @@ +//// [tests/cases/conformance/node/allowJs/nodeModulesAllowJsExportlessJsModuleDetectionAuto.ts] //// + +//// [foo.cjs] +// this file is a module despite having no imports +//// [bar.js] +// however this file is _not_ a module + +//// [foo.cjs] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +// this file is a module despite having no imports +//// [bar.js] +// however this file is _not_ a module diff --git a/tests/baselines/reference/nodeModulesAllowJsExportlessJsModuleDetectionAuto(module=node16).symbols b/tests/baselines/reference/nodeModulesAllowJsExportlessJsModuleDetectionAuto(module=node16).symbols new file mode 100644 index 0000000000000..e4e9a53aa590d --- /dev/null +++ b/tests/baselines/reference/nodeModulesAllowJsExportlessJsModuleDetectionAuto(module=node16).symbols @@ -0,0 +1,5 @@ +=== tests/cases/conformance/node/allowJs/foo.cjs === +// this file is a module despite having no imports +No type information for this code.=== tests/cases/conformance/node/allowJs/bar.js === +// however this file is _not_ a module +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/nodeModulesAllowJsExportlessJsModuleDetectionAuto(module=node16).types b/tests/baselines/reference/nodeModulesAllowJsExportlessJsModuleDetectionAuto(module=node16).types new file mode 100644 index 0000000000000..e4e9a53aa590d --- /dev/null +++ b/tests/baselines/reference/nodeModulesAllowJsExportlessJsModuleDetectionAuto(module=node16).types @@ -0,0 +1,5 @@ +=== tests/cases/conformance/node/allowJs/foo.cjs === +// this file is a module despite having no imports +No type information for this code.=== tests/cases/conformance/node/allowJs/bar.js === +// however this file is _not_ a module +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/nodeModulesAllowJsExportlessJsModuleDetectionAuto(module=nodenext).js b/tests/baselines/reference/nodeModulesAllowJsExportlessJsModuleDetectionAuto(module=nodenext).js new file mode 100644 index 0000000000000..e3ca6368e77fb --- /dev/null +++ b/tests/baselines/reference/nodeModulesAllowJsExportlessJsModuleDetectionAuto(module=nodenext).js @@ -0,0 +1,13 @@ +//// [tests/cases/conformance/node/allowJs/nodeModulesAllowJsExportlessJsModuleDetectionAuto.ts] //// + +//// [foo.cjs] +// this file is a module despite having no imports +//// [bar.js] +// however this file is _not_ a module + +//// [foo.cjs] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +// this file is a module despite having no imports +//// [bar.js] +// however this file is _not_ a module diff --git a/tests/baselines/reference/nodeModulesAllowJsExportlessJsModuleDetectionAuto(module=nodenext).symbols b/tests/baselines/reference/nodeModulesAllowJsExportlessJsModuleDetectionAuto(module=nodenext).symbols new file mode 100644 index 0000000000000..e4e9a53aa590d --- /dev/null +++ b/tests/baselines/reference/nodeModulesAllowJsExportlessJsModuleDetectionAuto(module=nodenext).symbols @@ -0,0 +1,5 @@ +=== tests/cases/conformance/node/allowJs/foo.cjs === +// this file is a module despite having no imports +No type information for this code.=== tests/cases/conformance/node/allowJs/bar.js === +// however this file is _not_ a module +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/nodeModulesAllowJsExportlessJsModuleDetectionAuto(module=nodenext).types b/tests/baselines/reference/nodeModulesAllowJsExportlessJsModuleDetectionAuto(module=nodenext).types new file mode 100644 index 0000000000000..e4e9a53aa590d --- /dev/null +++ b/tests/baselines/reference/nodeModulesAllowJsExportlessJsModuleDetectionAuto(module=nodenext).types @@ -0,0 +1,5 @@ +=== tests/cases/conformance/node/allowJs/foo.cjs === +// this file is a module despite having no imports +No type information for this code.=== tests/cases/conformance/node/allowJs/bar.js === +// however this file is _not_ a module +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/tripleSlashTypesReferenceWithMissingExports(module=node16).js b/tests/baselines/reference/tripleSlashTypesReferenceWithMissingExports(module=node16).js index 89dd2c7541a29..7c518b3b9d9cc 100644 --- a/tests/baselines/reference/tripleSlashTypesReferenceWithMissingExports(module=node16).js +++ b/tests/baselines/reference/tripleSlashTypesReferenceWithMissingExports(module=node16).js @@ -14,5 +14,7 @@ interface GlobalThing { a: number } const a: GlobalThing = { a: 0 }; //// [usage.js] +"use strict"; /// +Object.defineProperty(exports, "__esModule", { value: true }); const a = { a: 0 }; diff --git a/tests/baselines/reference/tripleSlashTypesReferenceWithMissingExports(module=nodenext).js b/tests/baselines/reference/tripleSlashTypesReferenceWithMissingExports(module=nodenext).js index 89dd2c7541a29..7c518b3b9d9cc 100644 --- a/tests/baselines/reference/tripleSlashTypesReferenceWithMissingExports(module=nodenext).js +++ b/tests/baselines/reference/tripleSlashTypesReferenceWithMissingExports(module=nodenext).js @@ -14,5 +14,7 @@ interface GlobalThing { a: number } const a: GlobalThing = { a: 0 }; //// [usage.js] +"use strict"; /// +Object.defineProperty(exports, "__esModule", { value: true }); const a = { a: 0 }; diff --git a/tests/cases/conformance/node/allowJs/nodeModulesAllowJsExportlessJsModuleDetectionAuto.ts b/tests/cases/conformance/node/allowJs/nodeModulesAllowJsExportlessJsModuleDetectionAuto.ts new file mode 100644 index 0000000000000..24037e466bafa --- /dev/null +++ b/tests/cases/conformance/node/allowJs/nodeModulesAllowJsExportlessJsModuleDetectionAuto.ts @@ -0,0 +1,8 @@ +// @module: node16,nodenext +// @allowJs: true +// @outDir: ./out +// @moduleDetection: auto +// @filename: foo.cjs +// this file is a module despite having no imports +// @filename: bar.js +// however this file is _not_ a module \ No newline at end of file