diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bf6b21d61d5..f85d3f887a47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ - `[jest-config, jest-worker]` Use `os.availableParallelism` if available to calculate number of workers to spawn ([#13738](https://github.com/facebook/jest/pull/13738)) - `[@jest/globals, jest-mock]` Add `jest.replaceProperty()` that replaces property value ([#13496](https://github.com/facebook/jest/pull/13496)) - `[jest-haste-map]` ignore Sapling vcs directories (`.sl/`) ([#13674](https://github.com/facebook/jest/pull/13674)) -- `[jest-resolve]` Support subpath imports ([#13705](https://github.com/facebook/jest/pull/13705), [#13723](https://github.com/facebook/jest/pull/13723)) +- `[jest-resolve]` Support subpath imports ([#13705](https://github.com/facebook/jest/pull/13705), [#13723](https://github.com/facebook/jest/pull/13723)), [#13777](https://github.com/facebook/jest/pull/13777)) - `[jest-runtime]` Add `jest.isolateModulesAsync` for scoped module initialization of asynchronous functions ([#13680](https://github.com/facebook/jest/pull/13680)) - `[jest-runtime]` Add `jest.isEnvironmentTornDown` function ([#13698](https://github.com/facebook/jest/pull/13698)) - `[jest-test-result]` Added `skipped` and `focused` status to `FormattedTestResult` ([#13700](https://github.com/facebook/jest/pull/13700)) diff --git a/packages/jest-resolve/package.json b/packages/jest-resolve/package.json index d2ee0d635ac1..f77f2d94f45f 100644 --- a/packages/jest-resolve/package.json +++ b/packages/jest-resolve/package.json @@ -24,8 +24,7 @@ "jest-util": "workspace:^", "jest-validate": "workspace:^", "resolve": "^1.20.0", - "resolve.exports": "^1.1.1", - "resolve.imports": "^2.0.3", + "resolve.exports": "^2.0.0", "slash": "^3.0.0" }, "devDependencies": { diff --git a/packages/jest-resolve/src/__tests__/resolve.test.ts b/packages/jest-resolve/src/__tests__/resolve.test.ts index 6cecedfcb7aa..48fb0bf39805 100644 --- a/packages/jest-resolve/src/__tests__/resolve.test.ts +++ b/packages/jest-resolve/src/__tests__/resolve.test.ts @@ -397,14 +397,7 @@ describe('findNodeModule', () => { basedir: path.resolve(importsRoot, './foo-import/index.js'), conditions: [], }); - }).toThrow( - expect.objectContaining({ - code: 'ERR_PACKAGE_IMPORT_NOT_DEFINED', - message: expect.stringMatching( - /^Package import specifier "#something-else" is not defined in package/, - ), - }), - ); + }).toThrow('Missing "#something-else" specifier in "foo-import" package'); }); }); }); diff --git a/packages/jest-resolve/src/defaultResolver.ts b/packages/jest-resolve/src/defaultResolver.ts index ad231802bda7..8d050c49c13e 100644 --- a/packages/jest-resolve/src/defaultResolver.ts +++ b/packages/jest-resolve/src/defaultResolver.ts @@ -8,11 +8,7 @@ import {dirname, isAbsolute, resolve as pathResolve} from 'path'; import pnpResolver from 'jest-pnp-resolver'; import {SyncOpts as UpstreamResolveOptions, sync as resolveSync} from 'resolve'; -import { - Options as ResolveExportsOptions, - resolve as resolveExports, -} from 'resolve.exports'; -import {resolve as resolveImports} from 'resolve.imports'; +import * as resolve from 'resolve.exports'; import { findClosestPackageJson, isDirectory, @@ -148,28 +144,26 @@ function getPathInModule( const pkg = readPackageCached(closestPackageJson); - const resolved = resolveImports( - { - base: options.basedir, - content: pkg, - path: dirname(closestPackageJson), - }, - path, - createImportsResolveOptions(options.conditions), + const resolved = resolve.imports( + pkg, + path as resolve.Imports.Entry, + createResolveOptions(options.conditions), ); - if (!resolved) { + if (resolved) { + const target = resolved[0]; + return target.startsWith('.') + ? // internal relative filepath + pathResolve(dirname(closestPackageJson), target) + : // this is an external module, re-resolve it + defaultResolver(target, options); + } + + if (pkg.imports) { throw new Error( '`imports` exists, but no results - this is a bug in Jest. Please report an issue', ); } - - if (resolved.startsWith('.')) { - return pathResolve(dirname(closestPackageJson), resolved); - } - - // this is an external module, re-resolve it - return defaultResolver(resolved, options); } const segments = path.split('/'); @@ -186,22 +180,22 @@ function getPathInModule( if (closestPackageJson) { const pkg = readPackageCached(closestPackageJson); - if (pkg.name === moduleName && pkg.exports) { - const subpath = segments.join('/') || '.'; - - const resolved = resolveExports( + if (pkg.name === moduleName) { + const resolved = resolve.exports( pkg, - subpath, + (segments.join('/') || '.') as resolve.Exports.Entry, createResolveOptions(options.conditions), ); - if (!resolved) { + if (resolved) { + return pathResolve(dirname(closestPackageJson), resolved[0]); + } + + if (pkg.exports) { throw new Error( '`exports` exists, but no results - this is a bug in Jest. Please report an issue', ); } - - return pathResolve(dirname(closestPackageJson), resolved); } } @@ -216,22 +210,20 @@ function getPathInModule( if (packageJsonPath && isFile(packageJsonPath)) { const pkg = readPackageCached(packageJsonPath); - if (pkg.exports) { - const subpath = segments.join('/') || '.'; - - const resolved = resolveExports( - pkg, - subpath, - createResolveOptions(options.conditions), - ); + const resolved = resolve.exports( + pkg, + (segments.join('/') || '.') as resolve.Exports.Entry, + createResolveOptions(options.conditions), + ); - if (!resolved) { - throw new Error( - '`exports` exists, but no results - this is a bug in Jest. Please report an issue', - ); - } + if (resolved) { + return pathResolve(dirname(packageJsonPath), resolved[0]); + } - return pathResolve(dirname(packageJsonPath), resolved); + if (pkg.exports) { + throw new Error( + '`exports` exists, but no results - this is a bug in Jest. Please report an issue', + ); } } } @@ -241,21 +233,13 @@ function getPathInModule( function createResolveOptions( conditions: Array | undefined, -): ResolveExportsOptions { +): resolve.Options { return conditions ? {conditions, unsafe: true} : // no conditions were passed - let's assume this is Jest internal and it should be `require` {browser: false, require: true}; } -function createImportsResolveOptions(conditions: Array | undefined) { - return { - conditions: conditions - ? [...conditions, 'default'] - : ['node', 'require', 'default'], - }; -} - // if it's a relative import or an absolute path, imports/exports are ignored const shouldIgnoreRequestForExports = (path: string) => path.startsWith('.') || isAbsolute(path); diff --git a/yarn.lock b/yarn.lock index 5bbd8687ee48..0f12970b068e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12895,8 +12895,7 @@ __metadata: jest-util: "workspace:^" jest-validate: "workspace:^" resolve: ^1.20.0 - resolve.exports: ^1.1.1 - resolve.imports: ^2.0.3 + resolve.exports: ^2.0.0 slash: ^3.0.0 tsd-lite: ^0.6.0 languageName: unknown @@ -16415,13 +16414,6 @@ __metadata: languageName: node linkType: hard -"pattern-key-compare@npm:^2.0.0": - version: 2.0.0 - resolution: "pattern-key-compare@npm:2.0.0" - checksum: cded15070cddbc5ef7b97c1b91371bcf59ff931f8afe383d2323f935891e6c4517bd76154f5edc2b1ab53c6fbeeb0711b9db43af592064482d0a9ccf03dd507c - languageName: node - linkType: hard - "pend@npm:~1.2.0": version: 1.2.0 resolution: "pend@npm:1.2.0" @@ -18359,19 +18351,10 @@ __metadata: languageName: node linkType: hard -"resolve.exports@npm:^1.1.1": - version: 1.1.1 - resolution: "resolve.exports@npm:1.1.1" - checksum: 485aa10082eb388a569d696e17ad7b16f4186efc97dd34eadd029d95b811f21ffee13b1b733198bb4584dbb3cb296aa6f141835221fb7613b9606b84f1386655 - languageName: node - linkType: hard - -"resolve.imports@npm:^2.0.3": - version: 2.0.3 - resolution: "resolve.imports@npm:2.0.3" - dependencies: - pattern-key-compare: ^2.0.0 - checksum: 155ae4a32ccc1da7ad12b88f6c748dd1e038092838e537de1066248c32a197b42489810da6070bb2bd0dd954e8abbe841b09282c0806c5493b2e49e8f7e29632 +"resolve.exports@npm:^2.0.0": + version: 2.0.0 + resolution: "resolve.exports@npm:2.0.0" + checksum: d8bee3b0cc0a0ae6c8323710983505bc6a3a2574f718e96f01e048a0f0af035941434b386cc9efc7eededc5e1199726185c306ec6f6a1aa55d5fbad926fd0634 languageName: node linkType: hard