packager: ResolutionRequest: @format

Summary: Add `prettier` before I continue some refactorings.

Reviewed By: davidaurelio

Differential Revision: D5036276

fbshipit-source-id: 590e1b23864f28c51d337204df3281dd8bd311cd
This commit is contained in:
Jean Lauliac 2017-05-11 03:35:06 -07:00 committed by Facebook Github Bot
parent 867a6dbd27
commit 3e46c051d3

View File

@ -7,7 +7,9 @@
* of patent rights can be found in the PATENTS file in the same directory. * of patent rights can be found in the PATENTS file in the same directory.
* *
* @flow * @flow
* @format
*/ */
'use strict'; 'use strict';
const AsyncTaskGroup = require('../lib/AsyncTaskGroup'); const AsyncTaskGroup = require('../lib/AsyncTaskGroup');
@ -24,7 +26,9 @@ const getAssetDataFromName = require('../lib/getAssetDataFromName');
import type {HasteFS} from '../types'; import type {HasteFS} from '../types';
import type DependencyGraphHelpers from './DependencyGraphHelpers'; import type DependencyGraphHelpers from './DependencyGraphHelpers';
import type ResolutionResponse from './ResolutionResponse'; import type ResolutionResponse from './ResolutionResponse';
import type {Options as TransformWorkerOptions} from '../../JSTransformer/worker/worker'; import type {
Options as TransformWorkerOptions,
} from '../../JSTransformer/worker/worker';
import type {ReadResult, CachedReadResult} from '../Module'; import type {ReadResult, CachedReadResult} from '../Module';
type DirExistsFn = (filePath: string) => boolean; type DirExistsFn = (filePath: string) => boolean;
@ -33,8 +37,16 @@ type DirExistsFn = (filePath: string) => boolean;
* `jest-haste-map`'s interface for ModuleMap. * `jest-haste-map`'s interface for ModuleMap.
*/ */
export type ModuleMap = { export type ModuleMap = {
getModule(name: string, platform: ?string, supportsNativePlatform: boolean): ?string, getModule(
getPackage(name: string, platform: ?string, supportsNativePlatform: boolean): ?string, name: string,
platform: ?string,
supportsNativePlatform: boolean,
): ?string,
getPackage(
name: string,
platform: ?string,
supportsNativePlatform: boolean,
): ?string,
}; };
type Packageish = { type Packageish = {
@ -52,12 +64,19 @@ type Moduleish = {
}; };
type ModuleishCache<TModule, TPackage> = { type ModuleishCache<TModule, TPackage> = {
getPackage(name: string, platform?: string, supportsNativePlatform?: boolean): TPackage, getPackage(
name: string,
platform?: string,
supportsNativePlatform?: boolean,
): TPackage,
getModule(path: string): TModule, getModule(path: string): TModule,
getAssetModule(path: string): TModule, getAssetModule(path: string): TModule,
}; };
type MatchFilesByDirAndPattern = (dirName: string, pattern: RegExp) => Array<string>; type MatchFilesByDirAndPattern = (
dirName: string,
pattern: RegExp,
) => Array<string>;
type Options<TModule, TPackage> = {| type Options<TModule, TPackage> = {|
+dirExists: DirExistsFn, +dirExists: DirExistsFn,
@ -91,7 +110,6 @@ function tryResolveSync<T>(action: () => T, secondaryAction: () => T): T {
} }
class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> { class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
_immediateResolutionCache: {[key: string]: TModule}; _immediateResolutionCache: {[key: string]: TModule};
_options: Options<TModule, TPackage>; _options: Options<TModule, TPackage>;
static emptyModule: string; static emptyModule: string;
@ -101,7 +119,10 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
this._resetResolutionCache(); this._resetResolutionCache();
} }
_tryResolve<T>(action: () => Promise<T>, secondaryAction: () => ?Promise<T>): Promise<T> { _tryResolve<T>(
action: () => Promise<T>,
secondaryAction: () => ?Promise<T>,
): Promise<T> {
return action().catch(error => { return action().catch(error => {
if (error.type !== 'UnableToResolveError') { if (error.type !== 'UnableToResolveError') {
throw error; throw error;
@ -123,8 +144,10 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
return result; return result;
}; };
if (!this._options.helpers.isNodeModulesDir(fromModule.path) if (
&& !(isRelativeImport(toModuleName) || isAbsolutePath(toModuleName))) { !this._options.helpers.isNodeModulesDir(fromModule.path) &&
!(isRelativeImport(toModuleName) || isAbsolutePath(toModuleName))
) {
const result = tryResolveSync( const result = tryResolveSync(
() => this._resolveHasteDependency(fromModule, toModuleName), () => this._resolveHasteDependency(fromModule, toModuleName),
() => this._resolveNodeDependency(fromModule, toModuleName), () => this._resolveNodeDependency(fromModule, toModuleName),
@ -139,7 +162,9 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
module: TModule, module: TModule,
dependencyNames: $ReadOnlyArray<string>, dependencyNames: $ReadOnlyArray<string>,
): [$ReadOnlyArray<string>, $ReadOnlyArray<TModule>] { ): [$ReadOnlyArray<string>, $ReadOnlyArray<TModule>] {
const dependencies = dependencyNames.map(name => this.resolveDependency(module, name)); const dependencies = dependencyNames.map(name =>
this.resolveDependency(module, name),
);
return [dependencyNames, dependencies]; return [dependencyNames, dependencies];
} }
@ -173,16 +198,25 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
}); });
} }
const resolveDependencies = (module: TModule) => Promise.resolve().then(() => { const resolveDependencies = (module: TModule) =>
const cached = module.readCached(transformOptions); Promise.resolve().then(() => {
if (cached.result != null) { const cached = module.readCached(transformOptions);
return this.resolveModuleDependencies(module, cached.result.dependencies); if (cached.result != null) {
} return this.resolveModuleDependencies(
return module.readFresh(transformOptions) module,
.then(({dependencies}) => this.resolveModuleDependencies(module, dependencies)); cached.result.dependencies,
}); );
}
return module
.readFresh(transformOptions)
.then(({dependencies}) =>
this.resolveModuleDependencies(module, dependencies),
);
});
const collectedDependencies = new MapWithDefaults(module => collect(module)); const collectedDependencies = new MapWithDefaults(module =>
collect(module),
);
const crawlDependencies = (mod, [depNames, dependencies]) => { const crawlDependencies = (mod, [depNames, dependencies]) => {
const filteredPairs = []; const filteredPairs = [];
@ -192,7 +226,7 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
debug( debug(
'WARNING: Cannot find required module `%s` from module `%s`', 'WARNING: Cannot find required module `%s` from module `%s`',
name, name,
mod.path mod.path,
); );
return false; return false;
} }
@ -202,20 +236,25 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
response.setResolvedDependencyPairs(mod, filteredPairs); response.setResolvedDependencyPairs(mod, filteredPairs);
const dependencyModules = filteredPairs.map(([, m]) => m); const dependencyModules = filteredPairs.map(([, m]) => m);
const newDependencies = const newDependencies = dependencyModules.filter(
dependencyModules.filter(m => !collectedDependencies.has(m)); m => !collectedDependencies.has(m),
);
if (onProgress) { if (onProgress) {
finishedModules += 1; finishedModules += 1;
totalModules += newDependencies.length; totalModules += newDependencies.length;
onProgress(finishedModules, Math.max(totalModules, preprocessedModuleCount)); onProgress(
finishedModules,
Math.max(totalModules, preprocessedModuleCount),
);
} }
if (recursive) { if (recursive) {
// doesn't block the return of this function invocation, but defers // doesn't block the return of this function invocation, but defers
// the resulution of collectionsInProgress.done.then(...) // the resulution of collectionsInProgress.done.then(...)
dependencyModules dependencyModules.forEach(dependency =>
.forEach(dependency => collectedDependencies.get(dependency)); collectedDependencies.get(dependency),
);
} }
return dependencyModules; return dependencyModules;
}; };
@ -223,49 +262,57 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
const collectionsInProgress = new AsyncTaskGroup(); const collectionsInProgress = new AsyncTaskGroup();
function collect(module) { function collect(module) {
collectionsInProgress.start(module); collectionsInProgress.start(module);
const result = resolveDependencies(module) const result = resolveDependencies(module).then(deps =>
.then(deps => crawlDependencies(module, deps)); crawlDependencies(module, deps),
);
const end = () => collectionsInProgress.end(module); const end = () => collectionsInProgress.end(module);
result.then(end, end); result.then(end, end);
return result; return result;
} }
return Promise.all([ return Promise.all([
// kicks off recursive dependency discovery, but doesn't block until it's done // kicks off recursive dependency discovery, but doesn't block until it's
// done
collectedDependencies.get(entry), collectedDependencies.get(entry),
// resolves when there are no more modules resolving dependencies // resolves when there are no more modules resolving dependencies
collectionsInProgress.done, collectionsInProgress.done,
]).then(([rootDependencies]) => { ])
return Promise.all( .then(([rootDependencies]) => {
Array.from(collectedDependencies, resolveKeyWithPromise) return Promise.all(
).then(moduleToDependenciesPairs => Array.from(collectedDependencies, resolveKeyWithPromise),
[rootDependencies, new MapWithDefaults(() => [], moduleToDependenciesPairs)] ).then(moduleToDependenciesPairs => [
); rootDependencies,
}).then(([rootDependencies, moduleDependencies]) => { new MapWithDefaults(() => [], moduleToDependenciesPairs),
// serialize dependencies, and make sure that every single one is only ]);
// included once })
const seen = new Set([entry]); .then(([rootDependencies, moduleDependencies]) => {
function traverse(dependencies) { // serialize dependencies, and make sure that every single one is only
dependencies.forEach(dependency => { // included once
if (seen.has(dependency)) { return; } const seen = new Set([entry]);
function traverse(dependencies) {
dependencies.forEach(dependency => {
if (seen.has(dependency)) {
return;
}
seen.add(dependency); seen.add(dependency);
response.pushDependency(dependency); response.pushDependency(dependency);
traverse(moduleDependencies.get(dependency)); traverse(moduleDependencies.get(dependency));
}); });
} }
traverse(rootDependencies); traverse(rootDependencies);
}); });
} }
/** /**
* This synchronously look at all the specified modules and recursively kicks off global cache * This synchronously look at all the specified modules and recursively kicks
* fetching or transforming (via `readFresh`). This is a hack that workaround the current * off global cache fetching or transforming (via `readFresh`). This is a hack
* structure, because we could do better. First off, the algorithm that resolves dependencies * that workaround the current structure, because we could do better. First
* recursively should be synchronous itself until it cannot progress anymore (and needs to * off, the algorithm that resolves dependencies recursively should be
* call `readFresh`), so that this algo would be integrated into it. * synchronous itself until it cannot progress anymore (and needs to call
* `readFresh`), so that this algo would be integrated into it.
*/ */
_preprocessPotentialDependencies( _preprocessPotentialDependencies(
transformOptions: TransformWorkerOptions, transformOptions: TransformWorkerOptions,
@ -273,13 +320,19 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
onProgress: (moduleCount: number) => mixed, onProgress: (moduleCount: number) => mixed,
): void { ): void {
const visitedModulePaths = new Set(); const visitedModulePaths = new Set();
const pendingBatches = [this.preprocessModule(transformOptions, module, visitedModulePaths)]; const pendingBatches = [
this.preprocessModule(transformOptions, module, visitedModulePaths),
];
onProgress(visitedModulePaths.size); onProgress(visitedModulePaths.size);
while (pendingBatches.length > 0) { while (pendingBatches.length > 0) {
const dependencyModules = pendingBatches.pop(); const dependencyModules = pendingBatches.pop();
while (dependencyModules.length > 0) { while (dependencyModules.length > 0) {
const dependencyModule = dependencyModules.pop(); const dependencyModule = dependencyModules.pop();
const deps = this.preprocessModule(transformOptions, dependencyModule, visitedModulePaths); const deps = this.preprocessModule(
transformOptions,
dependencyModule,
visitedModulePaths,
);
pendingBatches.push(deps); pendingBatches.push(deps);
onProgress(visitedModulePaths.size); onProgress(visitedModulePaths.size);
} }
@ -299,8 +352,13 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
}); });
} }
const dependencies = cached.result != null const dependencies = cached.result != null
? cached.result.dependencies : cached.outdatedDependencies; ? cached.result.dependencies
return this.tryResolveModuleDependencies(module, dependencies, visitedModulePaths); : cached.outdatedDependencies;
return this.tryResolveModuleDependencies(
module,
dependencies,
visitedModulePaths,
);
} }
tryResolveModuleDependencies( tryResolveModuleDependencies(
@ -331,14 +389,18 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
const pck = fromModule.getPackage(); const pck = fromModule.getPackage();
let realModuleName; let realModuleName;
if (pck) { if (pck) {
/* $FlowFixMe: redirectRequire can actually return `false` for exclusions */ /* $FlowFixMe: redirectRequire can actually return `false` for
exclusions*/
realModuleName = (pck.redirectRequire(toModuleName): string); realModuleName = (pck.redirectRequire(toModuleName): string);
} else { } else {
realModuleName = toModuleName; realModuleName = toModuleName;
} }
const modulePath = this._options.moduleMap const modulePath = this._options.moduleMap.getModule(
.getModule(realModuleName, this._options.platform, /* supportsNativePlatform */ true); realModuleName,
this._options.platform,
/* supportsNativePlatform */ true,
);
if (modulePath != null) { if (modulePath != null) {
const module = this._options.moduleCache.getModule(modulePath); const module = this._options.moduleCache.getModule(modulePath);
/* temporary until we strengthen the typing */ /* temporary until we strengthen the typing */
@ -349,8 +411,11 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
let packageName = realModuleName; let packageName = realModuleName;
let packagePath; let packagePath;
while (packageName && packageName !== '.') { while (packageName && packageName !== '.') {
packagePath = this._options.moduleMap packagePath = this._options.moduleMap.getPackage(
.getPackage(packageName, this._options.platform, /* supportsNativePlatform */ true); packageName,
this._options.platform,
/* supportsNativePlatform */ true,
);
if (packagePath != null) { if (packagePath != null) {
break; break;
} }
@ -358,21 +423,16 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
} }
if (packagePath != null) { if (packagePath != null) {
const package_ = this._options.moduleCache.getPackage(packagePath); const package_ = this._options.moduleCache.getPackage(packagePath);
/* temporary until we strengthen the typing */ /* temporary until we strengthen the typing */
invariant(package_.type === 'Package', 'expected Package type'); invariant(package_.type === 'Package', 'expected Package type');
const potentialModulePath = path.join( const potentialModulePath = path.join(
package_.root, package_.root,
path.relative(packageName, realModuleName) path.relative(packageName, realModuleName),
); );
return tryResolveSync( return tryResolveSync(
() => this._loadAsFile( () => this._loadAsFile(potentialModulePath, fromModule, toModuleName),
potentialModulePath,
fromModule,
toModuleName,
),
() => this._loadAsDir(potentialModulePath, fromModule, toModuleName), () => this._loadAsDir(potentialModulePath, fromModule, toModuleName),
); );
} }
@ -393,11 +453,14 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
} }
_resolveFileOrDir(fromModule: TModule, toModuleName: string): TModule { _resolveFileOrDir(fromModule: TModule, toModuleName: string): TModule {
const potentialModulePath = isAbsolutePath(toModuleName) ? const potentialModulePath = isAbsolutePath(toModuleName)
resolveWindowsPath(toModuleName) : ? resolveWindowsPath(toModuleName)
path.join(path.dirname(fromModule.path), toModuleName); : path.join(path.dirname(fromModule.path), toModuleName);
const realModuleName = this._redirectRequire(fromModule, potentialModulePath); const realModuleName = this._redirectRequire(
fromModule,
potentialModulePath,
);
if (realModuleName === false) { if (realModuleName === false) {
return this._loadAsFile( return this._loadAsFile(
ResolutionRequest.emptyModule, ResolutionRequest.emptyModule,
@ -408,7 +471,7 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
return tryResolveSync( return tryResolveSync(
() => this._loadAsFile(realModuleName, fromModule, toModuleName), () => this._loadAsFile(realModuleName, fromModule, toModuleName),
() => this._loadAsDir(realModuleName, fromModule, toModuleName) () => this._loadAsDir(realModuleName, fromModule, toModuleName),
); );
} }
@ -428,7 +491,8 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
if (isRelativeImport(realModuleName) || isAbsolutePath(realModuleName)) { if (isRelativeImport(realModuleName) || isAbsolutePath(realModuleName)) {
// derive absolute path /.../node_modules/fromModuleDir/realModuleName // derive absolute path /.../node_modules/fromModuleDir/realModuleName
const fromModuleParentIdx = fromModule.path.lastIndexOf('node_modules' + path.sep) + 13; const fromModuleParentIdx =
fromModule.path.lastIndexOf('node_modules' + path.sep) + 13;
const fromModuleDir = fromModule.path.slice( const fromModuleDir = fromModule.path.slice(
0, 0,
fromModule.path.indexOf(path.sep, fromModuleParentIdx), fromModule.path.indexOf(path.sep, fromModuleParentIdx),
@ -438,9 +502,11 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
} }
const searchQueue = []; const searchQueue = [];
for (let currDir = path.dirname(fromModule.path); for (
currDir !== '.' && currDir !== realPath.parse(fromModule.path).root; let currDir = path.dirname(fromModule.path);
currDir = path.dirname(currDir)) { currDir !== '.' && currDir !== realPath.parse(fromModule.path).root;
currDir = path.dirname(currDir)
) {
const searchPath = path.join(currDir, 'node_modules'); const searchPath = path.join(currDir, 'node_modules');
searchQueue.push(path.join(searchPath, realModuleName)); searchQueue.push(path.join(searchPath, realModuleName));
} }
@ -458,7 +524,11 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
const fullSearchQueue = searchQueue.concat(extraSearchQueue); const fullSearchQueue = searchQueue.concat(extraSearchQueue);
for (let i = 0; i < fullSearchQueue.length; ++i) { for (let i = 0; i < fullSearchQueue.length; ++i) {
const resolvedModule = this._tryResolveNodeDep(fullSearchQueue[i], fromModule, toModuleName); const resolvedModule = this._tryResolveNodeDep(
fullSearchQueue[i],
fromModule,
toModuleName,
);
if (resolvedModule != null) { if (resolvedModule != null) {
return resolvedModule; return resolvedModule;
} }
@ -473,12 +543,15 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
fromModule, fromModule,
toModuleName, toModuleName,
`Module does not exist in the module map${hint}\n` + `Module does not exist in the module map${hint}\n` +
displaySearchQueue.map(searchPath => ` ${path.dirname(searchPath)}\n`).join(', ') + '\n' + displaySearchQueue
`This might be related to https://github.com/facebook/react-native/issues/4968\n` + .map(searchPath => ` ${path.dirname(searchPath)}\n`)
`To resolve try the following:\n` + .join(', ') +
` 1. Clear watchman watches: \`watchman watch-del-all\`.\n` + '\n' +
` 2. Delete the \`node_modules\` folder: \`rm -rf node_modules && npm install\`.\n` + `This might be related to https://github.com/facebook/react-native/issues/4968\n` +
' 3. Reset packager cache: `rm -fr $TMPDIR/react-*` or `npm start -- --reset-cache`.' `To resolve try the following:\n` +
` 1. Clear watchman watches: \`watchman watch-del-all\`.\n` +
` 2. Delete the \`node_modules\` folder: \`rm -rf node_modules && npm install\`.\n` +
' 3. Reset packager cache: `rm -fr $TMPDIR/react-*` or `npm start -- --reset-cache`.',
); );
} }
@ -486,7 +559,11 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
* This is written as a separate function because "try..catch" blocks cause * This is written as a separate function because "try..catch" blocks cause
* the entire surrounding function to be deoptimized. * the entire surrounding function to be deoptimized.
*/ */
_tryResolveNodeDep(searchPath: string, fromModule: TModule, toModuleName: string): ?TModule { _tryResolveNodeDep(
searchPath: string,
fromModule: TModule,
toModuleName: string,
): ?TModule {
try { try {
return tryResolveSync( return tryResolveSync(
() => this._loadAsFile(searchPath, fromModule, toModuleName), () => this._loadAsFile(searchPath, fromModule, toModuleName),
@ -500,7 +577,11 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
} }
} }
_loadAsFile(potentialModulePath: string, fromModule: TModule, toModule: string): TModule { _loadAsFile(
potentialModulePath: string,
fromModule: TModule,
toModule: string,
): TModule {
if (this._options.helpers.isAssetFile(potentialModulePath)) { if (this._options.helpers.isAssetFile(potentialModulePath)) {
return this._loadAsAssetFile(potentialModulePath, fromModule, toModule); return this._loadAsAssetFile(potentialModulePath, fromModule, toModule);
} }
@ -540,14 +621,20 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
`File ${potentialModulePath} doesn't exist`, `File ${potentialModulePath} doesn't exist`,
); );
} }
} }
return this._options.moduleCache.getModule(file); return this._options.moduleCache.getModule(file);
} }
_loadAsAssetFile(potentialModulePath: string, fromModule: TModule, toModule: string): TModule { _loadAsAssetFile(
const {name, type} = getAssetDataFromName(potentialModulePath, this._options.platforms); potentialModulePath: string,
fromModule: TModule,
toModule: string,
): TModule {
const {name, type} = getAssetDataFromName(
potentialModulePath,
this._options.platforms,
);
let pattern = '^' + name + '(@[\\d\\.]+x)?'; let pattern = '^' + name + '(@[\\d\\.]+x)?';
if (this._options.platform != null) { if (this._options.platform != null) {
@ -570,10 +657,16 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
); );
} }
_loadAsDir(potentialDirPath: string, fromModule: TModule, toModule: string): TModule { _loadAsDir(
potentialDirPath: string,
fromModule: TModule,
toModule: string,
): TModule {
const packageJsonPath = path.join(potentialDirPath, 'package.json'); const packageJsonPath = path.join(potentialDirPath, 'package.json');
if (this._options.hasteFS.exists(packageJsonPath)) { if (this._options.hasteFS.exists(packageJsonPath)) {
const main = this._options.moduleCache.getPackage(packageJsonPath).getMain(); const main = this._options.moduleCache
.getPackage(packageJsonPath)
.getMain();
return tryResolveSync( return tryResolveSync(
() => this._loadAsFile(main, fromModule, toModule), () => this._loadAsFile(main, fromModule, toModule),
() => this._loadAsDir(main, fromModule, toModule), () => this._loadAsDir(main, fromModule, toModule),
@ -590,10 +683,8 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
_resetResolutionCache() { _resetResolutionCache() {
this._immediateResolutionCache = Object.create(null); this._immediateResolutionCache = Object.create(null);
} }
} }
function resolutionHash(modulePath, depName) { function resolutionHash(modulePath, depName) {
return `${path.resolve(modulePath)}:${depName}`; return `${path.resolve(modulePath)}:${depName}`;
} }
@ -615,7 +706,6 @@ class UnableToResolveError extends Error {
); );
this.type = this.name = 'UnableToResolveError'; this.type = this.name = 'UnableToResolveError';
} }
} }
function normalizePath(modulePath) { function normalizePath(modulePath) {
@ -628,8 +718,8 @@ function normalizePath(modulePath) {
return modulePath.replace(/\/$/, ''); return modulePath.replace(/\/$/, '');
} }
// HasteFS stores paths with backslashes on Windows, this ensures the path is // HasteFS stores paths with backslashes on Windows, this ensures the path is in
// in the proper format. Will also add drive letter if not present so `/root` will // the proper format. Will also add drive letter if not present so `/root` will
// resolve to `C:\root`. Noop on other platforms. // resolve to `C:\root`. Noop on other platforms.
function resolveWindowsPath(modulePath) { function resolveWindowsPath(modulePath) {
if (path.sep !== '\\') { if (path.sep !== '\\') {