Skip to content

Commit 4a8b767

Browse files
tvaldcpojer
authored andcommitted
Feature/internal resolve (#4315)
* Pull resolve.sync code directly into default_resolver. (incomplete) * Strip out extraneous core and caller dependencies. * Pull node-modules-path into codebase as well. (incomplete) * Remove dependency on path-parse. Assume existence of path.parse (added in v0.11.15). * Use internal resolve within default_resolver. * Adhere to linter constraints. * Extend basic error type with code property. * Fix typing and remove extraneous options. * Gather helper methods at end of resolveSync(). * Rename "start" parameter to more obvious "basedir". * Avoid shadowing basedir variable. * Inline loadNodeModulesSync() method. * Clarify relative import vs node_modules. * Use import instead of require. * Small logic and formatting simplifications. * Use isBuiltinModule() to detect core modules. Restore use of moduleDirectory option. * Remove package dependency on resolve. * Make node_modules_paths available to resolver core logic, rather than just default_resolver. * Add standard header to node_modules_paths.js. Add adaptation note to default_resolver.js. * Trim out unused options when calling nodeModulesPaths().
1 parent ea37e10 commit 4a8b767

4 files changed

Lines changed: 155 additions & 7 deletions

File tree

packages/jest-resolve/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010
"dependencies": {
1111
"browser-resolve": "^1.11.2",
1212
"chalk": "^2.0.1",
13-
"is-builtin-module": "^1.0.0",
14-
"resolve": "^1.3.2"
13+
"is-builtin-module": "^1.0.0"
1514
},
1615
"devDependencies": {
1716
"jest-haste-map": "^20.0.4"

packages/jest-resolve/src/default_resolver.js

Lines changed: 94 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
import type {Path} from 'types/Config';
1212

13-
import resolve from 'resolve';
1413
import browserResolve from 'browser-resolve';
1514

1615
type ResolverOptions = {|
@@ -21,10 +20,10 @@ type ResolverOptions = {|
2120
paths?: ?Array<Path>,
2221
|};
2322

24-
function defaultResolver(path: Path, options: ResolverOptions) {
25-
const resv = options.browser ? browserResolve : resolve;
23+
function defaultResolver(path: Path, options: ResolverOptions): Path {
24+
const resolve = options.browser ? browserResolve.sync : resolveSync;
2625

27-
return resv.sync(path, {
26+
return resolve(path, {
2827
basedir: options.basedir,
2928
extensions: options.extensions,
3029
moduleDirectory: options.moduleDirectory,
@@ -33,3 +32,94 @@ function defaultResolver(path: Path, options: ResolverOptions) {
3332
}
3433

3534
module.exports = defaultResolver;
35+
36+
/*
37+
* Adapted from: https://github.com/substack/node-resolve
38+
*/
39+
type ErrorWithCode = Error & {code?: string};
40+
41+
import fs from 'fs';
42+
import path from 'path';
43+
import isBuiltinModule from 'is-builtin-module';
44+
45+
import nodeModulesPaths from './node_modules_paths';
46+
47+
const REGEX_RELATIVE_IMPORT = /^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[\\\/])/;
48+
49+
function resolveSync(x: Path, options: ResolverOptions): Path {
50+
const readFileSync = fs.readFileSync;
51+
52+
const extensions = options.extensions || ['.js'];
53+
const basedir = options.basedir;
54+
55+
options.paths = options.paths || [];
56+
57+
if (REGEX_RELATIVE_IMPORT.test(x)) {
58+
// resolve relative import
59+
let target = path.resolve(basedir, x);
60+
if (x === '..') target += '/';
61+
const m = loadAsFileSync(target) || loadAsDirectorySync(target);
62+
if (m) return m;
63+
} else {
64+
// otherwise search for node_modules
65+
const dirs = nodeModulesPaths(basedir, {
66+
moduleDirectory: options.moduleDirectory,
67+
paths: options.paths,
68+
});
69+
for (let i = 0; i < dirs.length; i++) {
70+
const dir = dirs[i];
71+
const target = path.join(dir, '/', x);
72+
const m = loadAsFileSync(target) || loadAsDirectorySync(target);
73+
if (m) return m;
74+
}
75+
}
76+
77+
if (isBuiltinModule(x)) return x;
78+
79+
const err: ErrorWithCode = new Error(
80+
"Cannot find module '" + x + "' from '" + basedir + "'",
81+
);
82+
err.code = 'MODULE_NOT_FOUND';
83+
throw err;
84+
85+
/*
86+
* helper functions
87+
*/
88+
function isFile(file: Path): boolean {
89+
try {
90+
const stat = fs.statSync(file);
91+
return stat.isFile() || stat.isFIFO();
92+
} catch (e) {
93+
if (e && e.code === 'ENOENT') return false;
94+
throw e;
95+
}
96+
}
97+
98+
function loadAsFileSync(x: Path): ?Path {
99+
if (isFile(x)) return x;
100+
101+
for (let i = 0; i < extensions.length; i++) {
102+
const file = x + extensions[i];
103+
if (isFile(file)) return file;
104+
}
105+
106+
return undefined;
107+
}
108+
109+
function loadAsDirectorySync(x: Path): ?Path {
110+
const pkgfile = path.join(x, '/package.json');
111+
if (isFile(pkgfile)) {
112+
const body = readFileSync(pkgfile, 'utf8');
113+
try {
114+
const pkgmain = JSON.parse(body).main;
115+
if (pkgmain) {
116+
const target = path.resolve(x, pkgmain);
117+
const m = loadAsFileSync(target) || loadAsDirectorySync(target);
118+
if (m) return m;
119+
}
120+
} catch (e) {}
121+
}
122+
123+
return loadAsFileSync(path.join(x, '/index'));
124+
}
125+
}

packages/jest-resolve/src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import type {ResolveModuleConfig} from 'types/Resolve';
1414

1515
import fs from 'fs';
1616
import path from 'path';
17-
import nodeModulesPaths from 'resolve/lib/node-modules-paths';
17+
import nodeModulesPaths from './node_modules_paths';
1818
import isBuiltinModule from 'is-builtin-module';
1919
import defaultResolver from './default_resolver.js';
2020
import chalk from 'chalk';
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
* Copyright (c) 2014, Facebook, Inc. All rights reserved.
3+
*
4+
* This source code is licensed under the BSD-style license found in the
5+
* LICENSE file in the root directory of this source tree. An additional grant
6+
* of patent rights can be found in the PATENTS file in the same directory.
7+
*
8+
* Adapted from: https://github.com/substack/node-resolve
9+
*
10+
* @flow
11+
*/
12+
13+
import type {Path} from 'types/Config';
14+
import path from 'path';
15+
16+
type NodeModulesPathsOptions = {|
17+
moduleDirectory?: Array<string>,
18+
paths?: ?Array<Path>,
19+
|};
20+
21+
function nodeModulesPaths(
22+
basedir: Path,
23+
options: NodeModulesPathsOptions,
24+
): Path[] {
25+
const modules =
26+
options && options.moduleDirectory
27+
? [].concat(options.moduleDirectory)
28+
: ['node_modules'];
29+
30+
// ensure that `basedir` is an absolute path at this point,
31+
// resolving against the process' current working directory
32+
const basedirAbs = path.resolve(basedir);
33+
34+
let prefix = '/';
35+
if (/^([A-Za-z]:)/.test(basedirAbs)) {
36+
prefix = '';
37+
} else if (/^\\\\/.test(basedirAbs)) {
38+
prefix = '\\\\';
39+
}
40+
41+
const paths = [basedirAbs];
42+
let parsed = path.parse(basedirAbs);
43+
while (parsed.dir !== paths[paths.length - 1]) {
44+
paths.push(parsed.dir);
45+
parsed = path.parse(parsed.dir);
46+
}
47+
48+
const dirs = paths.reduce((dirs, aPath) => {
49+
return dirs.concat(
50+
modules.map(moduleDir => {
51+
return path.join(prefix, aPath, moduleDir);
52+
}),
53+
);
54+
}, []);
55+
56+
return options.paths ? dirs.concat(options.paths) : dirs;
57+
}
58+
59+
module.exports = nodeModulesPaths;

0 commit comments

Comments
 (0)