mirror of https://github.com/status-im/metro.git
metro: ModuleResolution: break down more functions
Reviewed By: davidaurelio Differential Revision: D6610652 fbshipit-source-id: 4c39fb69fe9b5eda96c1dca6697ff9da46df2cda
This commit is contained in:
parent
e4cba8e2e2
commit
494422aa43
|
@ -295,7 +295,11 @@ class ModuleResolver<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 result = this._loadAsFileOrDir(fullSearchQueue[i], platform);
|
const context = {
|
||||||
|
...this._options,
|
||||||
|
getPackageMainPath: this._getPackageMainPath,
|
||||||
|
};
|
||||||
|
const result = resolveFileOrDir(context, fullSearchQueue[i], platform);
|
||||||
// Eventually we should aggregate the candidates so that we can
|
// Eventually we should aggregate the candidates so that we can
|
||||||
// report them with more accuracy in the error below.
|
// report them with more accuracy in the error below.
|
||||||
if (result.type === 'resolved') {
|
if (result.type === 'resolved') {
|
||||||
|
@ -325,6 +329,11 @@ class ModuleResolver<TModule: Moduleish, TPackage: Packageish> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_getPackageMainPath = (packageJsonPath: string): string => {
|
||||||
|
const package_ = this._options.moduleCache.getPackage(packageJsonPath);
|
||||||
|
return package_.getMain();
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Eventually we'd like to remove all the exception being throw in the middle
|
* Eventually we'd like to remove all the exception being throw in the middle
|
||||||
* of the resolution algorithm, instead keeping track of tentatives in a
|
* of the resolution algorithm, instead keeping track of tentatives in a
|
||||||
|
@ -338,7 +347,11 @@ class ModuleResolver<TModule: Moduleish, TPackage: Packageish> {
|
||||||
toModuleName: string,
|
toModuleName: string,
|
||||||
platform: string | null,
|
platform: string | null,
|
||||||
): TModule {
|
): TModule {
|
||||||
const result = this._loadAsFileOrDir(potentialModulePath, platform);
|
const context = {
|
||||||
|
...this._options,
|
||||||
|
getPackageMainPath: this._getPackageMainPath,
|
||||||
|
};
|
||||||
|
const result = resolveFileOrDir(context, potentialModulePath, platform);
|
||||||
if (result.type === 'resolved') {
|
if (result.type === 'resolved') {
|
||||||
return this._getFileResolvedModule(result.resolution);
|
return this._getFileResolvedModule(result.resolution);
|
||||||
}
|
}
|
||||||
|
@ -379,30 +392,6 @@ class ModuleResolver<TModule: Moduleish, TPackage: Packageish> {
|
||||||
throw new Error('switch is not exhaustive');
|
throw new Error('switch is not exhaustive');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* In the NodeJS-style module resolution scheme we want to check potential
|
|
||||||
* paths both as directories and as files. For example, `foo/bar` may resolve
|
|
||||||
* to `foo/bar.js` (preferred), but it might also be `foo/bar/index.js`, or
|
|
||||||
* even a package directory.
|
|
||||||
*/
|
|
||||||
_loadAsFileOrDir(
|
|
||||||
potentialModulePath: string,
|
|
||||||
platform: string | null,
|
|
||||||
): Result<FileResolution, FileAndDirCandidates> {
|
|
||||||
const dirPath = path.dirname(potentialModulePath);
|
|
||||||
const fileNameHint = path.basename(potentialModulePath);
|
|
||||||
const {_options} = this;
|
|
||||||
const fileResult = resolveFile(_options, dirPath, fileNameHint, platform);
|
|
||||||
if (fileResult.type === 'resolved') {
|
|
||||||
return fileResult;
|
|
||||||
}
|
|
||||||
const dirResult = this._loadAsDir(potentialModulePath, platform);
|
|
||||||
if (dirResult.type === 'resolved') {
|
|
||||||
return dirResult;
|
|
||||||
}
|
|
||||||
return failedFor({file: fileResult.candidates, dir: dirResult.candidates});
|
|
||||||
}
|
|
||||||
|
|
||||||
_getEmptyModule(fromModule: TModule, toModuleName: string): TModule {
|
_getEmptyModule(fromModule: TModule, toModuleName: string): TModule {
|
||||||
const {moduleCache} = this._options;
|
const {moduleCache} = this._options;
|
||||||
const module = moduleCache.getModule(ModuleResolver.EMPTY_MODULE);
|
const module = moduleCache.getModule(ModuleResolver.EMPTY_MODULE);
|
||||||
|
@ -415,63 +404,101 @@ class ModuleResolver<TModule: Moduleish, TPackage: Packageish> {
|
||||||
"could not resolve `${ModuleResolver.EMPTY_MODULE}'",
|
"could not resolve `${ModuleResolver.EMPTY_MODULE}'",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileOrDirContext = FileContext & {
|
||||||
/**
|
/**
|
||||||
* Try to resolve a potential path as if it was a directory-based module.
|
* This should return the path of the "main" module of the specified
|
||||||
* Either this is a directory that contains a package, or that the directory
|
* `package.json` file, after post-processing: for example, applying the
|
||||||
* contains an index file. If it fails to resolve these options, it returns
|
* 'browser' field if necessary.
|
||||||
* `null` and fills the array of `candidates` that were tried.
|
|
||||||
*
|
*
|
||||||
* For example we could try to resolve `/foo/bar`, that would eventually
|
* FIXME: move the post-processing here. Right now it is
|
||||||
* resolve to `/foo/bar/lib/index.ios.js` if we're on platform iOS and that
|
* located in `node-haste/Package.js`, and fully duplicated in
|
||||||
* `bar` contains a package which entry point is `./lib/index` (or `./lib`).
|
* `ModuleGraph/node-haste/Package.js` (!)
|
||||||
*/
|
*/
|
||||||
_loadAsDir(
|
+getPackageMainPath: (packageJsonPath: string) => string,
|
||||||
potentialDirPath: string,
|
};
|
||||||
platform: string | null,
|
|
||||||
): Result<FileResolution, DirCandidates> {
|
|
||||||
const packageJsonPath = path.join(potentialDirPath, 'package.json');
|
|
||||||
if (this._options.doesFileExist(packageJsonPath)) {
|
|
||||||
return this._loadAsPackage(packageJsonPath, platform);
|
|
||||||
}
|
|
||||||
const opts = this._options;
|
|
||||||
const result = resolveFile(opts, potentialDirPath, 'index', platform);
|
|
||||||
if (result.type === 'resolved') {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return failedFor({type: 'index', file: result.candidates});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Right now we just consider it a failure to resolve if we couldn't find the
|
* In the NodeJS-style module resolution scheme we want to check potential
|
||||||
* file corresponding to the `main` indicated by a package. Argument can be
|
* paths both as directories and as files. For example, `/foo/bar` may resolve
|
||||||
* made this should be changed so that failing to find the `main` is not a
|
* to `/foo/bar.js` (preferred), but it might also be `/foo/bar/index.js`, or
|
||||||
* resolution failure, but identified instead as a corrupted or invalid
|
* even a package directory.
|
||||||
* package (or that a package only supports a specific platform, etc.)
|
*/
|
||||||
*/
|
function resolveFileOrDir(
|
||||||
_loadAsPackage(
|
context: FileOrDirContext,
|
||||||
packageJsonPath: string,
|
potentialModulePath: string,
|
||||||
platform: string | null,
|
platform: string | null,
|
||||||
): Result<FileResolution, DirCandidates> {
|
): Result<FileResolution, FileAndDirCandidates> {
|
||||||
const package_ = this._options.moduleCache.getPackage(packageJsonPath);
|
const dirPath = path.dirname(potentialModulePath);
|
||||||
const mainPrefixPath = package_.getMain();
|
const fileNameHint = path.basename(potentialModulePath);
|
||||||
const dirPath = path.dirname(mainPrefixPath);
|
const fileResult = resolveFile(context, dirPath, fileNameHint, platform);
|
||||||
const prefixName = path.basename(mainPrefixPath);
|
if (fileResult.type === 'resolved') {
|
||||||
const opts = this._options;
|
return fileResult;
|
||||||
const fileResult = resolveFile(opts, dirPath, prefixName, platform);
|
|
||||||
if (fileResult.type === 'resolved') {
|
|
||||||
return fileResult;
|
|
||||||
}
|
|
||||||
const dirResult = this._loadAsDir(mainPrefixPath, platform);
|
|
||||||
if (dirResult.type === 'resolved') {
|
|
||||||
return dirResult;
|
|
||||||
}
|
|
||||||
return failedFor({
|
|
||||||
type: 'package',
|
|
||||||
dir: dirResult.candidates,
|
|
||||||
file: fileResult.candidates,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
const dirResult = resolveDir(context, potentialModulePath, platform);
|
||||||
|
if (dirResult.type === 'resolved') {
|
||||||
|
return dirResult;
|
||||||
|
}
|
||||||
|
return failedFor({file: fileResult.candidates, dir: dirResult.candidates});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to resolve a potential path as if it was a directory-based module.
|
||||||
|
* Either this is a directory that contains a package, or that the directory
|
||||||
|
* contains an index file. If it fails to resolve these options, it returns
|
||||||
|
* `null` and fills the array of `candidates` that were tried.
|
||||||
|
*
|
||||||
|
* For example we could try to resolve `/foo/bar`, that would eventually
|
||||||
|
* resolve to `/foo/bar/lib/index.ios.js` if we're on platform iOS and that
|
||||||
|
* `bar` contains a package which entry point is `./lib/index` (or `./lib`).
|
||||||
|
*/
|
||||||
|
function resolveDir(
|
||||||
|
context: FileOrDirContext,
|
||||||
|
potentialDirPath: string,
|
||||||
|
platform: string | null,
|
||||||
|
): Result<FileResolution, DirCandidates> {
|
||||||
|
const packageJsonPath = path.join(potentialDirPath, 'package.json');
|
||||||
|
if (context.doesFileExist(packageJsonPath)) {
|
||||||
|
return resolvePackage(context, packageJsonPath, platform);
|
||||||
|
}
|
||||||
|
const result = resolveFile(context, potentialDirPath, 'index', platform);
|
||||||
|
if (result.type === 'resolved') {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return failedFor({type: 'index', file: result.candidates});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the main module of a package.
|
||||||
|
*
|
||||||
|
* Right now we just consider it a failure to resolve if we couldn't find the
|
||||||
|
* file corresponding to the `main` indicated by a package. This is incorrect:
|
||||||
|
* failing to find the `main` is not a resolution failure, but instead means the
|
||||||
|
* package is corrupted or invalid (or that a package only supports a specific
|
||||||
|
* platform, etc.)
|
||||||
|
*/
|
||||||
|
function resolvePackage(
|
||||||
|
context: FileOrDirContext,
|
||||||
|
packageJsonPath: string,
|
||||||
|
platform: string | null,
|
||||||
|
): Result<FileResolution, DirCandidates> {
|
||||||
|
const mainPrefixPath = context.getPackageMainPath(packageJsonPath);
|
||||||
|
const dirPath = path.dirname(mainPrefixPath);
|
||||||
|
const prefixName = path.basename(mainPrefixPath);
|
||||||
|
const fileResult = resolveFile(context, dirPath, prefixName, platform);
|
||||||
|
if (fileResult.type === 'resolved') {
|
||||||
|
return fileResult;
|
||||||
|
}
|
||||||
|
const dirResult = resolveDir(context, mainPrefixPath, platform);
|
||||||
|
if (dirResult.type === 'resolved') {
|
||||||
|
return dirResult;
|
||||||
|
}
|
||||||
|
return failedFor({
|
||||||
|
type: 'package',
|
||||||
|
dir: dirResult.candidates,
|
||||||
|
file: fileResult.candidates,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
type FileContext = {
|
type FileContext = {
|
||||||
|
|
Loading…
Reference in New Issue