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

Feature/internal resolve #4315

Merged
merged 20 commits into from
Aug 22, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
e19e946
Pull resolve.sync code directly into default_resolver. (incomplete)
tvald Aug 21, 2017
f8e02f3
Strip out extraneous core and caller dependencies.
tvald Aug 21, 2017
a80d267
Pull node-modules-path into codebase as well. (incomplete)
tvald Aug 21, 2017
a4f2641
Remove dependency on path-parse. Assume existence of path.parse (adde…
tvald Aug 21, 2017
b0dd695
Use internal resolve within default_resolver.
tvald Aug 21, 2017
5593152
Adhere to linter constraints.
tvald Aug 21, 2017
08bc70d
Extend basic error type with code property.
tvald Aug 21, 2017
942ddc7
Fix typing and remove extraneous options.
tvald Aug 21, 2017
d10676a
Gather helper methods at end of resolveSync().
tvald Aug 21, 2017
d15ec91
Rename "start" parameter to more obvious "basedir".
tvald Aug 21, 2017
24e9b18
Avoid shadowing basedir variable.
tvald Aug 21, 2017
7e46c07
Inline loadNodeModulesSync() method.
tvald Aug 21, 2017
73ccd44
Clarify relative import vs node_modules.
tvald Aug 21, 2017
513f1d2
Use import instead of require.
tvald Aug 21, 2017
e625b8a
Small logic and formatting simplifications.
tvald Aug 21, 2017
eb980f3
Use isBuiltinModule() to detect core modules. Restore use of moduleDi…
tvald Aug 21, 2017
b046899
Remove package dependency on resolve.
tvald Aug 21, 2017
580f0c8
Make node_modules_paths available to resolver core logic, rather than…
tvald Aug 21, 2017
3313380
Add standard header to node_modules_paths.js. Add adaptation note to …
tvald Aug 21, 2017
de104b0
Trim out unused options when calling nodeModulesPaths().
tvald Aug 22, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions packages/jest-resolve/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
"dependencies": {
"browser-resolve": "^1.11.2",
"chalk": "^2.0.1",
"is-builtin-module": "^1.0.0",
"resolve": "^1.3.2"
"is-builtin-module": "^1.0.0"
},
"devDependencies": {
"jest-haste-map": "^20.0.4"
Expand Down
98 changes: 94 additions & 4 deletions packages/jest-resolve/src/default_resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

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

import resolve from 'resolve';
import browserResolve from 'browser-resolve';

type ResolverOptions = {|
Expand All @@ -21,10 +20,10 @@ type ResolverOptions = {|
paths?: ?Array<Path>,
|};

function defaultResolver(path: Path, options: ResolverOptions) {
const resv = options.browser ? browserResolve : resolve;
function defaultResolver(path: Path, options: ResolverOptions): Path {
const resolve = options.browser ? browserResolve.sync : resolveSync;

return resv.sync(path, {
return resolve(path, {
basedir: options.basedir,
extensions: options.extensions,
moduleDirectory: options.moduleDirectory,
Expand All @@ -33,3 +32,94 @@ function defaultResolver(path: Path, options: ResolverOptions) {
}

module.exports = defaultResolver;

/*
* Adapted from: https://github.com/substack/node-resolve
*/
type ErrorWithCode = Error & {code?: string};

import fs from 'fs';
import path from 'path';
import isBuiltinModule from 'is-builtin-module';

import nodeModulesPaths from './node_modules_paths';

const REGEX_RELATIVE_IMPORT = /^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[\\\/])/;

function resolveSync(x: Path, options: ResolverOptions): Path {
const readFileSync = fs.readFileSync;

const extensions = options.extensions || ['.js'];
const basedir = options.basedir;

options.paths = options.paths || [];

if (REGEX_RELATIVE_IMPORT.test(x)) {
// resolve relative import
let target = path.resolve(basedir, x);
if (x === '..') target += '/';
const m = loadAsFileSync(target) || loadAsDirectorySync(target);
if (m) return m;
} else {
// otherwise search for node_modules
const dirs = nodeModulesPaths(basedir, {
moduleDirectory: options.moduleDirectory,
paths: options.paths,
});
for (let i = 0; i < dirs.length; i++) {
const dir = dirs[i];
const target = path.join(dir, '/', x);
const m = loadAsFileSync(target) || loadAsDirectorySync(target);
if (m) return m;
}
}

if (isBuiltinModule(x)) return x;

const err: ErrorWithCode = new Error(
"Cannot find module '" + x + "' from '" + basedir + "'",
);
err.code = 'MODULE_NOT_FOUND';
throw err;

/*
* helper functions
*/
function isFile(file: Path): boolean {
try {
const stat = fs.statSync(file);
return stat.isFile() || stat.isFIFO();
} catch (e) {
if (e && e.code === 'ENOENT') return false;
throw e;
}
}

function loadAsFileSync(x: Path): ?Path {
if (isFile(x)) return x;

for (let i = 0; i < extensions.length; i++) {
const file = x + extensions[i];
if (isFile(file)) return file;
}

return undefined;
}

function loadAsDirectorySync(x: Path): ?Path {
const pkgfile = path.join(x, '/package.json');
if (isFile(pkgfile)) {
const body = readFileSync(pkgfile, 'utf8');
try {
const pkgmain = JSON.parse(body).main;
if (pkgmain) {
const target = path.resolve(x, pkgmain);
const m = loadAsFileSync(target) || loadAsDirectorySync(target);
if (m) return m;
}
} catch (e) {}
}

return loadAsFileSync(path.join(x, '/index'));
}
}
2 changes: 1 addition & 1 deletion packages/jest-resolve/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type {ResolveModuleConfig} from 'types/Resolve';

import fs from 'fs';
import path from 'path';
import nodeModulesPaths from 'resolve/lib/node-modules-paths';
import nodeModulesPaths from './node_modules_paths';
import isBuiltinModule from 'is-builtin-module';
import defaultResolver from './default_resolver.js';
import chalk from 'chalk';
Expand Down
59 changes: 59 additions & 0 deletions packages/jest-resolve/src/node_modules_paths.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* Copyright (c) 2014, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* Adapted from: https://github.com/substack/node-resolve
*
* @flow
*/

import type {Path} from 'types/Config';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add the copyright header just like in other files?
Also, since it's adapted from resolve, an extra annotation is necessary:

 /**
  * Copyright (c) 2014, Facebook, Inc. All rights reserved.
  *
  * This source code is licensed under the BSD-style license found in the
  * LICENSE file in the root directory of this source tree. An additional grant
  * of patent rights can be found in the PATENTS file in the same directory.
  *
  * Adapted from: https://github.com/substack/node-resolve
  * 
  * @flow
  */

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 3313380

import path from 'path';

type NodeModulesPathsOptions = {|
moduleDirectory?: Array<string>,
paths?: ?Array<Path>,
|};

function nodeModulesPaths(
basedir: Path,
options: NodeModulesPathsOptions,
): Path[] {
const modules =
options && options.moduleDirectory
? [].concat(options.moduleDirectory)
: ['node_modules'];

// ensure that `basedir` is an absolute path at this point,
// resolving against the process' current working directory
const basedirAbs = path.resolve(basedir);

let prefix = '/';
if (/^([A-Za-z]:)/.test(basedirAbs)) {
prefix = '';
} else if (/^\\\\/.test(basedirAbs)) {
prefix = '\\\\';
}

const paths = [basedirAbs];
let parsed = path.parse(basedirAbs);
while (parsed.dir !== paths[paths.length - 1]) {
paths.push(parsed.dir);
parsed = path.parse(parsed.dir);
}

const dirs = paths.reduce((dirs, aPath) => {
return dirs.concat(
modules.map(moduleDir => {
return path.join(prefix, aPath, moduleDir);
}),
);
}, []);

return options.paths ? dirs.concat(options.paths) : dirs;
}

module.exports = nodeModulesPaths;