PHP WebShell
Текущая директория: /usr/lib/node_modules/bitgo/node_modules/metro-resolver/src
Просмотр файла: resolve.js.flow
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
* @oncall react_native
*/
import type {
FileAndDirCandidates,
FileCandidates,
Resolution,
ResolutionContext,
Result,
} from './types';
import FailedToResolveNameError from './errors/FailedToResolveNameError';
import FailedToResolvePathError from './errors/FailedToResolvePathError';
import formatFileCandidates from './errors/formatFileCandidates';
import InvalidPackageConfigurationError from './errors/InvalidPackageConfigurationError';
import InvalidPackageError from './errors/InvalidPackageError';
import PackageImportNotResolvedError from './errors/PackageImportNotResolvedError';
import PackagePathNotExportedError from './errors/PackagePathNotExportedError';
import {resolvePackageTargetFromExports} from './PackageExportsResolve';
import {resolvePackageTargetFromImports} from './PackageImportsResolve';
import {getPackageEntryPoint, redirectModulePath} from './PackageResolve';
import resolveAsset from './resolveAsset';
import isAssetFile from './utils/isAssetFile';
import path from 'path';
type ParsedBareSpecifier = $ReadOnly<{
isSinglePart: boolean,
isValidPackageName: boolean,
firstPart: string,
normalizedSpecifier: string,
packageName: string,
posixSubpath: string,
}>;
export default function resolve(
context: ResolutionContext,
moduleName: string,
platform: string | null,
): Resolution {
const resolveRequest = context.resolveRequest;
if (
resolveRequest &&
// Prevent infinite recursion in the trivial case
resolveRequest !== resolve
) {
return resolveRequest(
Object.freeze({...context, resolveRequest: resolve}),
moduleName,
platform,
);
}
if (isRelativeImport(moduleName) || path.isAbsolute(moduleName)) {
const result = resolveModulePath(context, moduleName, platform);
if (result.type === 'failed') {
throw new FailedToResolvePathError(result.candidates);
}
return result.resolution;
} else if (isSubpathImport(moduleName)) {
const pkg = context.getPackageForModule(context.originModulePath);
const importsField = pkg?.packageJson.imports;
if (pkg == null) {
throw new PackageImportNotResolvedError({
importSpecifier: moduleName,
reason: `Could not find a package.json file relative to module ${context.originModulePath}`,
});
} else if (importsField == null) {
throw new PackageImportNotResolvedError({
importSpecifier: moduleName,
reason: `Missing field "imports" in package.json. Check package.json at: ${pkg.rootPath}`,
});
} else {
try {
const packageImportsResult = resolvePackageTargetFromImports(
context,
pkg.rootPath,
moduleName,
importsField,
platform,
);
if (packageImportsResult != null) {
return packageImportsResult;
}
} catch (e) {
if (e instanceof PackageImportNotResolvedError) {
context.unstable_logWarning(
e.message +
' Falling back to file-based resolution. Consider updating the ' +
'call site or checking there is a matching subpath inside "imports" of package.json.',
);
} else if (e instanceof InvalidPackageConfigurationError) {
context.unstable_logWarning(
e.message + ' Falling back to file-based resolution.',
);
} else {
throw e;
}
}
}
}
const realModuleName = redirectModulePath(context, moduleName);
// exclude
if (realModuleName === false) {
return {type: 'empty'};
}
const {originModulePath} = context;
const isDirectImport =
isRelativeImport(realModuleName) || path.isAbsolute(realModuleName);
if (isDirectImport) {
// derive absolute path /.../node_modules/originModuleDir/realModuleName
const fromModuleParentIdx =
originModulePath.lastIndexOf('node_modules' + path.sep) + 13;
const originModuleDir = originModulePath.slice(
0,
originModulePath.indexOf(path.sep, fromModuleParentIdx),
);
const absPath = path.join(originModuleDir, realModuleName);
const result = resolveModulePath(context, absPath, platform);
if (result.type === 'failed') {
throw new FailedToResolvePathError(result.candidates);
}
return result.resolution;
}
/**
* At this point, realModuleName is not a "direct" (absolute or relative)
* import, so it's a bare specifier - for our purposes either Haste name
* or a package specifier.
*/
const parsedSpecifier = parseBareSpecifier(realModuleName);
if (context.allowHaste) {
if (parsedSpecifier.isSinglePart) {
const result = context.resolveHasteModule(parsedSpecifier.firstPart);
if (result != null) {
return {type: 'sourceFile', filePath: result};
}
}
if (parsedSpecifier.isValidPackageName) {
const result = resolveHastePackage(context, parsedSpecifier, platform);
if (result.type === 'resolved') {
return result.resolution;
}
}
}
/**
* realModuleName is now a package specifier.
*/
const {disableHierarchicalLookup} = context;
const nodeModulesPaths = [];
let next = path.dirname(originModulePath);
if (!disableHierarchicalLookup) {
let candidate;
do {
candidate = next;
const nodeModulesPath = candidate.endsWith(path.sep)
? candidate + 'node_modules'
: candidate + path.sep + 'node_modules';
nodeModulesPaths.push(nodeModulesPath);
next = path.dirname(candidate);
} while (candidate !== next);
}
// Fall back to `nodeModulesPaths` after hierarchical lookup, similar to $NODE_PATH
nodeModulesPaths.push(...context.nodeModulesPaths);
const extraPaths = [];
const {extraNodeModules} = context;
if (extraNodeModules && extraNodeModules[parsedSpecifier.packageName]) {
const newPackageName = extraNodeModules[parsedSpecifier.packageName];
extraPaths.push(path.join(newPackageName, parsedSpecifier.posixSubpath));
}
const allDirPaths = nodeModulesPaths
.map(nodeModulePath => {
let lookupResult = null;
// Insight: The module can only exist if there is a `node_modules` at
// this path. Redirections cannot succeed, because we will never look
// beyond a node_modules path segment for finding the closest
// package.json. Moreover, if the specifier contains a '/' separator,
// the first part *must* be a real directory, because it is the
// shallowest path that can possibly contain a redirecting package.json.
const mustBeDirectory =
parsedSpecifier.posixSubpath !== '.' ||
parsedSpecifier.packageName.length > parsedSpecifier.firstPart.length
? nodeModulePath + path.sep + parsedSpecifier.firstPart
: nodeModulePath;
lookupResult = context.fileSystemLookup(mustBeDirectory);
if (!lookupResult.exists || lookupResult.type !== 'd') {
return null;
}
return path.join(nodeModulePath, realModuleName);
})
.filter(Boolean)
.concat(extraPaths);
for (let i = 0; i < allDirPaths.length; ++i) {
const candidate = redirectModulePath(context, allDirPaths[i]);
if (candidate === false) {
return {type: 'empty'};
}
// candidate should be absolute here - we assume that redirectModulePath
// always returns an absolute path when given an absolute path.
const result = resolvePackage(context, candidate, platform);
if (result.type === 'resolved') {
return result.resolution;
}
}
throw new FailedToResolveNameError(nodeModulesPaths, extraPaths);
}
function parseBareSpecifier(specifier: string): ParsedBareSpecifier {
const normalized =
path.sep === '/' ? specifier : specifier.replaceAll('\\', '/');
const firstSepIdx = normalized.indexOf('/');
if (normalized.startsWith('@') && firstSepIdx !== -1) {
const secondSepIdx = normalized.indexOf('/', firstSepIdx + 1);
if (secondSepIdx === -1) {
// @foo/bar (valid scoped, no subpath)
return {
isSinglePart: false,
isValidPackageName: true,
firstPart: normalized.slice(0, firstSepIdx),
normalizedSpecifier: normalized,
packageName: normalized,
posixSubpath: '.',
};
}
// @foo/bar[/subpath] (valid scoped with subpath)
return {
isSinglePart: false,
isValidPackageName: true,
firstPart: normalized.slice(0, firstSepIdx),
normalizedSpecifier: normalized,
packageName: normalized.slice(0, secondSepIdx),
posixSubpath: '.' + normalized.slice(secondSepIdx),
};
}
// foo or @foo, no subpath. Valid if doesn't start with '@'.
if (firstSepIdx === -1) {
return {
isSinglePart: true,
isValidPackageName: !normalized.startsWith('@'),
firstPart: normalized,
normalizedSpecifier: normalized,
packageName: normalized,
posixSubpath: '.',
};
}
const packageName = normalized.slice(0, firstSepIdx);
// foo/subpath, valid, not scoped, with subpath
return {
isSinglePart: false,
isValidPackageName: true,
firstPart: packageName,
normalizedSpecifier: normalized,
packageName,
posixSubpath: '.' + normalized.slice(firstSepIdx),
};
}
/**
* Resolve any kind of module path, whether it's a file or a directory.
* For example we may want to resolve './foobar'. The closest
* `package.json` may define a redirection for this path, for example
* `/smth/lib/foobar`, that may be further resolved to
* `/smth/lib/foobar/index.ios.js`.
*/
function resolveModulePath(
context: ResolutionContext,
toModuleName: string,
platform: string | null,
): Result<Resolution, FileAndDirCandidates> {
// System-separated absolute path
const modulePath = path.isAbsolute(toModuleName)
? path.sep === '/'
? toModuleName
: toModuleName.replaceAll('/', '\\')
: path.join(path.dirname(context.originModulePath), toModuleName);
const redirectedPath = redirectModulePath(context, modulePath);
if (redirectedPath === false) {
return resolvedAs({type: 'empty'});
}
const dirPath = path.dirname(redirectedPath);
const fileName = path.basename(redirectedPath);
const fileResult: ?Result<Resolution, FileCandidates> =
// require('./foo/') should never resolve to ./foo.js - a trailing slash
// implies we should resolve as a directory only.
redirectedPath.endsWith(path.sep)
? null
: resolveFile(context, dirPath, fileName, platform);
if (fileResult != null && fileResult.type === 'resolved') {
return fileResult;
}
const dirResult = resolvePackageEntryPoint(context, redirectedPath, platform);
if (dirResult.type === 'resolved') {
return dirResult;
}
return failedFor({
file: fileResult?.candidates ?? null,
dir: dirResult.candidates,
});
}
/**
* Resolve a specifier as a Haste package.
*/
function resolveHastePackage(
context: ResolutionContext,
{
normalizedSpecifier: moduleName,
packageName,
posixSubpath: pathInModule,
}: ParsedBareSpecifier,
platform: string | null,
): Result<Resolution, void> {
const packageJsonPath = context.resolveHastePackage(packageName);
if (packageJsonPath == null) {
return failedFor();
}
const potentialModulePath = path.join(packageJsonPath, '..', pathInModule);
const result = resolvePackage(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;
packageName: string;
pathInModule: string;
constructor(opts: {
+candidates: FileAndDirCandidates,
+moduleName: string,
+packageName: string,
+pathInModule: string,
}) {
super(
`While resolving module \`${opts.moduleName}\`, ` +
`the Haste package \`${opts.packageName}\` was found. However the ` +
`subpath \`${opts.pathInModule}\` could not be found within ` +
'the package. Indeed, none of these files exist:\n\n' +
[opts.candidates.file, opts.candidates.dir]
.filter(Boolean)
.map(candidates => ` * \`${formatFileCandidates(candidates)}\``)
.join('\n'),
);
// $FlowFixMe[unsafe-object-assign]
Object.assign(this, opts);
}
}
/**
* Resolve a package entry point or subpath target.
*
* This should be used when resolving a bare import specifier prefixed with the
* package name. Use `resolveModulePath` instead to scope to legacy "browser"
* spec behaviour, which is also applicable to relative and absolute imports.
*/
function resolvePackage(
context: ResolutionContext,
/**
* The absolute path to a file or directory that may be contained within an
* npm package, e.g. from being joined with `context.extraNodeModules`.
*/
absoluteCandidatePath: string,
platform: string | null,
): Result<Resolution, FileAndDirCandidates> {
if (context.unstable_enablePackageExports) {
const pkg = context.getPackageForModule(absoluteCandidatePath);
const exportsField = pkg?.packageJson.exports;
if (pkg != null && exportsField != null) {
try {
const packageExportsResult = resolvePackageTargetFromExports(
context,
pkg.rootPath,
absoluteCandidatePath,
pkg.packageRelativePath,
exportsField,
platform,
);
if (packageExportsResult != null) {
return resolvedAs(packageExportsResult);
}
} catch (e) {
if (e instanceof PackagePathNotExportedError) {
context.unstable_logWarning(
e.message +
' Falling back to file-based resolution. Consider updating the ' +
'call site or asking the package maintainer(s) to expose this API.',
);
} else if (e instanceof InvalidPackageConfigurationError) {
context.unstable_logWarning(
e.message + ' Falling back to file-based resolution.',
);
} else {
throw e;
}
}
}
}
return resolveModulePath(context, absoluteCandidatePath, platform);
}
/**
* Attempt to resolve a module path as an npm package entry point, or resolve as
* a file if no `package.json` file is present.
*
* Implements legacy (non-exports) package resolution behaviour based on the
* ["browser" field spec](https://github.com/defunctzombie/package-browser-field-spec):
* - Looks for a "main" entry point based on `context.mainFields`.
* - Considers any "main" subpaths after expending source and platform-specific
* extensions, e.g. `./lib/index` -> `./lib/index.ios.js`.
* - Falls back to a child `index.js` file, e.g. `./lib` -> `./lib/index.js`.
*/
function resolvePackageEntryPoint(
context: ResolutionContext,
packagePath: string,
platform: string | null,
): Result<Resolution, FileCandidates> {
const dirLookup = context.fileSystemLookup(packagePath);
if (dirLookup.exists == false || dirLookup.type !== 'd') {
return failedFor({
type: 'sourceFile',
filePathPrefix: packagePath,
candidateExts: [],
});
}
const packageJsonPath = path.join(packagePath, 'package.json');
if (!context.doesFileExist(packageJsonPath)) {
return resolveFile(context, packagePath, 'index', platform);
}
const packageInfo = {
rootPath: path.dirname(packageJsonPath),
packageJson: context.getPackage(packageJsonPath) ?? {},
};
const mainModulePath = path.join(
packageInfo.rootPath,
getPackageEntryPoint(context, packageInfo, platform),
);
const fileResult = resolveFile(
context,
path.dirname(mainModulePath),
path.basename(mainModulePath),
platform,
);
if (fileResult.type === 'resolved') {
return fileResult;
}
// Fallback: Attempt to resolve any file at <subpath>/index.js
const indexResult = resolveFile(context, mainModulePath, 'index', platform);
if (indexResult.type !== 'resolved') {
throw new InvalidPackageError({
packageJsonPath,
mainModulePath,
fileCandidates: fileResult.candidates,
indexCandidates: indexResult.candidates,
});
}
return indexResult;
}
/**
* Given a file name for a particular directory, return a resolution result
* depending on whether or not we found the corresponding module as a file. For
* example, we might ask for `foo.png`, that resolves to
* `['/js/beep/foo.ios.png']`. Or we may ask for `boop`, that resolves to
* `/js/boop.android.ts`. On the other hand this function does not resolve
* directory-based module names: for example `boop` will not resolve to
* `/js/boop/index.js` (see `_loadAsDir` for that).
*/
function resolveFile(
context: ResolutionContext,
dirPath: string,
fileName: string,
platform: string | null,
): Result<Resolution, FileCandidates> {
if (isAssetFile(fileName, context.assetExts)) {
const assetResolutions = resolveAsset(
context,
path.join(dirPath, fileName),
);
if (assetResolutions == null) {
return failedFor({type: 'asset', name: fileName});
}
return resolvedAs(assetResolutions);
}
const candidateExts: Array<string> = [];
const filePathPrefix = path.join(dirPath, fileName);
const sfContext = {...context, candidateExts, filePathPrefix};
const sourceFileResolution = resolveSourceFile(sfContext, platform);
if (sourceFileResolution != null) {
if (typeof sourceFileResolution === 'string') {
return resolvedAs({type: 'sourceFile', filePath: sourceFileResolution});
}
return resolvedAs(sourceFileResolution);
}
return failedFor({type: 'sourceFile', filePathPrefix, candidateExts});
}
type SourceFileContext = $ReadOnly<{
...ResolutionContext,
candidateExts: Array<string>,
filePathPrefix: string,
}>;
// Either a full path, or a restricted subset of Resolution.
type SourceFileResolution = ?string | $ReadOnly<{type: 'empty'}>;
/**
* A particular 'base path' can resolve to a number of possibilities depending
* on the context. For example `foo/bar` could resolve to `foo/bar.ios.js`, or
* to `foo/bar.js`. If can also resolve to the bare path `foo/bar` itself, as
* supported by Node.js resolution. On the other hand it doesn't support
* `foo/bar.ios`, for historical reasons.
*
* Return the full path of the resolved module, `null` if no resolution could
* be found, or `{type: 'empty'}` if redirected to an empty module.
*/
function resolveSourceFile(
context: SourceFileContext,
platform: ?string,
): SourceFileResolution {
let filePath = resolveSourceFileForAllExts(context, '');
if (filePath) {
return filePath;
}
const {sourceExts} = context;
for (let i = 0; i < sourceExts.length; i++) {
const ext = `.${sourceExts[i]}`;
filePath = resolveSourceFileForAllExts(context, ext, platform);
if (filePath != null) {
return filePath;
}
}
return null;
}
/**
* For a particular extension, ex. `js`, we want to try a few possibilities,
* such as `foo.ios.js`, `foo.native.js`, and of course `foo.js`. Return the
* full path of the resolved module, `null` if no resolution could be found, or
* `{type: 'empty'}` if redirected to an empty module.
*/
function resolveSourceFileForAllExts(
context: SourceFileContext,
sourceExt: string,
platform: ?string,
): SourceFileResolution {
if (platform != null) {
const ext = `.${platform}${sourceExt}`;
const filePath = resolveSourceFileForExt(context, ext);
if (filePath) {
return filePath;
}
}
if (context.preferNativePlatform && sourceExt !== '') {
const filePath = resolveSourceFileForExt(context, `.native${sourceExt}`);
if (filePath) {
return filePath;
}
}
const filePath = resolveSourceFileForExt(context, sourceExt);
return filePath;
}
/**
* We try to resolve a single possible extension. If it doesn't exist, then
* we make sure to add the extension to a list of candidates for reporting.
*/
function resolveSourceFileForExt(
context: SourceFileContext,
extension: string,
): SourceFileResolution {
const filePath = `${context.filePathPrefix}${extension}`;
const redirectedPath =
// Any redirections for the bare path have already happened
extension !== '' ? redirectModulePath(context, filePath) : filePath;
if (redirectedPath === false) {
return {type: 'empty'};
}
const lookupResult = context.fileSystemLookup(redirectedPath);
if (lookupResult.exists && lookupResult.type === 'f') {
return lookupResult.realPath;
}
context.candidateExts.push(extension);
return null;
}
function isRelativeImport(filePath: string) {
return /^[.][.]?(?:[/]|$)/.test(filePath);
}
function isSubpathImport(filePath: string) {
return filePath.startsWith('#');
}
function resolvedAs<TResolution, TCandidates>(
resolution: TResolution,
): Result<TResolution, TCandidates> {
return {type: 'resolved', resolution};
}
function failedFor<TResolution, TCandidates>(
candidates: TCandidates,
): Result<TResolution, TCandidates> {
return {type: 'failed', candidates};
}
Выполнить команду
Для локальной разработки. Не используйте в интернете!