Skip to content

Commit

Permalink
feat: use resolve package in jest-resolve (#9520)
Browse files Browse the repository at this point in the history
  • Loading branch information
SimenB committed Feb 5, 2020
1 parent c4ae594 commit 1d0d8ba
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 118 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Expand Up @@ -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

Expand Down
4 changes: 3 additions & 1 deletion packages/jest-resolve/package.json
Expand Up @@ -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": {
Expand Down
1 change: 0 additions & 1 deletion packages/jest-resolve/src/__mocks__/userResolver.js
Expand Up @@ -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';
Expand Down
6 changes: 3 additions & 3 deletions packages/jest-resolve/src/__tests__/resolve.test.ts
Expand Up @@ -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';
Expand Down Expand Up @@ -83,7 +83,7 @@ describe('findNodeModule', () => {
});

describe('resolveModule', () => {
let moduleMap: typeof ModuleMap;
let moduleMap: ModuleMap;
beforeEach(() => {
moduleMap = ModuleMap.create('/');
});
Expand Down Expand Up @@ -195,7 +195,7 @@ describe('nodeModulesPaths', () => {

describe('Resolver.getModulePaths() -> nodeModulesPaths()', () => {
const _path = path;
let moduleMap: typeof ModuleMap;
let moduleMap: ModuleMap;

beforeEach(() => {
jest.resetModules();
Expand Down
127 changes: 16 additions & 111 deletions packages/jest-resolve/src/defaultResolver.ts
Expand Up @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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);
}
2 changes: 1 addition & 1 deletion yarn.lock
Expand Up @@ -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==
Expand Down

0 comments on commit 1d0d8ba

Please sign in to comment.