Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use resolve package in jest-resolve #9520

Merged
merged 2 commits into from Feb 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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,
thymikee marked this conversation as resolved.
Show resolved Hide resolved
});
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