From e19e946cb36127b1bdd5f590cb07e1108695fbbf Mon Sep 17 00:00:00 2001 From: Tony Valderrama Date: Mon, 21 Aug 2017 11:36:30 -0700 Subject: [PATCH 01/20] Pull resolve.sync code directly into default_resolver. (incomplete) --- packages/jest-resolve/src/default_resolver.js | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/packages/jest-resolve/src/default_resolver.js b/packages/jest-resolve/src/default_resolver.js index a4799d07aeb1..338e87f86a72 100644 --- a/packages/jest-resolve/src/default_resolver.js +++ b/packages/jest-resolve/src/default_resolver.js @@ -33,3 +33,95 @@ function defaultResolver(path: Path, options: ResolverOptions) { } module.exports = defaultResolver; + +/** + * resolve logic, taken directly from resolve.sync + */ + +var core = require('./core'); +var fs = require('fs'); +var path = require('path'); +var caller = require('./caller.js'); +var nodeModulesPaths = require('./node-modules-paths.js'); + +function resolveSync(x, options) { + var opts = options || {}; + var isFile = opts.isFile || function (file) { + try { + var stat = fs.statSync(file); + } catch (e) { + if (e && e.code === 'ENOENT') return false; + throw e; + } + return stat.isFile() || stat.isFIFO(); + }; + var readFileSync = opts.readFileSync || fs.readFileSync; + + var extensions = opts.extensions || ['.js']; + var y = opts.basedir || path.dirname(caller()); + + opts.paths = opts.paths || []; + + if (/^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[\\\/])/.test(x)) { + var res = path.resolve(y, x); + if (x === '..') res += '/'; + var m = loadAsFileSync(res) || loadAsDirectorySync(res); + if (m) return m; + } else { + var n = loadNodeModulesSync(x, y); + if (n) return n; + } + + if (core[x]) return x; + + var err = new Error("Cannot find module '" + x + "' from '" + y + "'"); + err.code = 'MODULE_NOT_FOUND'; + throw err; + + function loadAsFileSync(x) { + if (isFile(x)) { + return x; + } + + for (var i = 0; i < extensions.length; i++) { + var file = x + extensions[i]; + if (isFile(file)) { + return file; + } + } + } + + function loadAsDirectorySync(x) { + var pkgfile = path.join(x, '/package.json'); + if (isFile(pkgfile)) { + var body = readFileSync(pkgfile, 'utf8'); + try { + var pkg = JSON.parse(body); + if (opts.packageFilter) { + pkg = opts.packageFilter(pkg, x); + } + + if (pkg.main) { + var m = loadAsFileSync(path.resolve(x, pkg.main)); + if (m) return m; + var n = loadAsDirectorySync(path.resolve(x, pkg.main)); + if (n) return n; + } + } catch (e) {} + } + + return loadAsFileSync(path.join(x, '/index')); + } + + function loadNodeModulesSync(x, start) { + var dirs = nodeModulesPaths(start, opts); + for (var i = 0; i < dirs.length; i++) { + var dir = dirs[i]; + var m = loadAsFileSync(path.join(dir, '/', x)); + if (m) return m; + var n = loadAsDirectorySync(path.join(dir, '/', x)); + if (n) return n; + } + } +}; + From f8e02f3d425727a0451b0b6344d5545a07f3029a Mon Sep 17 00:00:00 2001 From: Tony Valderrama Date: Mon, 21 Aug 2017 11:37:36 -0700 Subject: [PATCH 02/20] Strip out extraneous core and caller dependencies. --- packages/jest-resolve/src/default_resolver.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/jest-resolve/src/default_resolver.js b/packages/jest-resolve/src/default_resolver.js index 338e87f86a72..542d1f74bd8e 100644 --- a/packages/jest-resolve/src/default_resolver.js +++ b/packages/jest-resolve/src/default_resolver.js @@ -38,10 +38,8 @@ module.exports = defaultResolver; * resolve logic, taken directly from resolve.sync */ -var core = require('./core'); var fs = require('fs'); var path = require('path'); -var caller = require('./caller.js'); var nodeModulesPaths = require('./node-modules-paths.js'); function resolveSync(x, options) { @@ -58,7 +56,7 @@ function resolveSync(x, options) { var readFileSync = opts.readFileSync || fs.readFileSync; var extensions = opts.extensions || ['.js']; - var y = opts.basedir || path.dirname(caller()); + var y = opts.basedir; opts.paths = opts.paths || []; @@ -72,8 +70,6 @@ function resolveSync(x, options) { if (n) return n; } - if (core[x]) return x; - var err = new Error("Cannot find module '" + x + "' from '" + y + "'"); err.code = 'MODULE_NOT_FOUND'; throw err; From a80d26782a93e2b62add4e9e3d949eb73342fe0a Mon Sep 17 00:00:00 2001 From: Tony Valderrama Date: Mon, 21 Aug 2017 11:40:46 -0700 Subject: [PATCH 03/20] Pull node-modules-path into codebase as well. (incomplete) --- packages/jest-resolve/src/default_resolver.js | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/packages/jest-resolve/src/default_resolver.js b/packages/jest-resolve/src/default_resolver.js index 542d1f74bd8e..304bf83f2eac 100644 --- a/packages/jest-resolve/src/default_resolver.js +++ b/packages/jest-resolve/src/default_resolver.js @@ -40,7 +40,6 @@ module.exports = defaultResolver; var fs = require('fs'); var path = require('path'); -var nodeModulesPaths = require('./node-modules-paths.js'); function resolveSync(x, options) { var opts = options || {}; @@ -121,3 +120,41 @@ function resolveSync(x, options) { } }; +/** + * node-modules-path, taken directly from resolve.sync + */ + +var parse = path.parse || require('path-parse'); + +function nodeModulesPaths(start, opts) { + var modules = opts && opts.moduleDirectory + ? [].concat(opts.moduleDirectory) + : ['node_modules'] + ; + + // ensure that `start` is an absolute path at this point, + // resolving against the process' current working directory + start = path.resolve(start); + + var prefix = '/'; + if (/^([A-Za-z]:)/.test(start)) { + prefix = ''; + } else if (/^\\\\/.test(start)) { + prefix = '\\\\'; + } + + var paths = [start]; + var parsed = parse(start); + while (parsed.dir !== paths[paths.length - 1]) { + paths.push(parsed.dir); + parsed = parse(parsed.dir); + } + + var dirs = paths.reduce(function (dirs, aPath) { + return dirs.concat(modules.map(function (moduleDir) { + return path.join(prefix, aPath, moduleDir); + })); + }, []); + + return opts && opts.paths ? dirs.concat(opts.paths) : dirs; +}; From a4f2641a554499229746046268870eeaed168707 Mon Sep 17 00:00:00 2001 From: Tony Valderrama Date: Mon, 21 Aug 2017 11:42:23 -0700 Subject: [PATCH 04/20] Remove dependency on path-parse. Assume existence of path.parse (added in v0.11.15). --- packages/jest-resolve/src/default_resolver.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/jest-resolve/src/default_resolver.js b/packages/jest-resolve/src/default_resolver.js index 304bf83f2eac..b470b0bd07cc 100644 --- a/packages/jest-resolve/src/default_resolver.js +++ b/packages/jest-resolve/src/default_resolver.js @@ -124,8 +124,6 @@ function resolveSync(x, options) { * node-modules-path, taken directly from resolve.sync */ -var parse = path.parse || require('path-parse'); - function nodeModulesPaths(start, opts) { var modules = opts && opts.moduleDirectory ? [].concat(opts.moduleDirectory) @@ -144,10 +142,10 @@ function nodeModulesPaths(start, opts) { } var paths = [start]; - var parsed = parse(start); + var parsed = path.parse(start); while (parsed.dir !== paths[paths.length - 1]) { paths.push(parsed.dir); - parsed = parse(parsed.dir); + parsed = path.parse(parsed.dir); } var dirs = paths.reduce(function (dirs, aPath) { From b0dd6954bfe976118f309c0fa833ea5148b07678 Mon Sep 17 00:00:00 2001 From: Tony Valderrama Date: Mon, 21 Aug 2017 11:56:15 -0700 Subject: [PATCH 05/20] Use internal resolve within default_resolver. --- packages/jest-resolve/src/default_resolver.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/jest-resolve/src/default_resolver.js b/packages/jest-resolve/src/default_resolver.js index b470b0bd07cc..fb9ff10f0ee8 100644 --- a/packages/jest-resolve/src/default_resolver.js +++ b/packages/jest-resolve/src/default_resolver.js @@ -10,7 +10,6 @@ import type {Path} from 'types/Config'; -import resolve from 'resolve'; import browserResolve from 'browser-resolve'; type ResolverOptions = {| @@ -22,9 +21,9 @@ type ResolverOptions = {| |}; function defaultResolver(path: Path, options: ResolverOptions) { - const resv = options.browser ? browserResolve : resolve; + const resolve = options.browser ? browserResolve.sync : resolveSync; - return resv.sync(path, { + return resolve(path, { basedir: options.basedir, extensions: options.extensions, moduleDirectory: options.moduleDirectory, From 559315258bd1e0f3e833131d701aa831a7bf64c7 Mon Sep 17 00:00:00 2001 From: Tony Valderrama Date: Mon, 21 Aug 2017 12:07:41 -0700 Subject: [PATCH 06/20] Adhere to linter constraints. --- packages/jest-resolve/src/default_resolver.js | 92 ++++++++++--------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/packages/jest-resolve/src/default_resolver.js b/packages/jest-resolve/src/default_resolver.js index fb9ff10f0ee8..209652d442c2 100644 --- a/packages/jest-resolve/src/default_resolver.js +++ b/packages/jest-resolve/src/default_resolver.js @@ -37,38 +37,40 @@ module.exports = defaultResolver; * resolve logic, taken directly from resolve.sync */ -var fs = require('fs'); -var path = require('path'); +const fs = require('fs'); +const path = require('path'); function resolveSync(x, options) { - var opts = options || {}; - var isFile = opts.isFile || function (file) { - try { - var stat = fs.statSync(file); - } catch (e) { - if (e && e.code === 'ENOENT') return false; - throw e; - } - return stat.isFile() || stat.isFIFO(); - }; - var readFileSync = opts.readFileSync || fs.readFileSync; + const opts = options || {}; + const isFile = + opts.isFile || + function(file) { + try { + const stat = fs.statSync(file); + return stat.isFile() || stat.isFIFO(); + } catch (e) { + if (e && e.code === 'ENOENT') return false; + throw e; + } + }; + const readFileSync = opts.readFileSync || fs.readFileSync; - var extensions = opts.extensions || ['.js']; - var y = opts.basedir; + const extensions = opts.extensions || ['.js']; + const y = opts.basedir; opts.paths = opts.paths || []; if (/^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[\\\/])/.test(x)) { - var res = path.resolve(y, x); + let res = path.resolve(y, x); if (x === '..') res += '/'; - var m = loadAsFileSync(res) || loadAsDirectorySync(res); + const m = loadAsFileSync(res) || loadAsDirectorySync(res); if (m) return m; } else { - var n = loadNodeModulesSync(x, y); + const n = loadNodeModulesSync(x, y); if (n) return n; } - var err = new Error("Cannot find module '" + x + "' from '" + y + "'"); + const err = new Error("Cannot find module '" + x + "' from '" + y + "'"); err.code = 'MODULE_NOT_FOUND'; throw err; @@ -77,8 +79,8 @@ function resolveSync(x, options) { return x; } - for (var i = 0; i < extensions.length; i++) { - var file = x + extensions[i]; + for (let i = 0; i < extensions.length; i++) { + const file = x + extensions[i]; if (isFile(file)) { return file; } @@ -86,19 +88,19 @@ function resolveSync(x, options) { } function loadAsDirectorySync(x) { - var pkgfile = path.join(x, '/package.json'); + const pkgfile = path.join(x, '/package.json'); if (isFile(pkgfile)) { - var body = readFileSync(pkgfile, 'utf8'); + const body = readFileSync(pkgfile, 'utf8'); try { - var pkg = JSON.parse(body); + let pkg = JSON.parse(body); if (opts.packageFilter) { pkg = opts.packageFilter(pkg, x); } if (pkg.main) { - var m = loadAsFileSync(path.resolve(x, pkg.main)); + const m = loadAsFileSync(path.resolve(x, pkg.main)); if (m) return m; - var n = loadAsDirectorySync(path.resolve(x, pkg.main)); + const n = loadAsDirectorySync(path.resolve(x, pkg.main)); if (n) return n; } } catch (e) {} @@ -108,50 +110,52 @@ function resolveSync(x, options) { } function loadNodeModulesSync(x, start) { - var dirs = nodeModulesPaths(start, opts); - for (var i = 0; i < dirs.length; i++) { - var dir = dirs[i]; - var m = loadAsFileSync(path.join(dir, '/', x)); + const dirs = nodeModulesPaths(start, opts); + for (let i = 0; i < dirs.length; i++) { + const dir = dirs[i]; + const m = loadAsFileSync(path.join(dir, '/', x)); if (m) return m; - var n = loadAsDirectorySync(path.join(dir, '/', x)); + const n = loadAsDirectorySync(path.join(dir, '/', x)); if (n) return n; } } -}; +} /** * node-modules-path, taken directly from resolve.sync */ function nodeModulesPaths(start, opts) { - var modules = opts && opts.moduleDirectory - ? [].concat(opts.moduleDirectory) - : ['node_modules'] - ; + const modules = + opts && opts.moduleDirectory + ? [].concat(opts.moduleDirectory) + : ['node_modules']; // ensure that `start` is an absolute path at this point, // resolving against the process' current working directory start = path.resolve(start); - var prefix = '/'; + let prefix = '/'; if (/^([A-Za-z]:)/.test(start)) { prefix = ''; } else if (/^\\\\/.test(start)) { prefix = '\\\\'; } - var paths = [start]; - var parsed = path.parse(start); + const paths = [start]; + let parsed = path.parse(start); while (parsed.dir !== paths[paths.length - 1]) { paths.push(parsed.dir); parsed = path.parse(parsed.dir); } - var dirs = paths.reduce(function (dirs, aPath) { - return dirs.concat(modules.map(function (moduleDir) { - return path.join(prefix, aPath, moduleDir); - })); + const dirs = paths.reduce((dirs, aPath) => { + return dirs.concat( + modules.map(moduleDir => { + return path.join(prefix, aPath, moduleDir); + }), + ); }, []); return opts && opts.paths ? dirs.concat(opts.paths) : dirs; -}; +} From 08bc70dcca288f089cb651a70cc50ec20d76ff3c Mon Sep 17 00:00:00 2001 From: Tony Valderrama Date: Mon, 21 Aug 2017 12:09:07 -0700 Subject: [PATCH 07/20] Extend basic error type with code property. --- packages/jest-resolve/src/default_resolver.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/jest-resolve/src/default_resolver.js b/packages/jest-resolve/src/default_resolver.js index 209652d442c2..048354191e5d 100644 --- a/packages/jest-resolve/src/default_resolver.js +++ b/packages/jest-resolve/src/default_resolver.js @@ -37,6 +37,8 @@ module.exports = defaultResolver; * resolve logic, taken directly from resolve.sync */ +type ErrorWithCode = Error & {code?: string}; + const fs = require('fs'); const path = require('path'); @@ -70,7 +72,9 @@ function resolveSync(x, options) { if (n) return n; } - const err = new Error("Cannot find module '" + x + "' from '" + y + "'"); + const err: ErrorWithCode = new Error( + "Cannot find module '" + x + "' from '" + y + "'", + ); err.code = 'MODULE_NOT_FOUND'; throw err; From 942ddc7b8536dda75a589d110cc9e17a4e43902c Mon Sep 17 00:00:00 2001 From: Tony Valderrama Date: Mon, 21 Aug 2017 12:31:49 -0700 Subject: [PATCH 08/20] Fix typing and remove extraneous options. --- packages/jest-resolve/src/default_resolver.js | 66 +++++++++---------- 1 file changed, 30 insertions(+), 36 deletions(-) diff --git a/packages/jest-resolve/src/default_resolver.js b/packages/jest-resolve/src/default_resolver.js index 048354191e5d..dbf6e4e5ae83 100644 --- a/packages/jest-resolve/src/default_resolver.js +++ b/packages/jest-resolve/src/default_resolver.js @@ -20,7 +20,7 @@ type ResolverOptions = {| paths?: ?Array, |}; -function defaultResolver(path: Path, options: ResolverOptions) { +function defaultResolver(path: Path, options: ResolverOptions): Path { const resolve = options.browser ? browserResolve.sync : resolveSync; return resolve(path, { @@ -42,25 +42,22 @@ type ErrorWithCode = Error & {code?: string}; const fs = require('fs'); const path = require('path'); -function resolveSync(x, options) { - const opts = options || {}; - const isFile = - opts.isFile || - function(file) { - try { - const stat = fs.statSync(file); - return stat.isFile() || stat.isFIFO(); - } catch (e) { - if (e && e.code === 'ENOENT') return false; - throw e; - } - }; - const readFileSync = opts.readFileSync || fs.readFileSync; +function resolveSync(x: Path, options: ResolverOptions): Path { + 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; + } + } + const readFileSync = fs.readFileSync; - const extensions = opts.extensions || ['.js']; - const y = opts.basedir; + const extensions = options.extensions || ['.js']; + const y = options.basedir; - opts.paths = opts.paths || []; + options.paths = options.paths || []; if (/^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[\\\/])/.test(x)) { let res = path.resolve(y, x); @@ -78,7 +75,7 @@ function resolveSync(x, options) { err.code = 'MODULE_NOT_FOUND'; throw err; - function loadAsFileSync(x) { + function loadAsFileSync(x: Path): ?Path { if (isFile(x)) { return x; } @@ -89,22 +86,20 @@ function resolveSync(x, options) { return file; } } + + return undefined; } - function loadAsDirectorySync(x) { + function loadAsDirectorySync(x: Path): ?Path { const pkgfile = path.join(x, '/package.json'); if (isFile(pkgfile)) { const body = readFileSync(pkgfile, 'utf8'); try { - let pkg = JSON.parse(body); - if (opts.packageFilter) { - pkg = opts.packageFilter(pkg, x); - } - - if (pkg.main) { - const m = loadAsFileSync(path.resolve(x, pkg.main)); + const pkgmain = JSON.parse(body).main; + if (pkgmain) { + const m = loadAsFileSync(path.resolve(x, pkgmain)); if (m) return m; - const n = loadAsDirectorySync(path.resolve(x, pkg.main)); + const n = loadAsDirectorySync(path.resolve(x, pkgmain)); if (n) return n; } } catch (e) {} @@ -113,8 +108,8 @@ function resolveSync(x, options) { return loadAsFileSync(path.join(x, '/index')); } - function loadNodeModulesSync(x, start) { - const dirs = nodeModulesPaths(start, opts); + function loadNodeModulesSync(x: Path, start: Path): ?Path { + const dirs = nodeModulesPaths(start, options); for (let i = 0; i < dirs.length; i++) { const dir = dirs[i]; const m = loadAsFileSync(path.join(dir, '/', x)); @@ -122,6 +117,8 @@ function resolveSync(x, options) { const n = loadAsDirectorySync(path.join(dir, '/', x)); if (n) return n; } + + return undefined; } } @@ -129,11 +126,8 @@ function resolveSync(x, options) { * node-modules-path, taken directly from resolve.sync */ -function nodeModulesPaths(start, opts) { - const modules = - opts && opts.moduleDirectory - ? [].concat(opts.moduleDirectory) - : ['node_modules']; +function nodeModulesPaths(start: Path, options: ResolverOptions): Path[] { + const modules = ['node_modules']; // ensure that `start` is an absolute path at this point, // resolving against the process' current working directory @@ -161,5 +155,5 @@ function nodeModulesPaths(start, opts) { ); }, []); - return opts && opts.paths ? dirs.concat(opts.paths) : dirs; + return options.paths ? dirs.concat(options.paths) : dirs; } From d10676ab91221da82107da85e3b38da609c87031 Mon Sep 17 00:00:00 2001 From: Tony Valderrama Date: Mon, 21 Aug 2017 12:37:30 -0700 Subject: [PATCH 09/20] Gather helper methods at end of resolveSync(). --- packages/jest-resolve/src/default_resolver.js | 85 +++++++++---------- 1 file changed, 42 insertions(+), 43 deletions(-) diff --git a/packages/jest-resolve/src/default_resolver.js b/packages/jest-resolve/src/default_resolver.js index dbf6e4e5ae83..3e780331c67a 100644 --- a/packages/jest-resolve/src/default_resolver.js +++ b/packages/jest-resolve/src/default_resolver.js @@ -33,25 +33,15 @@ function defaultResolver(path: Path, options: ResolverOptions): Path { module.exports = defaultResolver; -/** - * resolve logic, taken directly from resolve.sync +/* + * resolve logic, adapted from resolve.sync */ - type ErrorWithCode = Error & {code?: string}; const fs = require('fs'); const path = require('path'); function resolveSync(x: Path, options: ResolverOptions): Path { - 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; - } - } const readFileSync = fs.readFileSync; const extensions = options.extensions || ['.js']; @@ -75,6 +65,19 @@ function resolveSync(x: Path, options: ResolverOptions): Path { 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; @@ -109,7 +112,7 @@ function resolveSync(x: Path, options: ResolverOptions): Path { } function loadNodeModulesSync(x: Path, start: Path): ?Path { - const dirs = nodeModulesPaths(start, options); + const dirs = nodeModulesPaths(start); for (let i = 0; i < dirs.length; i++) { const dir = dirs[i]; const m = loadAsFileSync(path.join(dir, '/', x)); @@ -120,40 +123,36 @@ function resolveSync(x: Path, options: ResolverOptions): Path { return undefined; } -} -/** - * node-modules-path, taken directly from resolve.sync - */ - -function nodeModulesPaths(start: Path, options: ResolverOptions): Path[] { - const modules = ['node_modules']; + function nodeModulesPaths(start: Path): Path[] { + const modules = ['node_modules']; - // ensure that `start` is an absolute path at this point, - // resolving against the process' current working directory - start = path.resolve(start); + // ensure that `start` is an absolute path at this point, + // resolving against the process' current working directory + start = path.resolve(start); - let prefix = '/'; - if (/^([A-Za-z]:)/.test(start)) { - prefix = ''; - } else if (/^\\\\/.test(start)) { - prefix = '\\\\'; - } + let prefix = '/'; + if (/^([A-Za-z]:)/.test(start)) { + prefix = ''; + } else if (/^\\\\/.test(start)) { + prefix = '\\\\'; + } - const paths = [start]; - let parsed = path.parse(start); - while (parsed.dir !== paths[paths.length - 1]) { - paths.push(parsed.dir); - parsed = path.parse(parsed.dir); - } + const paths = [start]; + let parsed = path.parse(start); + 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); - }), - ); - }, []); + 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; + return options.paths ? dirs.concat(options.paths) : dirs; + } } From d15ec91ace2270b2800335349baf2bac8f559699 Mon Sep 17 00:00:00 2001 From: Tony Valderrama Date: Mon, 21 Aug 2017 12:41:33 -0700 Subject: [PATCH 10/20] Rename "start" parameter to more obvious "basedir". --- packages/jest-resolve/src/default_resolver.js | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/jest-resolve/src/default_resolver.js b/packages/jest-resolve/src/default_resolver.js index 3e780331c67a..ac0ee0f23157 100644 --- a/packages/jest-resolve/src/default_resolver.js +++ b/packages/jest-resolve/src/default_resolver.js @@ -45,22 +45,22 @@ function resolveSync(x: Path, options: ResolverOptions): Path { const readFileSync = fs.readFileSync; const extensions = options.extensions || ['.js']; - const y = options.basedir; + const basedir = options.basedir; options.paths = options.paths || []; if (/^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[\\\/])/.test(x)) { - let res = path.resolve(y, x); + let res = path.resolve(basedir, x); if (x === '..') res += '/'; const m = loadAsFileSync(res) || loadAsDirectorySync(res); if (m) return m; } else { - const n = loadNodeModulesSync(x, y); + const n = loadNodeModulesSync(x, basedir); if (n) return n; } const err: ErrorWithCode = new Error( - "Cannot find module '" + x + "' from '" + y + "'", + "Cannot find module '" + x + "' from '" + basedir + "'", ); err.code = 'MODULE_NOT_FOUND'; throw err; @@ -111,8 +111,8 @@ function resolveSync(x: Path, options: ResolverOptions): Path { return loadAsFileSync(path.join(x, '/index')); } - function loadNodeModulesSync(x: Path, start: Path): ?Path { - const dirs = nodeModulesPaths(start); + function loadNodeModulesSync(x: Path, basedir: Path): ?Path { + const dirs = nodeModulesPaths(basedir); for (let i = 0; i < dirs.length; i++) { const dir = dirs[i]; const m = loadAsFileSync(path.join(dir, '/', x)); @@ -124,22 +124,22 @@ function resolveSync(x: Path, options: ResolverOptions): Path { return undefined; } - function nodeModulesPaths(start: Path): Path[] { + function nodeModulesPaths(basedir: Path): Path[] { const modules = ['node_modules']; - // ensure that `start` is an absolute path at this point, + // ensure that `basedir` is an absolute path at this point, // resolving against the process' current working directory - start = path.resolve(start); + basedir = path.resolve(basedir); let prefix = '/'; - if (/^([A-Za-z]:)/.test(start)) { + if (/^([A-Za-z]:)/.test(basedir)) { prefix = ''; - } else if (/^\\\\/.test(start)) { + } else if (/^\\\\/.test(basedir)) { prefix = '\\\\'; } - const paths = [start]; - let parsed = path.parse(start); + const paths = [basedir]; + let parsed = path.parse(basedir); while (parsed.dir !== paths[paths.length - 1]) { paths.push(parsed.dir); parsed = path.parse(parsed.dir); From 24e9b18f058e5e107da051b4e0affb63585bbfa7 Mon Sep 17 00:00:00 2001 From: Tony Valderrama Date: Mon, 21 Aug 2017 12:49:47 -0700 Subject: [PATCH 11/20] Avoid shadowing basedir variable. --- packages/jest-resolve/src/default_resolver.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/jest-resolve/src/default_resolver.js b/packages/jest-resolve/src/default_resolver.js index ac0ee0f23157..85f9cd993fa3 100644 --- a/packages/jest-resolve/src/default_resolver.js +++ b/packages/jest-resolve/src/default_resolver.js @@ -111,8 +111,8 @@ function resolveSync(x: Path, options: ResolverOptions): Path { return loadAsFileSync(path.join(x, '/index')); } - function loadNodeModulesSync(x: Path, basedir: Path): ?Path { - const dirs = nodeModulesPaths(basedir); + function loadNodeModulesSync(x: Path): ?Path { + const dirs = nodeModulesPaths(); for (let i = 0; i < dirs.length; i++) { const dir = dirs[i]; const m = loadAsFileSync(path.join(dir, '/', x)); @@ -124,22 +124,22 @@ function resolveSync(x: Path, options: ResolverOptions): Path { return undefined; } - function nodeModulesPaths(basedir: Path): Path[] { + function nodeModulesPaths(): Path[] { const modules = ['node_modules']; // ensure that `basedir` is an absolute path at this point, // resolving against the process' current working directory - basedir = path.resolve(basedir); + const basedirAbs = path.resolve(basedir); let prefix = '/'; - if (/^([A-Za-z]:)/.test(basedir)) { + if (/^([A-Za-z]:)/.test(basedirAbs)) { prefix = ''; - } else if (/^\\\\/.test(basedir)) { + } else if (/^\\\\/.test(basedirAbs)) { prefix = '\\\\'; } - const paths = [basedir]; - let parsed = path.parse(basedir); + const paths = [basedirAbs]; + let parsed = path.parse(basedirAbs); while (parsed.dir !== paths[paths.length - 1]) { paths.push(parsed.dir); parsed = path.parse(parsed.dir); From 7e46c07a9a9d6aa824385b09e3c3ca6b908c2af1 Mon Sep 17 00:00:00 2001 From: Tony Valderrama Date: Mon, 21 Aug 2017 12:50:53 -0700 Subject: [PATCH 12/20] Inline loadNodeModulesSync() method. --- packages/jest-resolve/src/default_resolver.js | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/packages/jest-resolve/src/default_resolver.js b/packages/jest-resolve/src/default_resolver.js index 85f9cd993fa3..97baf8968038 100644 --- a/packages/jest-resolve/src/default_resolver.js +++ b/packages/jest-resolve/src/default_resolver.js @@ -55,8 +55,14 @@ function resolveSync(x: Path, options: ResolverOptions): Path { const m = loadAsFileSync(res) || loadAsDirectorySync(res); if (m) return m; } else { - const n = loadNodeModulesSync(x, basedir); - if (n) return n; + const dirs = nodeModulesPaths(); + for (let i = 0; i < dirs.length; i++) { + const dir = dirs[i]; + const m = loadAsFileSync(path.join(dir, '/', x)); + if (m) return m; + const n = loadAsDirectorySync(path.join(dir, '/', x)); + if (n) return n; + } } const err: ErrorWithCode = new Error( @@ -111,19 +117,6 @@ function resolveSync(x: Path, options: ResolverOptions): Path { return loadAsFileSync(path.join(x, '/index')); } - function loadNodeModulesSync(x: Path): ?Path { - const dirs = nodeModulesPaths(); - for (let i = 0; i < dirs.length; i++) { - const dir = dirs[i]; - const m = loadAsFileSync(path.join(dir, '/', x)); - if (m) return m; - const n = loadAsDirectorySync(path.join(dir, '/', x)); - if (n) return n; - } - - return undefined; - } - function nodeModulesPaths(): Path[] { const modules = ['node_modules']; From 73ccd44c3c53cb9411845bbb28626499c2c15a6b Mon Sep 17 00:00:00 2001 From: Tony Valderrama Date: Mon, 21 Aug 2017 12:53:43 -0700 Subject: [PATCH 13/20] Clarify relative import vs node_modules. --- packages/jest-resolve/src/default_resolver.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/jest-resolve/src/default_resolver.js b/packages/jest-resolve/src/default_resolver.js index 97baf8968038..35a76bb8a0be 100644 --- a/packages/jest-resolve/src/default_resolver.js +++ b/packages/jest-resolve/src/default_resolver.js @@ -40,6 +40,7 @@ type ErrorWithCode = Error & {code?: string}; const fs = require('fs'); const path = require('path'); +const REGEX_RELATIVE_IMPORT = /^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[\\\/])/; function resolveSync(x: Path, options: ResolverOptions): Path { const readFileSync = fs.readFileSync; @@ -49,12 +50,14 @@ function resolveSync(x: Path, options: ResolverOptions): Path { options.paths = options.paths || []; - if (/^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[\\\/])/.test(x)) { + if (REGEX_RELATIVE_IMPORT.test(x)) { + // resolve relative import let res = path.resolve(basedir, x); if (x === '..') res += '/'; const m = loadAsFileSync(res) || loadAsDirectorySync(res); if (m) return m; } else { + // otherwise search for node_modules const dirs = nodeModulesPaths(); for (let i = 0; i < dirs.length; i++) { const dir = dirs[i]; From 513f1d2f21fedeb49e9d278a5261d24b4a83accb Mon Sep 17 00:00:00 2001 From: Tony Valderrama Date: Mon, 21 Aug 2017 12:54:44 -0700 Subject: [PATCH 14/20] Use import instead of require. --- packages/jest-resolve/src/default_resolver.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/jest-resolve/src/default_resolver.js b/packages/jest-resolve/src/default_resolver.js index 35a76bb8a0be..fd3c94f83c9c 100644 --- a/packages/jest-resolve/src/default_resolver.js +++ b/packages/jest-resolve/src/default_resolver.js @@ -38,8 +38,9 @@ module.exports = defaultResolver; */ type ErrorWithCode = Error & {code?: string}; -const fs = require('fs'); -const path = require('path'); +import fs from 'fs'; +import path from 'path'; + const REGEX_RELATIVE_IMPORT = /^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[\\\/])/; function resolveSync(x: Path, options: ResolverOptions): Path { From e625b8a9f33be9b9451df174dcc41d55fd4588ed Mon Sep 17 00:00:00 2001 From: Tony Valderrama Date: Mon, 21 Aug 2017 13:00:34 -0700 Subject: [PATCH 15/20] Small logic and formatting simplifications. --- packages/jest-resolve/src/default_resolver.js | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/packages/jest-resolve/src/default_resolver.js b/packages/jest-resolve/src/default_resolver.js index fd3c94f83c9c..aad859d42c00 100644 --- a/packages/jest-resolve/src/default_resolver.js +++ b/packages/jest-resolve/src/default_resolver.js @@ -53,19 +53,18 @@ function resolveSync(x: Path, options: ResolverOptions): Path { if (REGEX_RELATIVE_IMPORT.test(x)) { // resolve relative import - let res = path.resolve(basedir, x); - if (x === '..') res += '/'; - const m = loadAsFileSync(res) || loadAsDirectorySync(res); + 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(); for (let i = 0; i < dirs.length; i++) { const dir = dirs[i]; - const m = loadAsFileSync(path.join(dir, '/', x)); + const target = path.join(dir, '/', x); + const m = loadAsFileSync(target) || loadAsDirectorySync(target); if (m) return m; - const n = loadAsDirectorySync(path.join(dir, '/', x)); - if (n) return n; } } @@ -89,15 +88,11 @@ function resolveSync(x: Path, options: ResolverOptions): Path { } function loadAsFileSync(x: Path): ?Path { - if (isFile(x)) { - return x; - } + if (isFile(x)) return x; for (let i = 0; i < extensions.length; i++) { const file = x + extensions[i]; - if (isFile(file)) { - return file; - } + if (isFile(file)) return file; } return undefined; @@ -110,10 +105,9 @@ function resolveSync(x: Path, options: ResolverOptions): Path { try { const pkgmain = JSON.parse(body).main; if (pkgmain) { - const m = loadAsFileSync(path.resolve(x, pkgmain)); + const target = path.resolve(x, pkgmain); + const m = loadAsFileSync(target) || loadAsDirectorySync(target); if (m) return m; - const n = loadAsDirectorySync(path.resolve(x, pkgmain)); - if (n) return n; } } catch (e) {} } From eb980f38358470c1cba8e4c264baf82f25e98e14 Mon Sep 17 00:00:00 2001 From: Tony Valderrama Date: Mon, 21 Aug 2017 13:20:49 -0700 Subject: [PATCH 16/20] Use isBuiltinModule() to detect core modules. Restore use of moduleDirectory option. --- packages/jest-resolve/src/default_resolver.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/jest-resolve/src/default_resolver.js b/packages/jest-resolve/src/default_resolver.js index aad859d42c00..9d8ddb8f4949 100644 --- a/packages/jest-resolve/src/default_resolver.js +++ b/packages/jest-resolve/src/default_resolver.js @@ -40,6 +40,7 @@ type ErrorWithCode = Error & {code?: string}; import fs from 'fs'; import path from 'path'; +import isBuiltinModule from 'is-builtin-module'; const REGEX_RELATIVE_IMPORT = /^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[\\\/])/; @@ -68,6 +69,8 @@ function resolveSync(x: Path, options: ResolverOptions): Path { } } + if (isBuiltinModule(x)) return x; + const err: ErrorWithCode = new Error( "Cannot find module '" + x + "' from '" + basedir + "'", ); @@ -116,7 +119,10 @@ function resolveSync(x: Path, options: ResolverOptions): Path { } function nodeModulesPaths(): Path[] { - const modules = ['node_modules']; + 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 From b04689981f310973c7adc12d70b4841dd6f23c96 Mon Sep 17 00:00:00 2001 From: Tony Valderrama Date: Mon, 21 Aug 2017 13:25:37 -0700 Subject: [PATCH 17/20] Remove package dependency on resolve. --- packages/jest-resolve/package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/jest-resolve/package.json b/packages/jest-resolve/package.json index 637fcc8447d3..6bd44f3e3da7 100644 --- a/packages/jest-resolve/package.json +++ b/packages/jest-resolve/package.json @@ -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" From 580f0c8c86924b2a197d14158fc0c35990682959 Mon Sep 17 00:00:00 2001 From: Tony Valderrama Date: Mon, 21 Aug 2017 13:57:45 -0700 Subject: [PATCH 18/20] Make node_modules_paths available to resolver core logic, rather than just default_resolver. --- packages/jest-resolve/src/default_resolver.js | 39 ++------------- packages/jest-resolve/src/index.js | 2 +- .../jest-resolve/src/node_modules_paths.js | 47 +++++++++++++++++++ 3 files changed, 51 insertions(+), 37 deletions(-) create mode 100644 packages/jest-resolve/src/node_modules_paths.js diff --git a/packages/jest-resolve/src/default_resolver.js b/packages/jest-resolve/src/default_resolver.js index 9d8ddb8f4949..af561fbfbc36 100644 --- a/packages/jest-resolve/src/default_resolver.js +++ b/packages/jest-resolve/src/default_resolver.js @@ -42,6 +42,8 @@ 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 { @@ -60,7 +62,7 @@ function resolveSync(x: Path, options: ResolverOptions): Path { if (m) return m; } else { // otherwise search for node_modules - const dirs = nodeModulesPaths(); + const dirs = nodeModulesPaths(basedir, options); for (let i = 0; i < dirs.length; i++) { const dir = dirs[i]; const target = path.join(dir, '/', x); @@ -117,39 +119,4 @@ function resolveSync(x: Path, options: ResolverOptions): Path { return loadAsFileSync(path.join(x, '/index')); } - - function nodeModulesPaths(): 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; - } } diff --git a/packages/jest-resolve/src/index.js b/packages/jest-resolve/src/index.js index b96b80a1bdfc..90565d999210 100644 --- a/packages/jest-resolve/src/index.js +++ b/packages/jest-resolve/src/index.js @@ -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'; diff --git a/packages/jest-resolve/src/node_modules_paths.js b/packages/jest-resolve/src/node_modules_paths.js new file mode 100644 index 000000000000..84c183d4db5e --- /dev/null +++ b/packages/jest-resolve/src/node_modules_paths.js @@ -0,0 +1,47 @@ +import type {Path} from 'types/Config'; +import path from 'path'; + +type NodeModulesPathsOptions = {| + moduleDirectory?: Array, + paths?: ?Array, +|}; + +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; From 33133808fc289da15460235c4a772afaed5d20bf Mon Sep 17 00:00:00 2001 From: Tony Valderrama Date: Mon, 21 Aug 2017 14:31:51 -0700 Subject: [PATCH 19/20] Add standard header to node_modules_paths.js. Add adaptation note to default_resolver.js. --- packages/jest-resolve/src/default_resolver.js | 2 +- packages/jest-resolve/src/node_modules_paths.js | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/jest-resolve/src/default_resolver.js b/packages/jest-resolve/src/default_resolver.js index af561fbfbc36..51e2c2acfb81 100644 --- a/packages/jest-resolve/src/default_resolver.js +++ b/packages/jest-resolve/src/default_resolver.js @@ -34,7 +34,7 @@ function defaultResolver(path: Path, options: ResolverOptions): Path { module.exports = defaultResolver; /* - * resolve logic, adapted from resolve.sync + * Adapted from: https://github.com/substack/node-resolve */ type ErrorWithCode = Error & {code?: string}; diff --git a/packages/jest-resolve/src/node_modules_paths.js b/packages/jest-resolve/src/node_modules_paths.js index 84c183d4db5e..d5aacc9c871e 100644 --- a/packages/jest-resolve/src/node_modules_paths.js +++ b/packages/jest-resolve/src/node_modules_paths.js @@ -1,3 +1,15 @@ +/** + * 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'; import path from 'path'; From de104b06480e767253645a3b53d7361d52490e2f Mon Sep 17 00:00:00 2001 From: Tony Valderrama Date: Mon, 21 Aug 2017 18:25:31 -0700 Subject: [PATCH 20/20] Trim out unused options when calling nodeModulesPaths(). --- packages/jest-resolve/src/default_resolver.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/jest-resolve/src/default_resolver.js b/packages/jest-resolve/src/default_resolver.js index 51e2c2acfb81..2ed74a9823b3 100644 --- a/packages/jest-resolve/src/default_resolver.js +++ b/packages/jest-resolve/src/default_resolver.js @@ -62,7 +62,10 @@ function resolveSync(x: Path, options: ResolverOptions): Path { if (m) return m; } else { // otherwise search for node_modules - const dirs = nodeModulesPaths(basedir, options); + 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);