From 1d0d8ba8169808d0e07c56c2e74d48b373b10fc1 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Wed, 5 Feb 2020 20:38:36 +0100 Subject: [PATCH] feat: use `resolve` package in `jest-resolve` (#9520) --- CHANGELOG.md | 3 +- packages/jest-resolve/package.json | 4 +- .../src/__mocks__/userResolver.js | 1 - .../src/__tests__/resolve.test.ts | 6 +- packages/jest-resolve/src/defaultResolver.ts | 127 +++--------------- yarn.lock | 2 +- 6 files changed, 25 insertions(+), 118 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e109d49082a4..e568389dd809 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,9 +16,10 @@ ### Chore & Maintenance +- `[docs]` Warn about unexpected behavior / bug of node-notifier when using the `notify` options. +- `[jest-resolver]` Use `resolve` package to implement custom module resolution ([#9520](https://github.com/facebook/jest/pull/9520)) - `[@jest/reporters]` Remove unused dependencies and type exports ([#9462](https://github.com/facebook/jest/pull/9462)) - `[website]` Update pictures of reports when matchers fail ([#9214](https://github.com/facebook/jest/pull/9214)) -- `[docs]` Warn about unexpected behavior / bug of node-notifier when using the `notify` options. ### Performance diff --git a/packages/jest-resolve/package.json b/packages/jest-resolve/package.json index 91009e37f6bd..c0b9da1a3b92 100644 --- a/packages/jest-resolve/package.json +++ b/packages/jest-resolve/package.json @@ -14,10 +14,12 @@ "browser-resolve": "^1.11.3", "chalk": "^3.0.0", "jest-pnp-resolver": "^1.2.1", - "realpath-native": "^2.0.0" + "realpath-native": "^2.0.0", + "resolve": "^1.15.0" }, "devDependencies": { "@types/browser-resolve": "^0.0.5", + "@types/resolve": "^1.14.0", "jest-haste-map": "^25.1.0" }, "engines": { diff --git a/packages/jest-resolve/src/__mocks__/userResolver.js b/packages/jest-resolve/src/__mocks__/userResolver.js index 9b702a30ffe4..3b8e4c10f327 100644 --- a/packages/jest-resolve/src/__mocks__/userResolver.js +++ b/packages/jest-resolve/src/__mocks__/userResolver.js @@ -3,7 +3,6 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * */ 'use strict'; diff --git a/packages/jest-resolve/src/__tests__/resolve.test.ts b/packages/jest-resolve/src/__tests__/resolve.test.ts index c136ba0e5c6d..077bd6513d8d 100644 --- a/packages/jest-resolve/src/__tests__/resolve.test.ts +++ b/packages/jest-resolve/src/__tests__/resolve.test.ts @@ -9,7 +9,7 @@ import * as fs from 'fs'; import * as path from 'path'; import {ModuleMap} from 'jest-haste-map'; -import Resolver from '../'; +import Resolver = require('../'); // @ts-ignore: js file import userResolver from '../__mocks__/userResolver'; import nodeModulesPaths from '../nodeModulesPaths'; @@ -83,7 +83,7 @@ describe('findNodeModule', () => { }); describe('resolveModule', () => { - let moduleMap: typeof ModuleMap; + let moduleMap: ModuleMap; beforeEach(() => { moduleMap = ModuleMap.create('/'); }); @@ -195,7 +195,7 @@ describe('nodeModulesPaths', () => { describe('Resolver.getModulePaths() -> nodeModulesPaths()', () => { const _path = path; - let moduleMap: typeof ModuleMap; + let moduleMap: ModuleMap; beforeEach(() => { jest.resetModules(); diff --git a/packages/jest-resolve/src/defaultResolver.ts b/packages/jest-resolve/src/defaultResolver.ts index 7dde191c71b5..cf9c28ec9bc6 100644 --- a/packages/jest-resolve/src/defaultResolver.ts +++ b/packages/jest-resolve/src/defaultResolver.ts @@ -6,14 +6,11 @@ */ import * as fs from 'fs'; -import * as path from 'path'; +import {sync as resolveSync} from 'resolve'; import {sync as browserResolve} from 'browser-resolve'; import {sync as realpath} from 'realpath-native'; import pnpResolver from 'jest-pnp-resolver'; import {Config} from '@jest/types'; -import isBuiltinModule from './isBuiltinModule'; -import nodeModulesPaths from './nodeModulesPaths'; -import ModuleNotFoundError from './ModuleNotFoundError'; type ResolverOptions = { basedir: Config.Path; @@ -36,120 +33,33 @@ export default function defaultResolver( const resolve = options.browser ? browserResolve : resolveSync; - let result = resolve(path, { + const result = resolve(path, { basedir: options.basedir, - defaultResolver, extensions: options.extensions, + isDirectory, + isFile, moduleDirectory: options.moduleDirectory, paths: options.paths, - rootDir: options.rootDir, + preserveSymlinks: false, }); - if (options.browser && result) { + + try { // Dereference symlinks to ensure we don't create a separate // module instance depending on how it was referenced. - result = realpath(result); - } - return result; -} + const resolved = realpath(result); -export const clearDefaultResolverCache = () => { - checkedPaths.clear(); -}; - -const REGEX_RELATIVE_IMPORT = /^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[\\\/])/; - -function resolveSync( - target: Config.Path, - options: ResolverOptions, -): Config.Path { - const basedir = options.basedir; - const extensions = options.extensions || ['.js']; - const paths = options.paths || []; - - if (REGEX_RELATIVE_IMPORT.test(target)) { - // resolve relative import - const resolveTarget = path.resolve(basedir, target); - const result = tryResolve(resolveTarget); - if (result) { - return result; - } - } else { - // otherwise search for node_modules - const dirs = nodeModulesPaths(basedir, { - moduleDirectory: options.moduleDirectory, - paths, - }); - for (let i = 0; i < dirs.length; i++) { - const resolveTarget = path.join(dirs[i], target); - const result = tryResolve(resolveTarget); - if (result) { - return result; - } + if (resolved) { + return resolved; } + } catch { + // ignore } - if (isBuiltinModule(target)) { - return target; - } - - throw new ModuleNotFoundError( - "Cannot find module '" + target + "' from '" + basedir + "'", - ); - - /* - * contextual helper functions - */ - function tryResolve(name: Config.Path): Config.Path | undefined { - const dir = path.dirname(name); - let result; - if (isDirectory(dir)) { - result = resolveAsFile(name) || resolveAsDirectory(name); - } - if (result) { - // Dereference symlinks to ensure we don't create a separate - // module instance depending on how it was referenced. - result = realpath(result); - } - return result; - } - - function resolveAsFile(name: Config.Path): Config.Path | undefined { - if (isFile(name)) { - return name; - } - - for (let i = 0; i < extensions.length; i++) { - const file = name + extensions[i]; - if (isFile(file)) { - return file; - } - } - - return undefined; - } - - function resolveAsDirectory(name: Config.Path): Config.Path | undefined { - if (!isDirectory(name)) { - return undefined; - } - - const pkgfile = path.join(name, 'package.json'); - let pkgmain; - try { - const body = fs.readFileSync(pkgfile, 'utf8'); - pkgmain = JSON.parse(body).main; - } catch (e) {} - - if (pkgmain && !isCurrentDirectory(pkgmain)) { - const resolveTarget = path.resolve(name, pkgmain); - const result = tryResolve(resolveTarget); - if (result) { - return result; - } - } + return result; +} - return resolveAsFile(path.join(name, 'index')); - } +export function clearDefaultResolverCache() { + checkedPaths.clear(); } enum IPathType { @@ -197,8 +107,3 @@ function isFile(file: Config.Path): boolean { function isDirectory(dir: Config.Path): boolean { return statSyncCached(dir) === IPathType.DIRECTORY; } - -const CURRENT_DIRECTORY = path.resolve('.'); -function isCurrentDirectory(testPath: Config.Path): boolean { - return CURRENT_DIRECTORY === path.resolve(testPath); -} diff --git a/yarn.lock b/yarn.lock index e9f45689142b..ea4eabb91a2b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2297,7 +2297,7 @@ "@types/prop-types" "*" csstype "^2.2.0" -"@types/resolve@*": +"@types/resolve@*", "@types/resolve@^1.14.0": version "1.14.0" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.14.0.tgz#c95d696264f8e53e764a7c0b83e9317b458b76c3" integrity sha512-bmjNBW6tok+67iOsASeYSJxSgY++BIR35nGyGLORTDirhra9reJ0shgGL3U7KPDUbOBCx8JrlCjd4d/y5uiMRQ==