diff --git a/copy.mjs b/copy.mjs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/jest-resolve/package.json b/packages/jest-resolve/package.json index d0bec260ddbb..f81d7e871099 100644 --- a/packages/jest-resolve/package.json +++ b/packages/jest-resolve/package.json @@ -17,7 +17,6 @@ "./package.json": "./package.json" }, "dependencies": { - "@okikio/resolve.imports": "^1.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "jest-haste-map": "workspace:^", @@ -26,6 +25,7 @@ "jest-validate": "workspace:^", "resolve": "^1.20.0", "resolve.exports": "^1.1.0", + "resolve.imports": "^2.0.0", "slash": "^3.0.0" }, "devDependencies": { diff --git a/packages/jest-resolve/src/__mocks__/imports/array-import/browser.cjs b/packages/jest-resolve/src/__mocks__/imports/array-import/browser.cjs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/jest-resolve/src/__mocks__/imports/array-import/node-2.mjs b/packages/jest-resolve/src/__mocks__/imports/array-import/node-2.mjs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/jest-resolve/src/__mocks__/imports/array-import/node.cjs b/packages/jest-resolve/src/__mocks__/imports/array-import/node.cjs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/jest-resolve/src/__mocks__/imports/array-import/package.json b/packages/jest-resolve/src/__mocks__/imports/array-import/package.json new file mode 100644 index 000000000000..87771ec171d6 --- /dev/null +++ b/packages/jest-resolve/src/__mocks__/imports/array-import/package.json @@ -0,0 +1,10 @@ +{ + "name": "array-import", + "imports": { + "#nested": { + "import": ["./node.mjs", "./node-2.mjs"], + "browser": ["./not-exist.cjs", "./browser.cjs"], + "require": ["not-exist-package", "./node.cjs"] + } + } +} diff --git a/packages/jest-resolve/src/__mocks__/imports/nested-import/browser.cjs b/packages/jest-resolve/src/__mocks__/imports/nested-import/browser.cjs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/jest-resolve/src/__mocks__/imports/nested-import/node.cjs b/packages/jest-resolve/src/__mocks__/imports/nested-import/node.cjs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/jest-resolve/src/__mocks__/imports/nested-import/node.mjs b/packages/jest-resolve/src/__mocks__/imports/nested-import/node.mjs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/jest-resolve/src/__mocks__/imports/nested-import/package.json b/packages/jest-resolve/src/__mocks__/imports/nested-import/package.json new file mode 100644 index 000000000000..d980fdacbc13 --- /dev/null +++ b/packages/jest-resolve/src/__mocks__/imports/nested-import/package.json @@ -0,0 +1,12 @@ +{ + "name": "nested-import", + "imports": { + "#nested": { + "node": { + "import": "./node.mjs", + "require": "./node.cjs" + }, + "default": "./browser.cjs" + } + } +} diff --git a/packages/jest-resolve/src/__tests__/resolve.test.ts b/packages/jest-resolve/src/__tests__/resolve.test.ts index d9c69dbc13e1..d9bcba08a0c8 100644 --- a/packages/jest-resolve/src/__tests__/resolve.test.ts +++ b/packages/jest-resolve/src/__tests__/resolve.test.ts @@ -345,6 +345,51 @@ describe('findNodeModule', () => { ); }); + test('supports nested pattern', () => { + const result = Resolver.findNodeModule('#nested', { + basedir: path.resolve(importsRoot, './nested-import/index.cjs'), + conditions: ['node', 'require'], + }); + + expect(result).toEqual( + path.resolve(importsRoot, './nested-import/node.cjs'), + ); + }); + + test('supports array pattern - resolve to first found', () => { + const result = Resolver.findNodeModule('#array-import', { + basedir: path.resolve(importsRoot, './array-import/index.cjs'), + conditions: ['import'], + }); + + expect(result).toEqual( + path.resolve(importsRoot, './array-import/node.mjs'), + ); + }); + + test('supports array pattern - ignore not exist internal file', () => { + const result = Resolver.findNodeModule('#array-import', { + basedir: path.resolve(importsRoot, './array-import/index.cjs'), + conditions: ['browser'], + }); + + expect(result).toEqual( + path.resolve(importsRoot, './array-import/browser.cjs'), + ); + }); + + test('supports array pattern - ignore not exist external module', () => { + // this is for optional dependency + const result = Resolver.findNodeModule('#array-import', { + basedir: path.resolve(importsRoot, './array-import/index.cjs'), + conditions: ['require'], + }); + + expect(result).toEqual( + path.resolve(importsRoot, './array-import/node.cjs'), + ); + }); + test('fails for non-existent mapping', () => { expect(() => { Resolver.findNodeModule('#something-else', { diff --git a/packages/jest-resolve/src/defaultResolver.ts b/packages/jest-resolve/src/defaultResolver.ts index bffa2ad9177f..4672c6ce6e41 100644 --- a/packages/jest-resolve/src/defaultResolver.ts +++ b/packages/jest-resolve/src/defaultResolver.ts @@ -6,13 +6,13 @@ */ import {dirname, isAbsolute, resolve as pathResolve} from 'path'; -import {resolve as resolveImports} from '@okikio/resolve.imports'; 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 { findClosestPackageJson, isDirectory, @@ -110,9 +110,7 @@ const defaultResolver: SyncResolver = (path, options) => { realpathSync, }; - const pathToResolve = getPathInModule(path, resolveOptions); - - const result = resolveSync(pathToResolve, resolveOptions); + const result = resolveByPathInModule(path, resolveOptions); // Dereference symlinks to ensure we don't create a separate // module instance depending on how it was referenced. @@ -129,7 +127,7 @@ function readPackageSync(_: unknown, file: string): PackageJSON { return readPackageCached(file); } -function getPathInModule( +function resolveByPathInModule( path: string, options: UpstreamResolveOptionsWithConditions, ): string { @@ -149,7 +147,11 @@ function getPathInModule( const pkg = readPackageCached(closestPackageJson); const resolved = resolveImports( - pkg, + { + base: options.basedir, + content: pkg, + path: closestPackageJson, + }, path, createResolveOptions(options.conditions), ); @@ -160,12 +162,25 @@ function getPathInModule( ); } - if (resolved.startsWith('.')) { - return pathResolve(dirname(closestPackageJson), resolved); + const resolvedValues = Array.isArray(resolved) ? resolved : [resolved]; + + for (const resolved of resolvedValues) { + const resolvedPath = resolveByPath(resolved); + try { + return resolveSync(resolvedPath, options); + } catch (e) { + continue; + } } - // this is an external module, re-resolve it - return defaultResolver(resolved, options); + function resolveByPath(resolved: string) { + if (resolved.startsWith('.')) { + return pathResolve(dirname(closestPackageJson!), resolved); + } + + // this is an external module, re-resolve it + return defaultResolver(resolved, options); + } } const segments = path.split('/'); diff --git a/yarn.lock b/yarn.lock index 8bfec085f959..17bad94bc1ce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3721,13 +3721,6 @@ __metadata: languageName: node linkType: hard -"@okikio/resolve.imports@npm:^1.0.0": - version: 1.0.0 - resolution: "@okikio/resolve.imports@npm:1.0.0" - checksum: a06d347731b3c47e79125d346dd0172fda3cf20d138249f4ed23c5cc60b32f668f9bbab49698fc061ef5782d236622ff4cd0ce2b2520550273e863f55b687350 - languageName: node - linkType: hard - "@pkgr/utils@npm:^2.3.1": version: 2.3.1 resolution: "@pkgr/utils@npm:2.3.1" @@ -12891,7 +12884,6 @@ __metadata: version: 0.0.0-use.local resolution: "jest-resolve@workspace:packages/jest-resolve" dependencies: - "@okikio/resolve.imports": ^1.0.0 "@tsd/typescript": ^4.9.0 "@types/graceful-fs": ^4.1.3 "@types/pnpapi": ^0.0.2 @@ -12904,6 +12896,7 @@ __metadata: jest-validate: "workspace:^" resolve: ^1.20.0 resolve.exports: ^1.1.0 + resolve.imports: ^2.0.0 slash: ^3.0.0 tsd-lite: ^0.6.0 languageName: unknown @@ -16422,6 +16415,13 @@ __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" @@ -18366,6 +18366,15 @@ __metadata: languageName: node linkType: hard +"resolve.imports@npm:^2.0.0": + version: 2.0.0 + resolution: "resolve.imports@npm:2.0.0" + dependencies: + pattern-key-compare: ^2.0.0 + checksum: ad914fcd84f656888ada484a45f4ff09429b99cd896a4a4a28bbc0676a795a528a7760125e297951d8b314584fb72da428a09d0e7f1d60d4d48bfb093d996609 + languageName: node + linkType: hard + "resolve@npm:^1.1.6, resolve@npm:^1.10.0, resolve@npm:^1.14.2, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.0, resolve@npm:^1.3.2": version: 1.22.1 resolution: "resolve@npm:1.22.1"