PHP WebShell
Текущая директория: /usr/lib/node_modules/bitgo/node_modules/metro/src/ModuleGraph/worker
Просмотр файла: collectDependencies.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.
*
* @format
* @flow
*/
import type {NodePath} from '@babel/traverse';
import type {CallExpression, Identifier, StringLiteral} from '@babel/types';
import type {
AllowOptionalDependencies,
AsyncDependencyType,
} from 'metro/private/DeltaBundler/types';
import generate from '@babel/generator';
import template from '@babel/template';
import traverse from '@babel/traverse';
import * as types from '@babel/types';
import {isImport, isProgram} from '@babel/types';
import crypto from 'crypto';
import invariant from 'invariant';
import nullthrows from 'nullthrows';
type ImportDependencyOptions = $ReadOnly<{
asyncType: AsyncDependencyType,
isESMImport: boolean,
}>;
export type Dependency = $ReadOnly<{
data: DependencyData,
name: string,
}>;
// TODO: Convert to a Flow enum
export type ContextMode = 'sync' | 'eager' | 'lazy' | 'lazy-once';
type ContextFilter = $ReadOnly<{pattern: string, flags: string}>;
export type RequireContextParams = $ReadOnly<{
/* Should search for files recursively. Optional, default `true` when `require.context` is used */
recursive: boolean,
/* Filename filter pattern for use in `require.context`. Optional, default `.*` (any file) when `require.context` is used */
filter: $ReadOnly<ContextFilter>,
/** Mode for resolving dynamic dependencies. Defaults to `sync` */
mode: ContextMode,
}>;
type DependencyData = $ReadOnly<{
// A locally unique key for this dependency within the current module.
key: string,
// If null, then the dependency is synchronous.
// (ex. `require('foo')`)
asyncType: AsyncDependencyType | null,
// If true, the dependency is declared using an ESM import, e.g.
// "import x from 'y'" or "await import('z')". A resolver should typically
// use this to assert either "import" or "require" for conditional exports
// and subpath imports.
isESMImport: boolean,
isOptional?: boolean,
locs: $ReadOnlyArray<BabelSourceLocation>,
/** Context for requiring a collection of modules. */
contextParams?: RequireContextParams,
}>;
export type MutableInternalDependency = {
...DependencyData,
locs: Array<BabelSourceLocation>,
index: number,
name: string,
};
export type InternalDependency = $ReadOnly<MutableInternalDependency>;
export type State = {
asyncRequireModulePathStringLiteral: ?StringLiteral,
dependencyCalls: Set<string>,
dependencyRegistry: DependencyRegistry,
dependencyTransformer: DependencyTransformer,
dynamicRequires: DynamicRequiresBehavior,
dependencyMapIdentifier: ?Identifier,
keepRequireNames: boolean,
allowOptionalDependencies: AllowOptionalDependencies,
/** Enable `require.context` statements which can be used to import multiple files in a directory. */
unstable_allowRequireContext: boolean,
unstable_isESMImportAtSource: ?(BabelSourceLocation) => boolean,
};
export type Options = $ReadOnly<{
asyncRequireModulePath: string,
dependencyMapName: ?string,
dynamicRequires: DynamicRequiresBehavior,
inlineableCalls: $ReadOnlyArray<string>,
keepRequireNames: boolean,
allowOptionalDependencies: AllowOptionalDependencies,
dependencyTransformer?: DependencyTransformer,
/** Enable `require.context` statements which can be used to import multiple files in a directory. */
unstable_allowRequireContext: boolean,
unstable_isESMImportAtSource?: ?(BabelSourceLocation) => boolean,
}>;
export type CollectedDependencies = $ReadOnly<{
ast: BabelNodeFile,
dependencyMapName: string,
dependencies: $ReadOnlyArray<Dependency>,
}>;
export interface DependencyTransformer {
transformSyncRequire(
path: NodePath<CallExpression>,
dependency: InternalDependency,
state: State,
): void;
transformImportCall(
path: NodePath<>,
dependency: InternalDependency,
state: State,
): void;
transformImportMaybeSyncCall(
path: NodePath<>,
dependency: InternalDependency,
state: State,
): void;
transformPrefetch(
path: NodePath<>,
dependency: InternalDependency,
state: State,
): void;
transformIllegalDynamicRequire(path: NodePath<>, state: State): void;
}
export type DynamicRequiresBehavior = 'throwAtRuntime' | 'reject';
/**
* Transform all the calls to `require()` and `import()` in a file into ID-
* independent code, and return the list of dependencies. For example, a call
* like `require('Foo')` could be transformed to `require(_depMap[3], 'Foo')`
* where `_depMap` is provided by the outer scope. As such, we don't need to
* know the actual module ID.
*
* The second argument is only provided for debugging purposes.
*/
export default function collectDependencies(
ast: BabelNodeFile,
options: Options,
): CollectedDependencies {
const visited = new WeakSet<BabelNodeCallExpression>();
const state: State = {
asyncRequireModulePathStringLiteral: null,
dependencyCalls: new Set(),
dependencyRegistry: new DependencyRegistry(),
dependencyTransformer:
options.dependencyTransformer ?? DefaultDependencyTransformer,
dependencyMapIdentifier: null,
dynamicRequires: options.dynamicRequires,
keepRequireNames: options.keepRequireNames,
allowOptionalDependencies: options.allowOptionalDependencies,
unstable_allowRequireContext: options.unstable_allowRequireContext,
unstable_isESMImportAtSource: options.unstable_isESMImportAtSource ?? null,
};
const visitor = {
CallExpression(
path: NodePath<BabelNodeCallExpression>,
state: State,
): void {
if (visited.has(path.node)) {
return;
}
const callee = path.node.callee;
const name = callee.type === 'Identifier' ? callee.name : null;
if (isImport(callee)) {
processImportCall(path, state, {
asyncType: 'async',
isESMImport: true,
});
return;
}
if (name === '__prefetchImport' && !path.scope.getBinding(name)) {
processImportCall(path, state, {
asyncType: 'prefetch',
isESMImport: true,
});
return;
}
// Match `require.context`
if (
// Feature gate, defaults to `false`.
state.unstable_allowRequireContext &&
callee.type === 'MemberExpression' &&
// `require`
callee.object.type === 'Identifier' &&
callee.object.name === 'require' &&
// `context`
callee.property.type === 'Identifier' &&
callee.property.name === 'context' &&
!callee.computed &&
// Ensure `require` refers to the global and not something else.
!path.scope.getBinding('require')
) {
processRequireContextCall(path, state);
visited.add(path.node);
return;
}
// Match `require.resolveWeak`
if (
callee.type === 'MemberExpression' &&
// `require`
callee.object.type === 'Identifier' &&
callee.object.name === 'require' &&
// `resolveWeak`
callee.property.type === 'Identifier' &&
callee.property.name === 'resolveWeak' &&
!callee.computed &&
// Ensure `require` refers to the global and not something else.
!path.scope.getBinding('require')
) {
processResolveWeakCall(path, state);
visited.add(path.node);
return;
}
// Match `require.unstable_importMaybeSync`
if (
callee.type === 'MemberExpression' &&
// `require`
callee.object.type === 'Identifier' &&
callee.object.name === 'require' &&
// `unstable_importMaybeSync`
callee.property.type === 'Identifier' &&
callee.property.name === 'unstable_importMaybeSync' &&
!callee.computed &&
// Ensure `require` refers to the global and not something else.
!path.scope.getBinding('require')
) {
processImportCall(path, state, {
asyncType: 'maybeSync',
// Treat require.unstable_importMaybeSync as an ESM import, like its
// async "await import()" counterpart. Subject to change while
// unstable_.
isESMImport: true,
});
visited.add(path.node);
return;
}
if (
name != null &&
state.dependencyCalls.has(name) &&
!path.scope.getBinding(name)
) {
processRequireCall(path, state);
visited.add(path.node);
}
},
ImportDeclaration: collectImports,
ExportNamedDeclaration: collectImports,
ExportAllDeclaration: collectImports,
Program(path: NodePath<BabelNodeProgram>, state: State) {
state.asyncRequireModulePathStringLiteral = types.stringLiteral(
options.asyncRequireModulePath,
);
if (options.dependencyMapName != null) {
state.dependencyMapIdentifier = types.identifier(
options.dependencyMapName,
);
} else {
state.dependencyMapIdentifier =
path.scope.generateUidIdentifier('dependencyMap');
}
state.dependencyCalls = new Set(['require', ...options.inlineableCalls]);
},
};
traverse(ast, visitor, null, state);
const collectedDependencies = state.dependencyRegistry.getDependencies();
// Compute the list of dependencies.
const dependencies = new Array<Dependency>(collectedDependencies.length);
for (const {index, name, ...dependencyData} of collectedDependencies) {
dependencies[index] = {
name,
data: dependencyData,
};
}
return {
ast,
dependencies,
dependencyMapName: nullthrows(state.dependencyMapIdentifier).name,
};
}
/** Extract args passed to the `require.context` method. */
function getRequireContextArgs(
path: NodePath<CallExpression>,
): [string, RequireContextParams] {
const args = path.get('arguments');
let directory: string;
if (!Array.isArray(args) || args.length < 1) {
throw new InvalidRequireCallError(path);
} else {
const result = args[0].evaluate();
if (result.confident && typeof result.value === 'string') {
directory = result.value;
} else {
throw new InvalidRequireCallError(
result.deopt ?? args[0],
'First argument of `require.context` should be a string denoting the directory to require.',
);
}
}
// Default to requiring through all directories.
let recursive: boolean = true;
if (args.length > 1) {
const result = args[1].evaluate();
if (result.confident && typeof result.value === 'boolean') {
recursive = result.value;
} else if (!(result.confident && typeof result.value === 'undefined')) {
throw new InvalidRequireCallError(
result.deopt ?? args[1],
'Second argument of `require.context` should be an optional boolean indicating if files should be imported recursively or not.',
);
}
}
// Default to all files.
let filter: ContextFilter = {pattern: '.*', flags: ''};
if (args.length > 2) {
// evaluate() to check for undefined (because it's technically a scope lookup)
// but check the AST for the regex literal, since evaluate() doesn't do regex.
const result = args[2].evaluate();
const argNode = args[2].node;
if (argNode.type === 'RegExpLiteral') {
// TODO: Handle `new RegExp(...)` -- `argNode.type === 'NewExpression'`
filter = {
pattern: argNode.pattern,
flags: argNode.flags || '',
};
} else if (!(result.confident && typeof result.value === 'undefined')) {
throw new InvalidRequireCallError(
args[2],
`Third argument of \`require.context\` should be an optional RegExp pattern matching all of the files to import, instead found node of type: ${argNode.type}.`,
);
}
}
// Default to `sync`.
let mode: ContextMode = 'sync';
if (args.length > 3) {
const result = args[3].evaluate();
if (result.confident && typeof result.value === 'string') {
mode = getContextMode(args[3], result.value);
} else if (!(result.confident && typeof result.value === 'undefined')) {
throw new InvalidRequireCallError(
result.deopt ?? args[3],
'Fourth argument of `require.context` should be an optional string "mode" denoting how the modules will be resolved.',
);
}
}
if (args.length > 4) {
throw new InvalidRequireCallError(
path,
`Too many arguments provided to \`require.context\` call. Expected 4, got: ${args.length}`,
);
}
return [
directory,
{
recursive,
filter,
mode,
},
];
}
function getContextMode(path: NodePath<>, mode: string): ContextMode {
if (
mode === 'sync' ||
mode === 'eager' ||
mode === 'lazy' ||
mode === 'lazy-once'
) {
return mode;
}
throw new InvalidRequireCallError(
path,
`require.context "${mode}" mode is not supported. Expected one of: sync, eager, lazy, lazy-once`,
);
}
function processRequireContextCall(
path: NodePath<CallExpression>,
state: State,
): void {
const [directory, contextParams] = getRequireContextArgs(path);
const transformer = state.dependencyTransformer;
const dep = registerDependency(
state,
{
// We basically want to "import" every file in a folder and then filter them out with the given `filter` RegExp.
name: directory,
// Capture the matching context
contextParams,
asyncType: null,
isESMImport: false,
optional: isOptionalDependency(directory, path, state),
},
path,
);
// require() the generated module representing this context
path.get('callee').replaceWith(types.identifier('require'));
transformer.transformSyncRequire(path, dep, state);
}
function processResolveWeakCall(
path: NodePath<CallExpression>,
state: State,
): void {
const name = getModuleNameFromCallArgs(path);
if (name == null) {
throw new InvalidRequireCallError(path);
}
const dependency = registerDependency(
state,
{
name,
asyncType: 'weak',
isESMImport: false,
optional: isOptionalDependency(name, path, state),
},
path,
);
path.replaceWith(
makeResolveWeakTemplate({
MODULE_ID: createModuleIDExpression(dependency, state),
}),
);
}
function collectImports(path: NodePath<>, state: State): void {
if (path.node.source) {
invariant(
path.node.source.type === 'StringLiteral',
`Expected import source to be a string. Maybe you're using 'createImportExpressions', which is not currently supported.
See: https://github.com/facebook/metro/pull/1343`,
);
registerDependency(
state,
{
name: path.node.source.value,
asyncType: null,
isESMImport: true,
optional: false,
},
path,
);
}
}
function processImportCall(
path: NodePath<CallExpression>,
state: State,
options: ImportDependencyOptions,
): void {
const name = getModuleNameFromCallArgs(path);
if (name == null) {
throw new InvalidRequireCallError(path);
}
const dep = registerDependency(
state,
{
name,
asyncType: options.asyncType,
isESMImport: options.isESMImport,
optional: isOptionalDependency(name, path, state),
},
path,
);
const transformer = state.dependencyTransformer;
switch (options.asyncType) {
case 'async':
transformer.transformImportCall(path, dep, state);
break;
case 'maybeSync':
transformer.transformImportMaybeSyncCall(path, dep, state);
break;
case 'prefetch':
transformer.transformPrefetch(path, dep, state);
break;
case 'weak':
throw new Error('Unreachable');
default:
options.asyncType as empty;
throw new Error('Unreachable');
}
}
function processRequireCall(
path: NodePath<CallExpression>,
state: State,
): void {
const name = getModuleNameFromCallArgs(path);
const transformer = state.dependencyTransformer;
if (name == null) {
if (state.dynamicRequires === 'reject') {
throw new InvalidRequireCallError(path);
}
transformer.transformIllegalDynamicRequire(path, state);
return;
}
let isESMImport = false;
if (state.unstable_isESMImportAtSource) {
const isImport = state.unstable_isESMImportAtSource;
const loc = getNearestLocFromPath(path);
if (loc) {
isESMImport = isImport(loc);
}
}
const dep = registerDependency(
state,
{
name,
asyncType: null,
isESMImport,
optional: isOptionalDependency(name, path, state),
},
path,
);
transformer.transformSyncRequire(path, dep, state);
}
function getNearestLocFromPath(path: NodePath<>): ?BabelSourceLocation {
let current: ?(NodePath<> | NodePath<BabelNode>) = path;
while (
current &&
!current.node.loc &&
// $FlowFixMe[prop-missing] METRO_INLINE_REQUIRES_INIT_LOC is Metro-specific and not typed
!current.node.METRO_INLINE_REQUIRES_INIT_LOC
) {
current = current.parentPath;
}
// Do not use the location of the `Program` node
if (current && isProgram(current.node)) {
current = null;
}
return (
// $FlowFixMe[prop-missing] METRO_INLINE_REQUIRES_INIT_LOC is Metro-specific and not typed
current?.node.METRO_INLINE_REQUIRES_INIT_LOC ?? current?.node.loc
);
}
export type ImportQualifier = $ReadOnly<{
name: string,
asyncType: AsyncDependencyType | null,
isESMImport: boolean,
optional: boolean,
contextParams?: RequireContextParams,
}>;
function registerDependency(
state: State,
qualifier: ImportQualifier,
path: NodePath<>,
): InternalDependency {
const dependency = state.dependencyRegistry.registerDependency(qualifier);
const loc = getNearestLocFromPath(path);
if (loc != null) {
dependency.locs.push(loc);
}
return dependency;
}
function isOptionalDependency(
name: string,
path: NodePath<>,
state: State,
): boolean {
const {allowOptionalDependencies} = state;
// The async require module is a 'built-in'. Resolving should never fail -> treat it as non-optional.
if (name === state.asyncRequireModulePathStringLiteral?.value) {
return false;
}
const isExcluded = () =>
Array.isArray(allowOptionalDependencies.exclude) &&
allowOptionalDependencies.exclude.includes(name);
if (!allowOptionalDependencies || isExcluded()) {
return false;
}
// Valid statement stack for single-level try-block: expressionStatement -> blockStatement -> tryStatement
let sCount = 0;
let p: ?(NodePath<> | NodePath<BabelNode>) = path;
while (p && sCount < 3) {
if (p.isStatement()) {
if (p.node.type === 'BlockStatement') {
// A single-level should have the tryStatement immediately followed BlockStatement
// with the key 'block' to distinguish from the finally block, which has key = 'finalizer'
return (
p.parentPath != null &&
p.parentPath.node.type === 'TryStatement' &&
p.key === 'block'
);
}
sCount += 1;
}
p = p.parentPath;
}
return false;
}
function getModuleNameFromCallArgs(path: NodePath<CallExpression>): ?string {
const args = path.get('arguments');
if (!Array.isArray(args) || args.length !== 1) {
throw new InvalidRequireCallError(path);
}
const result = args[0].evaluate();
if (result.confident && typeof result.value === 'string') {
return result.value;
}
return null;
}
collectDependencies.getModuleNameFromCallArgs = getModuleNameFromCallArgs;
class InvalidRequireCallError extends Error {
constructor({node}: NodePath<>, message?: string) {
const line = node.loc && node.loc.start && node.loc.start.line;
super(
[
`Invalid call at line ${line || '<unknown>'}: ${generate(node).code}`,
message,
]
.filter(Boolean)
.join('\n'),
);
}
}
collectDependencies.InvalidRequireCallError = InvalidRequireCallError;
/**
* Produces a Babel template that will throw at runtime when the require call
* is reached. This makes dynamic require errors catchable by libraries that
* want to use them.
*/
const dynamicRequireErrorTemplate = template.expression(`
(function(line) {
throw new Error(
'Dynamic require defined at line ' + line + '; not supported by Metro',
);
})(LINE)
`);
/**
* Produces a Babel template that transforms an "import(...)" call into a
* "require(...)" call to the asyncRequire specified.
*/
const makeAsyncRequireTemplate = template.expression(`
require(ASYNC_REQUIRE_MODULE_PATH)(MODULE_ID, DEPENDENCY_MAP.paths)
`);
const makeAsyncRequireTemplateWithName = template.expression(`
require(ASYNC_REQUIRE_MODULE_PATH)(MODULE_ID, DEPENDENCY_MAP.paths, MODULE_NAME)
`);
const makeAsyncPrefetchTemplate = template.expression(`
require(ASYNC_REQUIRE_MODULE_PATH).prefetch(MODULE_ID, DEPENDENCY_MAP.paths)
`);
const makeAsyncPrefetchTemplateWithName = template.expression(`
require(ASYNC_REQUIRE_MODULE_PATH).prefetch(MODULE_ID, DEPENDENCY_MAP.paths, MODULE_NAME)
`);
const makeAsyncImportMaybeSyncTemplate = template.expression(`
require(ASYNC_REQUIRE_MODULE_PATH).unstable_importMaybeSync(MODULE_ID, DEPENDENCY_MAP.paths)
`);
const makeAsyncImportMaybeSyncTemplateWithName = template.expression(`
require(ASYNC_REQUIRE_MODULE_PATH).unstable_importMaybeSync(MODULE_ID, DEPENDENCY_MAP.paths, MODULE_NAME)
`);
const makeResolveWeakTemplate = template.expression(`
MODULE_ID
`);
const DefaultDependencyTransformer: DependencyTransformer = {
transformSyncRequire(
path: NodePath<CallExpression>,
dependency: InternalDependency,
state: State,
): void {
const moduleIDExpression = createModuleIDExpression(dependency, state);
path.node.arguments = ([moduleIDExpression]: Array<
| BabelNodeExpression
| BabelNodeSpreadElement
| BabelNodeArgumentPlaceholder,
>);
// Always add the debug name argument last
if (state.keepRequireNames) {
path.node.arguments.push(types.stringLiteral(dependency.name));
}
},
transformImportCall(
path: NodePath<>,
dependency: InternalDependency,
state: State,
): void {
const makeNode = state.keepRequireNames
? makeAsyncRequireTemplateWithName
: makeAsyncRequireTemplate;
const opts = {
ASYNC_REQUIRE_MODULE_PATH: nullthrows(
state.asyncRequireModulePathStringLiteral,
),
MODULE_ID: createModuleIDExpression(dependency, state),
DEPENDENCY_MAP: nullthrows(state.dependencyMapIdentifier),
...(state.keepRequireNames
? {MODULE_NAME: createModuleNameLiteral(dependency)}
: null),
};
/* $FlowFixMe[incompatible-type] Natural Inference rollout. See
* https://fburl.com/gdoc/y8dn025u */
path.replaceWith(makeNode(opts));
},
transformImportMaybeSyncCall(
path: NodePath<>,
dependency: InternalDependency,
state: State,
): void {
const makeNode = state.keepRequireNames
? makeAsyncImportMaybeSyncTemplateWithName
: makeAsyncImportMaybeSyncTemplate;
const opts = {
ASYNC_REQUIRE_MODULE_PATH: nullthrows(
state.asyncRequireModulePathStringLiteral,
),
MODULE_ID: createModuleIDExpression(dependency, state),
DEPENDENCY_MAP: nullthrows(state.dependencyMapIdentifier),
...(state.keepRequireNames
? {MODULE_NAME: createModuleNameLiteral(dependency)}
: null),
};
/* $FlowFixMe[incompatible-type] Natural Inference rollout. See
* https://fburl.com/gdoc/y8dn025u */
path.replaceWith(makeNode(opts));
},
transformPrefetch(
path: NodePath<>,
dependency: InternalDependency,
state: State,
): void {
const makeNode = state.keepRequireNames
? makeAsyncPrefetchTemplateWithName
: makeAsyncPrefetchTemplate;
const opts = {
ASYNC_REQUIRE_MODULE_PATH: nullthrows(
state.asyncRequireModulePathStringLiteral,
),
MODULE_ID: createModuleIDExpression(dependency, state),
DEPENDENCY_MAP: nullthrows(state.dependencyMapIdentifier),
...(state.keepRequireNames
? {MODULE_NAME: createModuleNameLiteral(dependency)}
: null),
};
/* $FlowFixMe[incompatible-type] Natural Inference rollout. See
* https://fburl.com/gdoc/y8dn025u */
path.replaceWith(makeNode(opts));
},
transformIllegalDynamicRequire(path: NodePath<>, state: State): void {
path.replaceWith(
dynamicRequireErrorTemplate({
LINE: types.numericLiteral(path.node.loc?.start.line ?? 0),
}),
);
},
};
function createModuleIDExpression(
dependency: InternalDependency,
state: State,
): BabelNodeExpression {
return types.memberExpression(
nullthrows(state.dependencyMapIdentifier),
types.numericLiteral(dependency.index),
true,
);
}
function createModuleNameLiteral(dependency: InternalDependency) {
return types.stringLiteral(dependency.name);
}
/**
* Given an import qualifier, return a key used to register the dependency.
* Attributes can be appended to distinguish various combinations that would
* otherwise be considered the same dependency edge.
*
* For example, the following dependencies would collapse into a single edge
* if they simply utilized the `name` property:
*
* ```
* require('./foo');
* import foo from './foo'
* await import('./foo')
* require.context('./foo');
* require.context('./foo', true, /something/);
* require.context('./foo', false, /something/);
* require.context('./foo', false, /something/, 'lazy');
* ```
*
* This method should be utilized by `registerDependency`.
*/
function getKeyForDependency(qualifier: ImportQualifier): string {
const {asyncType, contextParams, isESMImport, name} = qualifier;
let key = [name, isESMImport ? 'import' : 'require'].join('\0');
if (asyncType != null) {
key += '\0' + asyncType;
}
// Add extra qualifiers when using `require.context` to prevent collisions.
if (contextParams) {
// NOTE(EvanBacon): Keep this synchronized with `RequireContextParams`, if any other properties are added
// then this key algorithm should be updated to account for those properties.
// Example: `./directory__true__/foobar/m__lazy`
key += [
'',
'context',
String(contextParams.recursive),
String(contextParams.filter.pattern),
String(contextParams.filter.flags),
contextParams.mode,
// Join together and append to the name:
].join('\0');
}
return key;
}
class DependencyRegistry {
_dependencies: Map<string, InternalDependency> = new Map();
registerDependency(qualifier: ImportQualifier): InternalDependency {
const key = getKeyForDependency(qualifier);
let dependency: ?InternalDependency = this._dependencies.get(key);
if (dependency == null) {
const newDependency: MutableInternalDependency = {
name: qualifier.name,
asyncType: qualifier.asyncType,
isESMImport: qualifier.isESMImport,
locs: [],
index: this._dependencies.size,
key: crypto.createHash('sha1').update(key).digest('base64'),
};
if (qualifier.optional) {
newDependency.isOptional = true;
}
if (qualifier.contextParams) {
newDependency.contextParams = qualifier.contextParams;
}
dependency = newDependency;
} else {
if (dependency.isOptional && !qualifier.optional) {
// A previously optionally required dependency was required non-optionally.
// Mark it non optional for the whole module
dependency = {
...dependency,
isOptional: false,
};
}
}
this._dependencies.set(key, dependency);
return dependency;
}
getDependencies(): Array<InternalDependency> {
return Array.from(this._dependencies.values());
}
}
Выполнить команду
Для локальной разработки. Не используйте в интернете!