in compiler/crates/relay-transforms/src/flatten.rs [395:533]
fn can_flatten_selections(
&self,
flattened_selections: &mut Vec<Selection>,
selections: &[Selection],
parent_type: Type,
) -> DiagnosticsResult<()> {
for selection in selections {
if self.should_validate_fragment_spreads {
if let Selection::FragmentSpread(spread) = selection {
let fragment_definition =
self.fragments
.get(&spread.fragment.item)
.ok_or(Diagnostic::error(
ValidationMessage::UndefinedFragment(spread.fragment.item),
spread.fragment.location,
))?;
if fragment_definition.type_condition == parent_type {
self.can_flatten_selections(
flattened_selections,
&fragment_definition.selections,
fragment_definition.type_condition,
)?;
}
continue;
}
}
if let Selection::InlineFragment(inline_fragment) = selection {
// We will iterate through a selection of inline fragments
// (ignoring its directives) if this inline fragment doesn't
// have a type condition or type condition is the same as `parent_type`.
// The one exception for the latter case is @module directive.
// These are specially validated: they don't have conflicts in selections
// but may have conflicts in directive arguments.
if inline_fragment.type_condition.is_none()
|| (inline_fragment.type_condition == Some(parent_type)
&& inline_fragment
.directives
.named(ModuleMetadata::directive_name())
.is_none())
{
self.can_flatten_selections(
flattened_selections,
&inline_fragment.selections,
parent_type,
)?;
continue;
}
}
let flattened_selection = flattened_selections.iter_mut().find(|sel| {
sel.ptr_eq(selection) || NodeIdentifier::are_equal(&self.schema, sel, selection)
});
match flattened_selection {
None => {
flattened_selections.push(selection.clone());
}
Some(flattened_selection) => {
if flattened_selection.ptr_eq(selection) {
continue;
}
match flattened_selection {
Selection::InlineFragment(flattened_node) => {
let node = match selection {
Selection::InlineFragment(node) => node,
_ => unreachable!("FlattenTransform: Expected an InlineFragment."),
};
if let Some(flattened_module_metadata) =
ModuleMetadata::find(&flattened_node.directives)
{
if let Some(module_metadata) =
ModuleMetadata::find(&node.directives)
{
if flattened_module_metadata.key != module_metadata.key
|| flattened_module_metadata.module_name
!= module_metadata.module_name
|| flattened_module_metadata.fragment_name
!= module_metadata.fragment_name
{
let error = Diagnostic::error(
ValidationMessage::ConflictingModuleSelections,
module_metadata.location,
)
.annotate(
"conflicts with",
flattened_module_metadata.location,
);
return Err(vec![error]);
}
}
}
let type_condition =
flattened_node.type_condition.unwrap_or(parent_type);
let flattened_node_mut = Arc::make_mut(flattened_node);
self.can_flatten_selections(
&mut flattened_node_mut.selections,
&node.selections,
type_condition,
)?;
}
Selection::LinkedField(flattened_node) => {
let node = match selection {
Selection::LinkedField(node) => node,
_ => unreachable!("FlattenTransform: Expected a LinkedField."),
};
let type_ = self
.schema
.field(flattened_node.definition.item)
.type_
.inner();
let flattened_node_mut = Arc::make_mut(flattened_node);
self.can_flatten_selections(
&mut flattened_node_mut.selections,
&node.selections,
type_,
)?;
}
Selection::Condition(flattened_node) => {
let node = match selection {
Selection::Condition(node) => node,
_ => unreachable!("FlattenTransform: Expected a Condition."),
};
let flattened_node_mut = Arc::make_mut(flattened_node);
self.can_flatten_selections(
&mut flattened_node_mut.selections,
&node.selections,
parent_type,
)?;
}
Selection::ScalarField(_) | Selection::FragmentSpread(_) => {}
};
}
}
}
Ok(())
}