in compiler/crates/relay-typegen/src/lib.rs [799:952]
fn selections_to_babel(
&mut self,
selections: impl Iterator<Item = TypeSelection>,
unmasked: bool,
fragment_type_name: Option<StringKey>,
) -> AST {
let mut base_fields: TypeSelectionMap = Default::default();
let mut by_concrete_type: IndexMap<Type, Vec<TypeSelection>> = Default::default();
for selection in selections {
if let Some(concrete_type) = selection.get_enclosing_concrete_type() {
by_concrete_type
.entry(concrete_type)
.or_insert_with(Vec::new)
.push(selection);
} else {
let key = selection.get_string_key();
let key = TypeSelectionKey {
key,
concrete_type: None,
};
match base_fields.entry(key) {
Entry::Occupied(entry) => {
let previous_sel = entry.get().clone();
*entry.into_mut() = merge_selection(Some(selection), previous_sel, true);
}
Entry::Vacant(entry) => {
entry.insert(selection);
}
}
}
}
let mut types: Vec<Vec<Prop>> = Vec::new();
fn has_typename_selection(selections: &Vec<TypeSelection>) -> bool {
selections.iter().any(TypeSelection::is_typename)
}
if !by_concrete_type.is_empty()
&& base_fields.values().all(TypeSelection::is_typename)
&& (base_fields.values().any(TypeSelection::is_typename)
|| by_concrete_type.values().all(has_typename_selection))
{
let mut typename_aliases = IndexSet::new();
for (concrete_type, selections) in by_concrete_type {
types.push(
group_refs(
base_fields.values().cloned().chain(selections),
self.should_sort_typegen_items,
)
.map(|selection| {
if selection.is_typename() {
typename_aliases.insert(selection.get_field_name_or_alias().expect(
"Just checked this exists by checking that the field is typename",
));
}
self.make_prop(selection, unmasked, Some(concrete_type))
})
.collect(),
);
}
// It might be some other type then the listed concrete types. Ideally, we
// would set the type to diff(string, set of listed concrete types), but
// this doesn't exist in Flow at the time.
types.push(
typename_aliases
.iter()
.map(|typename_alias| {
Prop::KeyValuePair(KeyValuePairProp {
key: *typename_alias,
read_only: true,
optional: false,
value: AST::OtherTypename,
})
})
.collect(),
);
} else {
let mut selection_map = selections_to_map(hashmap_into_values(base_fields), false);
for concrete_type_selections in hashmap_into_values(by_concrete_type) {
merge_selections(
&mut selection_map,
selections_to_map(
concrete_type_selections.into_iter().map(|mut sel| {
sel.set_conditional(true);
sel
}),
false,
),
true,
);
}
let selection_map_values = group_refs(
hashmap_into_values(selection_map),
self.should_sort_typegen_items,
)
.map(|sel| {
if let TypeSelection::ScalarField(ref scalar_field) = sel {
if sel.is_typename() {
if let Some(type_condition) = scalar_field.concrete_type {
let mut scalar_field = scalar_field.clone();
scalar_field.conditional = false;
return self.make_prop(
TypeSelection::ScalarField(scalar_field),
unmasked,
Some(type_condition),
);
}
}
} else if let TypeSelection::LinkedField(ref linked_field) = sel {
if let Some(concrete_type) = linked_field.concrete_type {
let mut linked_field = linked_field.clone();
linked_field.concrete_type = None;
return self.make_prop(
TypeSelection::LinkedField(linked_field),
unmasked,
Some(concrete_type),
);
}
}
self.make_prop(sel, unmasked, None)
})
.collect();
types.push(selection_map_values);
}
AST::Union(SortedASTList::new(
types
.into_iter()
.map(|mut props: Vec<Prop>| {
if let Some(fragment_type_name) = fragment_type_name {
props.push(Prop::KeyValuePair(KeyValuePairProp {
key: *KEY_FRAGMENT_TYPE,
optional: false,
read_only: true,
value: AST::FragmentReferenceType(fragment_type_name),
}));
}
if unmasked {
AST::InexactObject(InexactObject::new(
props,
self.should_sort_typegen_items,
))
} else {
AST::ExactObject(ExactObject::new(props, self.should_sort_typegen_items))
}
})
.collect(),
self.should_sort_typegen_items,
))
}