Skip to content

Commit

Permalink
Cherry-pick PR #49268 into release-4.7 (#49276)
Browse files Browse the repository at this point in the history
Component commits:
5d13ab2 moduleDetection: auto makes cjs files parse as modules, module: node sets moduleDetection: force

Co-authored-by: Wesley Wigham <t-weswig@microsoft.com>
  • Loading branch information
TypeScript Bot and weswigham authored Jun 1, 2022
1 parent 4e91c6c commit 3551935
Show file tree
Hide file tree
Showing 15 changed files with 75 additions and 7 deletions.
6 changes: 4 additions & 2 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
10 changes: 6 additions & 4 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ interface GlobalThing { a: number }
const a: GlobalThing = { a: 0 };

//// [usage.js]
"use strict";
/// <reference types="pkg" />
Object.defineProperty(exports, "__esModule", { value: true });
const a = { a: 0 };
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ interface GlobalThing { a: number }
const a: GlobalThing = { a: 0 };

//// [usage.js]
"use strict";
/// <reference types="pkg" />
Object.defineProperty(exports, "__esModule", { value: true });
const a = { a: 0 };
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 3551935

Please sign in to comment.