From c857018ce4f91ce594683d0d4d18534127438a14 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Fri, 1 Oct 2021 13:55:37 +0200 Subject: [PATCH] feat: support `.` in `exports` field --- e2e/resolve-conditions/resolver.js | 4 +- packages/jest-resolve/package.json | 1 + .../conditions/node_modules/import/file.js | 0 .../node_modules/import/package.json | 6 +++ .../conditions/node_modules/main/file.js | 0 .../conditions/node_modules/main/package.json | 4 ++ .../conditions/node_modules/require/file.js | 0 .../node_modules/require/package.json | 6 +++ .../src/__tests__/resolve.test.ts | 37 +++++++++++++++++++ packages/jest-resolve/src/defaultResolver.ts | 34 +++++++++++++++++ yarn.lock | 8 ++++ 11 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 packages/jest-resolve/src/__mocks__/conditions/node_modules/import/file.js create mode 100644 packages/jest-resolve/src/__mocks__/conditions/node_modules/import/package.json create mode 100644 packages/jest-resolve/src/__mocks__/conditions/node_modules/main/file.js create mode 100644 packages/jest-resolve/src/__mocks__/conditions/node_modules/main/package.json create mode 100644 packages/jest-resolve/src/__mocks__/conditions/node_modules/require/file.js create mode 100644 packages/jest-resolve/src/__mocks__/conditions/node_modules/require/package.json diff --git a/e2e/resolve-conditions/resolver.js b/e2e/resolve-conditions/resolver.js index 98c8aed1bf67..fe2665e71798 100644 --- a/e2e/resolve-conditions/resolver.js +++ b/e2e/resolve-conditions/resolver.js @@ -25,10 +25,10 @@ function createPathFilter(conditions) { return ( resolveExports(pkg, path, { - // `resolve.exports adds `node` unless `browser` is `false`, so let's add this ugly thing + // `resolve.exports` adds `node` unless `browser` is `true`, so let's add this ugly thing browser: conditions.includes('browser'), conditions, - // `resolve.exports adds `import` unless `require` is `false`, so let's add this ugly thing + // `resolve.exports` adds `import` unless `require` is `true`, so let's add this ugly thing require: conditions.includes('require'), }) || relativePath ); diff --git a/packages/jest-resolve/package.json b/packages/jest-resolve/package.json index 725ed4b83cf5..a318305de4ff 100644 --- a/packages/jest-resolve/package.json +++ b/packages/jest-resolve/package.json @@ -23,6 +23,7 @@ "jest-util": "^27.2.4", "jest-validate": "^27.2.4", "resolve": "^1.20.0", + "resolve.exports": "^1.0.2", "slash": "^3.0.0" }, "devDependencies": { diff --git a/packages/jest-resolve/src/__mocks__/conditions/node_modules/import/file.js b/packages/jest-resolve/src/__mocks__/conditions/node_modules/import/file.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/jest-resolve/src/__mocks__/conditions/node_modules/import/package.json b/packages/jest-resolve/src/__mocks__/conditions/node_modules/import/package.json new file mode 100644 index 000000000000..24fc72b1cac7 --- /dev/null +++ b/packages/jest-resolve/src/__mocks__/conditions/node_modules/import/package.json @@ -0,0 +1,6 @@ +{ + "name": "import", + "exports": { + "import": "./file.js" + } +} diff --git a/packages/jest-resolve/src/__mocks__/conditions/node_modules/main/file.js b/packages/jest-resolve/src/__mocks__/conditions/node_modules/main/file.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/jest-resolve/src/__mocks__/conditions/node_modules/main/package.json b/packages/jest-resolve/src/__mocks__/conditions/node_modules/main/package.json new file mode 100644 index 000000000000..18b48565f56a --- /dev/null +++ b/packages/jest-resolve/src/__mocks__/conditions/node_modules/main/package.json @@ -0,0 +1,4 @@ +{ + "name": "main", + "main": "./file.js" +} diff --git a/packages/jest-resolve/src/__mocks__/conditions/node_modules/require/file.js b/packages/jest-resolve/src/__mocks__/conditions/node_modules/require/file.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/jest-resolve/src/__mocks__/conditions/node_modules/require/package.json b/packages/jest-resolve/src/__mocks__/conditions/node_modules/require/package.json new file mode 100644 index 000000000000..c42b33ecca86 --- /dev/null +++ b/packages/jest-resolve/src/__mocks__/conditions/node_modules/require/package.json @@ -0,0 +1,6 @@ +{ + "name": "require", + "exports": { + "require": "./file.js" + } +} diff --git a/packages/jest-resolve/src/__tests__/resolve.test.ts b/packages/jest-resolve/src/__tests__/resolve.test.ts index cfbe99bc841d..baf5b9be06a8 100644 --- a/packages/jest-resolve/src/__tests__/resolve.test.ts +++ b/packages/jest-resolve/src/__tests__/resolve.test.ts @@ -146,6 +146,43 @@ describe('findNodeModule', () => { }), ); }); + + describe('conditions', () => { + const conditionsRoot = path.resolve(__dirname, '../__mocks__/conditions'); + + test('resolves without exports, just main', () => { + const result = Resolver.findNodeModule('main', { + basedir: conditionsRoot, + conditions: ['require'], + }); + + expect(result).toEqual( + path.resolve(conditionsRoot, './node_modules/main/file.js'), + ); + }); + + test('resolves with import', () => { + const result = Resolver.findNodeModule('import', { + basedir: conditionsRoot, + conditions: ['import'], + }); + + expect(result).toEqual( + path.resolve(conditionsRoot, './node_modules/import/file.js'), + ); + }); + + test('resolves with require', () => { + const result = Resolver.findNodeModule('require', { + basedir: conditionsRoot, + conditions: ['require'], + }); + + expect(result).toEqual( + path.resolve(conditionsRoot, './node_modules/require/file.js'), + ); + }); + }); }); describe('resolveModule', () => { diff --git a/packages/jest-resolve/src/defaultResolver.ts b/packages/jest-resolve/src/defaultResolver.ts index 79ea2976a848..f2c28ffcaddd 100644 --- a/packages/jest-resolve/src/defaultResolver.ts +++ b/packages/jest-resolve/src/defaultResolver.ts @@ -8,6 +8,10 @@ import * as fs from 'graceful-fs'; import pnpResolver from 'jest-pnp-resolver'; import {Opts as ResolveOpts, sync as resolveSync} from 'resolve'; +import { + Options as ResolveExportsOptions, + resolve as resolveExports, +} from 'resolve.exports'; import type {Config} from '@jest/types'; import {tryRealpath} from 'jest-util'; @@ -43,6 +47,8 @@ export default function defaultResolver( ...options, isDirectory, isFile, + packageFilter: + options.packageFilter ?? createPackageFilter(options.conditions), preserveSymlinks: false, readPackageSync, realpathSync, @@ -149,3 +155,31 @@ function realpathSync(file: Config.Path): Config.Path { function readPackageSync(_: unknown, file: Config.Path): PkgJson { return readPackageCached(file); } + +function createPackageFilter(conditions?: Array) { + const options: ResolveExportsOptions = conditions + ? { + // `resolve.exports` adds `node` unless `browser` is `true`, so let's add this ugly thing + browser: conditions.includes('browser'), + conditions, + // `resolve.exports` adds `import` unless `require` is `true`, so let's add this ugly thing + require: conditions.includes('require'), + } + : // no conditions were passed - let's assume this is Jest internal and it should be `require` + {browser: false, require: true}; + + function attemptExportsFallback(pkg: PkgJson) { + try { + return resolveExports(pkg, '.', options); + } catch { + return undefined; + } + } + + return function packageFilter(pkg: PkgJson) { + return { + ...pkg, + main: pkg.main ?? attemptExportsFallback(pkg), + }; + }; +} diff --git a/yarn.lock b/yarn.lock index 6c85c0e5e11d..ac283eb12161 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13026,6 +13026,7 @@ fsevents@^1.2.7: jest-util: ^27.2.4 jest-validate: ^27.2.4 resolve: ^1.20.0 + resolve.exports: ^1.0.2 slash: ^3.0.0 languageName: unknown linkType: soft @@ -18944,6 +18945,13 @@ react-native@0.64.0: languageName: node linkType: hard +"resolve.exports@npm:^1.0.2": + version: 1.0.2 + resolution: "resolve.exports@npm:1.0.2" + checksum: 012a46e3ae41c53762abf5b50ea1b4adf2de617bbea1dbc7bf6e609c1ceaedee7782acbc92d443951d5dd0c3a8fb1090ce73285a9ccc24b530e33b5e09ae196f + languageName: node + linkType: hard + "resolve@^1.1.6, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.15.0, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.3.2": version: 1.20.0 resolution: "resolve@npm:1.20.0"