Allow extensionless mains for cjs mode packages even from an esm import (#47893)

This commit is contained in:
Wesley Wigham
2022-02-14 14:13:21 -08:00
committed by GitHub
parent 03f9035029
commit e32281cc02
5 changed files with 161 additions and 1 deletions
+11 -1
View File
@@ -1819,7 +1819,17 @@ namespace ts {
// Even if extensions is DtsOnly, we can still look up a .ts file as a result of package.json "types"
const nextExtensions = extensions === Extensions.DtsOnly ? Extensions.TypeScript : extensions;
// Don't do package.json lookup recursively, because Node.js' package lookup doesn't.
return nodeLoadModuleByRelativeName(nextExtensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ false);
// Disable `EsmMode` for the resolution of the package path for cjs-mode packages (so the `main` field can omit extensions)
// (technically it only emits a deprecation warning in esm packages right now, but that's probably
// enough to mean we don't need to support it)
const features = state.features;
if (jsonContent?.type !== "module") {
state.features &= ~NodeResolutionFeatures.EsmMode;
}
const result = nodeLoadModuleByRelativeName(nextExtensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ false);
state.features = features;
return result;
};
const onlyRecordFailuresForPackageFile = packageFile ? !directoryProbablyExists(getDirectoryPath(packageFile), state.host) : undefined;
@@ -0,0 +1,42 @@
//// [tests/cases/compiler/nodeNextEsmImportsOfPackagesWithExtensionlessMains.ts] ////
//// [package.json]
{
"name": "@types/ip",
"version": "1.1.0",
"main": "",
"types": "index"
}
//// [index.d.ts]
export function address(): string;
//// [package.json]
{
"name": "nullthrows",
"version": "1.1.1",
"main": "nullthrows.js",
"types": "nullthrows.d.ts"
}
//// [nullthrows.d.ts]
declare function nullthrows(x: any): any;
declare namespace nullthrows {
export {nullthrows as default};
}
export = nullthrows;
//// [package.json]
{
"type": "module"
}
//// [index.ts]
import * as ip from 'ip';
import nullthrows from 'nullthrows'; // shouldn't be callable, `nullthrows` is a cjs package, so the `default` is the module itself
export function getAddress(): string {
return nullthrows(ip.address());
}
//// [index.js]
import * as ip from 'ip';
import nullthrows from 'nullthrows'; // shouldn't be callable, `nullthrows` is a cjs package, so the `default` is the module itself
export function getAddress() {
return nullthrows(ip.address());
}
@@ -0,0 +1,35 @@
=== tests/cases/compiler/index.ts ===
import * as ip from 'ip';
>ip : Symbol(ip, Decl(index.ts, 0, 6))
import nullthrows from 'nullthrows'; // shouldn't be callable, `nullthrows` is a cjs package, so the `default` is the module itself
>nullthrows : Symbol(nullthrows, Decl(index.ts, 1, 6))
export function getAddress(): string {
>getAddress : Symbol(getAddress, Decl(index.ts, 1, 36))
return nullthrows(ip.address());
>nullthrows : Symbol(nullthrows, Decl(index.ts, 1, 6))
>ip.address : Symbol(ip.address, Decl(index.d.ts, 0, 0))
>ip : Symbol(ip, Decl(index.ts, 0, 6))
>address : Symbol(ip.address, Decl(index.d.ts, 0, 0))
}
=== tests/cases/compiler/node_modules/@types/ip/index.d.ts ===
export function address(): string;
>address : Symbol(address, Decl(index.d.ts, 0, 0))
=== tests/cases/compiler/node_modules/nullthrows/nullthrows.d.ts ===
declare function nullthrows(x: any): any;
>nullthrows : Symbol(nullthrows, Decl(nullthrows.d.ts, 0, 0), Decl(nullthrows.d.ts, 0, 41))
>x : Symbol(x, Decl(nullthrows.d.ts, 0, 28))
declare namespace nullthrows {
>nullthrows : Symbol(nullthrows, Decl(nullthrows.d.ts, 0, 0), Decl(nullthrows.d.ts, 0, 41))
export {nullthrows as default};
>nullthrows : Symbol(nullthrows, Decl(nullthrows.d.ts, 0, 0), Decl(nullthrows.d.ts, 0, 41))
>default : Symbol(default, Decl(nullthrows.d.ts, 2, 12))
}
export = nullthrows;
>nullthrows : Symbol(nullthrows, Decl(nullthrows.d.ts, 0, 0), Decl(nullthrows.d.ts, 0, 41))
@@ -0,0 +1,37 @@
=== tests/cases/compiler/index.ts ===
import * as ip from 'ip';
>ip : typeof ip
import nullthrows from 'nullthrows'; // shouldn't be callable, `nullthrows` is a cjs package, so the `default` is the module itself
>nullthrows : typeof nullthrows
export function getAddress(): string {
>getAddress : () => string
return nullthrows(ip.address());
>nullthrows(ip.address()) : any
>nullthrows : typeof nullthrows
>ip.address() : string
>ip.address : () => string
>ip : typeof ip
>address : () => string
}
=== tests/cases/compiler/node_modules/@types/ip/index.d.ts ===
export function address(): string;
>address : () => string
=== tests/cases/compiler/node_modules/nullthrows/nullthrows.d.ts ===
declare function nullthrows(x: any): any;
>nullthrows : typeof nullthrows
>x : any
declare namespace nullthrows {
>nullthrows : typeof nullthrows
export {nullthrows as default};
>nullthrows : typeof nullthrows
>default : typeof nullthrows
}
export = nullthrows;
>nullthrows : typeof nullthrows
@@ -0,0 +1,36 @@
// @noImplicitReferences: true
// @module: nodenext
// @outDir: esm
// @filename: node_modules/@types/ip/package.json
{
"name": "@types/ip",
"version": "1.1.0",
"main": "",
"types": "index"
}
// @filename: node_modules/@types/ip/index.d.ts
export function address(): string;
// @filename: node_modules/nullthrows/package.json
{
"name": "nullthrows",
"version": "1.1.1",
"main": "nullthrows.js",
"types": "nullthrows.d.ts"
}
// @filename: node_modules/nullthrows/nullthrows.d.ts
declare function nullthrows(x: any): any;
declare namespace nullthrows {
export {nullthrows as default};
}
export = nullthrows;
// @filename: package.json
{
"type": "module"
}
// @filename: index.ts
import * as ip from 'ip';
import nullthrows from 'nullthrows'; // shouldn't be callable, `nullthrows` is a cjs package, so the `default` is the module itself
export function getAddress(): string {
return nullthrows(ip.address());
}