use super::*;
pub(super) fn propagate_factory_call_accesses(
graph: &ModuleGraph,
resolved_modules: &[ResolvedModule],
indexes: &MemberPassIndexes<'_>,
accessed_members: &mut FxHashMap<ExportKey, FxHashSet<String>>,
) {
for resolved in resolved_modules {
let local_to_export_keys = indexes.local_keys(resolved.file_id);
for access in factory_call_member_accesses(resolved) {
let Some(seed_keys) = local_to_export_keys.get(access.callee_object.as_str()) else {
continue;
};
for seed_key in seed_keys {
for origin in
walk_re_export_origins(graph, seed_key.file_id, seed_key.export_name.as_str())
{
let Some(origin_module) = indexes.module_by_id.get(&origin.file_id) else {
continue;
};
let matches_factory = origin_module.exports.iter().any(|export| {
export.name.matches_str(origin.export_name.as_str())
&& export.members.iter().any(|member| {
member.is_instance_returning_static
&& member.kind == MemberKind::ClassMethod
&& member.name == access.callee_method
})
});
if !matches_factory {
continue;
}
accessed_members
.entry(origin)
.or_default()
.insert(access.member.clone());
}
}
}
}
}
pub(super) struct FactoryReturnCreditContext<'a, 'ctx> {
pub(super) graph: &'ctx ModuleGraph,
pub(super) indexes: &'ctx MemberPassIndexes<'a>,
pub(super) accessed_members: &'ctx mut FxHashMap<ExportKey, FxHashSet<String>>,
}
pub(super) fn credit_factory_return_class_member(
context: &mut FactoryReturnCreditContext<'_, '_>,
factory_origin_file_id: FileId,
class_local_name: &str,
member: &str,
) {
for class_origin in factory_return_class_origins(
context.graph,
context.indexes,
factory_origin_file_id,
class_local_name,
) {
context
.accessed_members
.entry(class_origin)
.or_default()
.insert(member.to_string());
}
}
pub(super) fn propagate_factory_fn_accesses(
graph: &ModuleGraph,
resolved_modules: &[ResolvedModule],
indexes: &MemberPassIndexes<'_>,
accessed_members: &mut FxHashMap<ExportKey, FxHashSet<String>>,
) {
for resolved in resolved_modules {
let local_to_export_keys = indexes.local_keys(resolved.file_id);
for access in factory_fn_member_accesses(resolved) {
let Some(seed_keys) = local_to_export_keys.get(access.callee_name.as_str()) else {
continue;
};
let classes = seed_keys
.iter()
.flat_map(|seed_key| factory_return_classes_for_callee(graph, indexes, seed_key));
for class_origin in classes {
accessed_members
.entry(class_origin)
.or_default()
.insert(access.member.clone());
}
}
}
}
pub(super) fn propagate_factory_return_object_accesses(
graph: &ModuleGraph,
resolved_modules: &[ResolvedModule],
indexes: &MemberPassIndexes<'_>,
accessed_members: &mut FxHashMap<ExportKey, FxHashSet<String>>,
) {
for resolved in resolved_modules {
let local_to_export_keys = indexes.local_keys(resolved.file_id);
for access in factory_return_object_property_accesses(resolved) {
let Some(seed_keys) = local_to_export_keys.get(access.callee_name.as_str()) else {
continue;
};
let classes = seed_keys.iter().flat_map(|seed_key| {
factory_return_object_property_classes(
graph,
indexes,
seed_key,
access.property_path.as_str(),
)
});
let mut context = FactoryReturnCreditContext {
graph,
indexes,
accessed_members,
};
for (factory_origin_file_id, class_local_name) in classes {
credit_factory_return_class_member(
&mut context,
factory_origin_file_id,
&class_local_name,
access.member.as_str(),
);
}
}
}
}
fn factory_return_object_property_classes(
graph: &ModuleGraph,
indexes: &MemberPassIndexes<'_>,
seed_key: &ExportKey,
property_path: &str,
) -> Vec<(FileId, String)> {
let mut out = Vec::new();
for factory_origin in
walk_re_export_origins(graph, seed_key.file_id, seed_key.export_name.as_str())
{
let Some(factory_module) = indexes.module_by_id.get(&factory_origin.file_id) else {
continue;
};
let Some(shape) = factory_module
.exported_factory_return_object_shapes
.iter()
.find(|shape| shape.export_name.as_str() == factory_origin.export_name.as_str())
else {
continue;
};
for property in &shape.properties {
if property.property_path == property_path {
out.push((factory_origin.file_id, property.class_local_name.clone()));
}
}
}
out
}
fn factory_return_class_origins(
graph: &ModuleGraph,
indexes: &MemberPassIndexes<'_>,
factory_origin_file_id: FileId,
class_local_name: &str,
) -> Vec<ExportKey> {
let factory_local_keys = indexes.local_keys(factory_origin_file_id);
let Some(class_seed_keys) = factory_local_keys.get(class_local_name) else {
return Vec::new();
};
class_seed_keys
.iter()
.flat_map(|class_seed| export_key_with_origins(graph, class_seed))
.filter(|class_origin| {
indexes
.module_by_id
.get(&class_origin.file_id)
.is_some_and(|class_module| {
export_is_class_with_members(class_module, class_origin.export_name.as_str())
})
})
.collect()
}
fn factory_return_classes_for_callee(
graph: &ModuleGraph,
indexes: &MemberPassIndexes<'_>,
seed_key: &ExportKey,
) -> Vec<ExportKey> {
let mut origins = Vec::new();
for factory_origin in
walk_re_export_origins(graph, seed_key.file_id, seed_key.export_name.as_str())
{
let Some(factory_module) = indexes.module_by_id.get(&factory_origin.file_id) else {
continue;
};
let Some(factory_return) =
factory_module
.exported_factory_returns
.iter()
.find(|factory_return| {
factory_origin.export_name.as_str() == factory_return.export_name.as_str()
})
else {
continue;
};
origins.extend(factory_return_class_origins(
graph,
indexes,
factory_origin.file_id,
factory_return.class_local_name.as_str(),
));
}
origins
}
pub(super) fn propagate_factory_fn_whole_object_uses(
graph: &ModuleGraph,
resolved_modules: &[ResolvedModule],
indexes: &MemberPassIndexes<'_>,
whole_object_used_exports: &mut FxHashSet<ExportKey>,
) {
for resolved in resolved_modules {
let local_to_export_keys = indexes.local_keys(resolved.file_id);
for fact in factory_fn_whole_objects(resolved) {
let Some(seed_keys) = local_to_export_keys.get(fact.callee_name.as_str()) else {
continue;
};
let classes = seed_keys
.iter()
.flat_map(|seed_key| factory_return_classes_for_callee(graph, indexes, seed_key));
whole_object_used_exports.extend(classes);
}
}
}