in packages/metro/src/ModuleGraph/worker/collectDependencies.js [137:252]
function collectDependencies<TSplitCondition = void>(
ast: BabelNodeFile,
options: Options<TSplitCondition>,
): CollectedDependencies<TSplitCondition> {
const visited = new WeakSet();
const state: State<TSplitCondition> = {
asyncRequireModulePathStringLiteral: null,
dependencyCalls: new Set(),
dependencyRegistry:
options.dependencyRegistry ?? new DefaultModuleDependencyRegistry(),
dependencyTransformer:
options.dependencyTransformer ?? DefaultDependencyTransformer,
dependencyMapIdentifier: null,
dynamicRequires: options.dynamicRequires,
keepRequireNames: options.keepRequireNames,
allowOptionalDependencies: options.allowOptionalDependencies,
};
const visitor = {
CallExpression(path, 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',
});
return;
}
if (name === '__prefetchImport' && !path.scope.getBinding(name)) {
processImportCall(path, state, {
asyncType: 'prefetch',
});
return;
}
if (name === '__jsResource' && !path.scope.getBinding(name)) {
processImportCall(path, state, {
asyncType: 'async',
jsResource: true,
});
return;
}
if (
name === '__conditionallySplitJSResource' &&
!path.scope.getBinding(name)
) {
const args = path.get('arguments');
invariant(Array.isArray(args), 'Expected arguments to be an array');
processImportCall(path, state, {
asyncType: 'async',
jsResource: true,
splitCondition: args[1],
});
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, 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(collectedDependencies.length);
for (const {index, name, ...dependencyData} of collectedDependencies) {
dependencies[index] = {
name,
data: dependencyData,
};
}
return {
ast,
dependencies,
dependencyMapName: nullthrows(state.dependencyMapIdentifier).name,
};
}