From dd16d7427a07242e788f90733c0c3e96acf13c9a Mon Sep 17 00:00:00 2001 From: Jean Lauliac Date: Tue, 2 Jan 2018 03:09:41 -0800 Subject: [PATCH] ModuleResolution: extract resolveHasteName function Summary: Finally we can extract this function out, that remove any remaining dependency on the `TModule` generics and the like. Next steps are to push Metro-specific concepts out of the `resolveDependency` function and out of the module completely, after which the module will be ready to have its own unit tests, and be split into a `metro-resolve`. Reviewed By: cpojer Differential Revision: D6645333 fbshipit-source-id: a7915d646f888c29b410bf211f2e2bc4ec157676 --- .../DependencyGraph/ModuleResolution.js | 121 ++++++++++-------- 1 file changed, 66 insertions(+), 55 deletions(-) diff --git a/packages/metro/src/node-haste/DependencyGraph/ModuleResolution.js b/packages/metro/src/node-haste/DependencyGraph/ModuleResolution.js index e07ab553..031e0fab 100644 --- a/packages/metro/src/node-haste/DependencyGraph/ModuleResolution.js +++ b/packages/metro/src/node-haste/DependencyGraph/ModuleResolution.js @@ -125,60 +125,6 @@ class ModuleResolver { this._options = options; } - _resolveHasteDependency( - moduleName: string, - platform: string | null, - ): Result { - const modulePath = this._options.moduleMap.getModule( - moduleName, - platform, - /* supportsNativePlatform */ true, - ); - if (modulePath != null) { - return { - type: 'resolved', - resolution: {type: 'sourceFile', filePath: modulePath}, - }; - } - - let packageName = moduleName; - let packageJsonPath; - while (packageName && packageName !== '.') { - packageJsonPath = this._options.moduleMap.getPackage( - packageName, - platform, - /* supportsNativePlatform */ true, - ); - if (packageJsonPath != null) { - break; - } - packageName = path.dirname(packageName); - } - - if (packageJsonPath == null) { - return failedFor(); - } - // FIXME: `moduleCache.getModule` should return the directory path, not - // the `package.json` file path, because the directory is what's really - // representing the package. - const packageDirPath = path.dirname(packageJsonPath); - - const pathInModule = moduleName.substring(packageName.length + 1); - const potentialModulePath = path.join(packageDirPath, pathInModule); - - const context = { - ...this._options, - getPackageMainPath: this._getPackageMainPath, - }; - const result = resolveFileOrDir(context, potentialModulePath, platform); - if (result.type === 'resolved') { - return result; - } - const {candidates} = result; - const opts = {moduleName, packageName, pathInModule, candidates}; - throw new MissingFileInHastePackageError(opts); - } - _redirectRequire(fromModule: TModule, modulePath: string): string | false { const pck = fromModule.getPackage(); if (pck) { @@ -241,7 +187,23 @@ class ModuleResolver { // At that point we only have module names that // aren't relative paths nor absolute paths. if (allowHaste) { - const result = this._resolveHasteDependency( + const result = resolveHasteName( + { + ...this._options, + resolveHasteModule: name => + this._options.moduleMap.getModule( + name, + platform, + /* supportsNativePlatform */ true, + ), + resolveHastePackage: name => + this._options.moduleMap.getPackage( + name, + platform, + /* supportsNativePlatform */ true, + ), + getPackageMainPath: this._getPackageMainPath, + }, normalizePath(realModuleName), platform, ); @@ -372,6 +334,55 @@ class ModuleResolver { } } +type HasteContext = FileOrDirContext & { + /** + * Given a name, this should return the full path to the file that provides + * a Haste module of that name. Ex. for `Foo` it may return `/smth/Foo.js`. + */ + +resolveHasteModule: (name: string) => ?string, + /** + * Given a name, this should return the full path to the package manifest that + * provides a Haste package of that name. Ex. for `Foo` it may return + * `/smth/Foo/package.json`. + */ + +resolveHastePackage: (name: string) => ?string, +}; + +/** + * Resolve a module as a Haste module or package. For example we might try to + * resolve `Foo`, that is provided by file `/smth/Foo.js`. Or, in the case of + * a Haste package, it could be `/smth/Foo/index.js`. + */ +function resolveHasteName( + context: HasteContext, + moduleName: string, + platform: string | null, +): Result { + const modulePath = context.resolveHasteModule(moduleName); + if (modulePath != null) { + return resolvedAs({type: 'sourceFile', filePath: modulePath}); + } + let packageName = moduleName; + let packageJsonPath = context.resolveHastePackage(packageName); + while (packageJsonPath == null && packageName && packageName !== '.') { + packageName = path.dirname(packageName); + packageJsonPath = context.resolveHastePackage(packageName); + } + if (packageJsonPath == null) { + return failedFor(); + } + const packageDirPath = path.dirname(packageJsonPath); + const pathInModule = moduleName.substring(packageName.length + 1); + const potentialModulePath = path.join(packageDirPath, pathInModule); + const result = resolveFileOrDir(context, potentialModulePath, platform); + if (result.type === 'resolved') { + return result; + } + const {candidates} = result; + const opts = {moduleName, packageName, pathInModule, candidates}; + throw new MissingFileInHastePackageError(opts); +} + class MissingFileInHastePackageError extends Error { candidates: FileAndDirCandidates; moduleName: string;