From 3113dedca90b3be88cf1f31f564a7ee7ace23502 Mon Sep 17 00:00:00 2001 From: Sergio Cinos Date: Tue, 11 Aug 2020 15:59:52 +0200 Subject: [PATCH 1/8] [iest-resolve] Add support for `packageFilter` for custom resolvers --- docs/Configuration.md | 3 ++- packages/jest-resolve/src/defaultResolver.ts | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index 406f48fa493f..06c40fc55ec8 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -693,7 +693,8 @@ This option allows the use of a custom resolver. This resolver must be a node mo "extensions": [string], "moduleDirectory": [string], "paths": [string], - "rootDir": [string] + "packageFilter": "function(pkg, pkgdir)", + "rootDir": [string], } ``` diff --git a/packages/jest-resolve/src/defaultResolver.ts b/packages/jest-resolve/src/defaultResolver.ts index 6febcba33d3b..87d18238782c 100644 --- a/packages/jest-resolve/src/defaultResolver.ts +++ b/packages/jest-resolve/src/defaultResolver.ts @@ -20,6 +20,7 @@ type ResolverOptions = { moduleDirectory?: Array; paths?: Array; rootDir?: Config.Path; + packageFilter?: (pkg: any, pkgfile: string) => any; }; declare global { @@ -45,6 +46,7 @@ export default function defaultResolver( isDirectory, isFile, moduleDirectory: options.moduleDirectory, + packageFilter: options.packageFilter, paths: options.paths, preserveSymlinks: false, realpathSync, From 6bae80cf1354dccc55bb5ef0d48b0c9447350e4d Mon Sep 17 00:00:00 2001 From: Sergio Cinos Date: Tue, 11 Aug 2020 16:24:44 +0200 Subject: [PATCH 2/8] Fix lint problem in Configuration.md --- docs/Configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index 06c40fc55ec8..7f0377060d9f 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -694,7 +694,7 @@ This option allows the use of a custom resolver. This resolver must be a node mo "moduleDirectory": [string], "paths": [string], "packageFilter": "function(pkg, pkgdir)", - "rootDir": [string], + "rootDir": [string] } ``` From 4f0ecc706e1d36556241318d9c8d34a63c7542b1 Mon Sep 17 00:00:00 2001 From: Sergio Cinos Date: Tue, 11 Aug 2020 16:26:10 +0200 Subject: [PATCH 3/8] Adds entry in changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 093d3cc6a965..ea522cebb042 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Features +- `[jest-resolve]` Add support for `packageFilter` on custom resolver ([#10393](https://github.com/facebook/jest/pull/10393)) + ### Fixes ### Chore & Maintenance From 66335e082f9a9704896837488aa2654e96155aad Mon Sep 17 00:00:00 2001 From: Sergio Cinos Date: Tue, 11 Aug 2020 23:03:01 +0200 Subject: [PATCH 4/8] Add example on how to use `packageFilter` --- docs/Configuration.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/Configuration.md b/docs/Configuration.md index 7f0377060d9f..ac857952fb24 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -713,6 +713,38 @@ For example, if you want to respect Browserify's [`"browser"` field](https://git } ``` +By combining `defaultResolver` and `packageFilter` we can implement a `package.json` "pre-processor" that allows us to change how the default resolver will resolve modules. For example, imagine we want to use the field `"module"` if it is present, otherwise fallback to `"main"`: + +```json +{ + ... + "jest": { + "resolver": "my-module-resolve" + } +} +``` + +```js +// my-module-resolve package + +module.exports = (request, options) => { + // Call the defaultResolver, so we leverage its cache, error handling, etc. + return options.defaultResolver(request, { + ...options, + ...{ + // Use packageFilter to process parsed `package.json` before the resolution (see https://www.npmjs.com/package/resolve#resolveid-opts-cb) + packageFilter: pkg => { + return { + ...pkg, + // Alter the value of `main` before resolving the package + main: pkg.module || pkg.main, + }; + }, + }, + }); +}; +``` + ### `restoreMocks` [boolean] Default: `false` From 141887ee48e925b57511db2ebcf487d42a181a66 Mon Sep 17 00:00:00 2001 From: Sergio Cinos Date: Tue, 11 Aug 2020 23:05:49 +0200 Subject: [PATCH 5/8] Pull packageFilter type from "resolve" --- packages/jest-resolve/src/defaultResolver.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/jest-resolve/src/defaultResolver.ts b/packages/jest-resolve/src/defaultResolver.ts index 87d18238782c..b40754b5f349 100644 --- a/packages/jest-resolve/src/defaultResolver.ts +++ b/packages/jest-resolve/src/defaultResolver.ts @@ -10,6 +10,7 @@ import {sync as resolveSync} from 'resolve'; import pnpResolver from 'jest-pnp-resolver'; import {tryRealpath} from 'jest-util'; import type {Config} from '@jest/types'; +import type {Opts as ResolveOpts} from 'resolve'; type ResolverOptions = { allowPnp?: boolean; @@ -20,7 +21,7 @@ type ResolverOptions = { moduleDirectory?: Array; paths?: Array; rootDir?: Config.Path; - packageFilter?: (pkg: any, pkgfile: string) => any; + packageFilter?: ResolveOpts['packageFilter']; }; declare global { From 8325c0e25990b07d099378ac9f6451b6c9c57ba3 Mon Sep 17 00:00:00 2001 From: Sergio Cinos Date: Wed, 12 Aug 2020 00:16:21 +0200 Subject: [PATCH 6/8] Add tests for packageFilter support --- .../src/__tests__/resolve.test.ts | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/packages/jest-resolve/src/__tests__/resolve.test.ts b/packages/jest-resolve/src/__tests__/resolve.test.ts index 75f1125697fb..822cdede4d2d 100644 --- a/packages/jest-resolve/src/__tests__/resolve.test.ts +++ b/packages/jest-resolve/src/__tests__/resolve.test.ts @@ -9,6 +9,7 @@ import * as path from 'path'; import * as fs from 'graceful-fs'; import {ModuleMap} from 'jest-haste-map'; +import {sync as resolveSync} from 'resolve'; import Resolver = require('../'); import userResolver from '../__mocks__/userResolver'; import nodeModulesPaths from '../nodeModulesPaths'; @@ -17,8 +18,23 @@ import type {ResolverConfig} from '../types'; jest.mock('../__mocks__/userResolver'); +// Do not fully mock `resolve` because it is used by Jest. Doing it will crash +// in very strange ways. Instead just spy on the method `sync`. +jest.mock('resolve', () => { + const originalModule = jest.requireActual('resolve'); + return { + ...originalModule, + sync: jest.spyOn(originalModule, 'sync'), + }; +}); + +const mockResolveSync = < + jest.Mock, Parameters> +>resolveSync; + beforeEach(() => { userResolver.mockClear(); + mockResolveSync.mockClear(); }); describe('isCoreModule', () => { @@ -93,6 +109,27 @@ describe('findNodeModule', () => { rootDir: undefined, }); }); + + it('passes packageFilter to the resolve module when using the default resolver', () => { + const packageFilter = jest.fn(); + + // A resolver that delegates to defaultResolver with a packageFilter implementation + userResolver.mockImplementation((request, opts) => + opts.defaultResolver(request, {...opts, packageFilter}), + ); + + Resolver.findNodeModule('test', { + basedir: '/', + resolver: require.resolve('../__mocks__/userResolver'), + }); + + expect(mockResolveSync).toHaveBeenCalledWith( + 'test', + expect.objectContaining({ + packageFilter, + }), + ); + }); }); describe('resolveModule', () => { From e981f8f1f0ec2e7cc13c645632837dcd5b0388a2 Mon Sep 17 00:00:00 2001 From: Sergio Cinos Date: Wed, 12 Aug 2020 00:23:58 +0200 Subject: [PATCH 7/8] Simplify example --- docs/Configuration.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index ac857952fb24..0a43c9b9412f 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -731,15 +731,13 @@ module.exports = (request, options) => { // Call the defaultResolver, so we leverage its cache, error handling, etc. return options.defaultResolver(request, { ...options, - ...{ - // Use packageFilter to process parsed `package.json` before the resolution (see https://www.npmjs.com/package/resolve#resolveid-opts-cb) - packageFilter: pkg => { - return { - ...pkg, - // Alter the value of `main` before resolving the package - main: pkg.module || pkg.main, - }; - }, + // Use packageFilter to process parsed `package.json` before the resolution (see https://www.npmjs.com/package/resolve#resolveid-opts-cb) + packageFilter: pkg => { + return { + ...pkg, + // Alter the value of `main` before resolving the package + main: pkg.module || pkg.main, + }; }, }); }; From b1dd18a6ef27030c7732056e8cfbc284e4075291 Mon Sep 17 00:00:00 2001 From: Sergio Cinos Date: Wed, 12 Aug 2020 22:35:44 +0200 Subject: [PATCH 8/8] Import from `resolve` just once --- packages/jest-resolve/src/defaultResolver.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/jest-resolve/src/defaultResolver.ts b/packages/jest-resolve/src/defaultResolver.ts index b40754b5f349..c925ae8fe3b0 100644 --- a/packages/jest-resolve/src/defaultResolver.ts +++ b/packages/jest-resolve/src/defaultResolver.ts @@ -6,11 +6,10 @@ */ import * as fs from 'graceful-fs'; -import {sync as resolveSync} from 'resolve'; +import {Opts as ResolveOpts, sync as resolveSync} from 'resolve'; import pnpResolver from 'jest-pnp-resolver'; import {tryRealpath} from 'jest-util'; import type {Config} from '@jest/types'; -import type {Opts as ResolveOpts} from 'resolve'; type ResolverOptions = { allowPnp?: boolean;