in compiler/crates/relay-typegen/src/lib.rs [388:502]
fn write_fragment_type_exports_section(
&mut self,
fragment_definition: &FragmentDefinition,
) -> FmtResult {
// Assignable fragments do not require $data and $ref type exports, and their aliases
let is_assignable_fragment = fragment_definition
.directives
.named(*ASSIGNABLE_DIRECTIVE)
.is_some();
let mut selections = self.visit_selections(&fragment_definition.selections);
if !fragment_definition.type_condition.is_abstract_type() {
let num_concrete_selections = selections
.iter()
.filter(|sel| sel.get_enclosing_concrete_type().is_some())
.count();
if num_concrete_selections <= 1 {
for selection in selections.iter_mut().filter(|sel| sel.is_typename()) {
selection.set_concrete_type(fragment_definition.type_condition);
}
}
}
self.generated_fragments
.insert(fragment_definition.name.item);
let data_type = fragment_definition.name.item;
let data_type_name = format!("{}$data", data_type);
let ref_type_data_property = Prop::KeyValuePair(KeyValuePairProp {
key: *KEY_DATA,
optional: true,
read_only: true,
value: AST::Identifier(data_type_name.as_str().intern()),
});
let fragment_name = fragment_definition.name.item;
let ref_type_fragment_spreads_property = Prop::KeyValuePair(KeyValuePairProp {
key: *KEY_FRAGMENT_SPREADS,
optional: false,
read_only: true,
value: AST::FragmentReference(SortedStringKeyList::new(
vec![fragment_name],
self.should_sort_typegen_items,
)),
});
let is_plural_fragment = is_plural(fragment_definition);
let mut ref_type = AST::InexactObject(InexactObject::new(
vec![ref_type_data_property, ref_type_fragment_spreads_property],
self.should_sort_typegen_items,
));
if is_plural_fragment {
ref_type = AST::ReadOnlyArray(Box::new(ref_type));
}
let unmasked = RelayDirective::is_unmasked_fragment_definition(fragment_definition);
let base_type = self.selections_to_babel(
selections.into_iter(),
unmasked,
if unmasked { None } else { Some(fragment_name) },
);
let type_ = if is_plural_fragment {
AST::ReadOnlyArray(base_type.into())
} else {
base_type
};
let type_ = match fragment_definition
.directives
.named(*CHILDREN_CAN_BUBBLE_METADATA_KEY)
{
Some(_) => AST::Nullable(type_.into()),
None => type_,
};
self.runtime_imports.fragment_reference = true;
self.write_import_actor_change_point()?;
self.write_fragment_imports()?;
self.write_enum_definitions()?;
self.write_runtime_imports()?;
self.write_relay_resolver_imports()?;
let refetchable_metadata = RefetchableMetadata::find(&fragment_definition.directives);
let fragment_type_name = format!("{}$fragmentType", fragment_name);
self.writer
.write_export_fragment_type(&fragment_type_name)?;
if let Some(refetchable_metadata) = refetchable_metadata {
let variables_name = format!("{}$variables", refetchable_metadata.operation_name);
match self.js_module_format {
JsModuleFormat::CommonJS => {
if self.has_unified_output {
self.writer.write_import_fragment_type(
&[&variables_name],
&format!("./{}.graphql", refetchable_metadata.operation_name),
)?;
} else {
self.writer.write_any_type_definition(&variables_name)?;
}
}
JsModuleFormat::Haste => {
self.writer.write_import_fragment_type(
&[&variables_name],
&format!("{}.graphql", refetchable_metadata.operation_name),
)?;
}
}
}
if !is_assignable_fragment {
self.writer.write_export_type(&data_type_name, &type_)?;
self.writer
.write_export_type(&format!("{}$key", fragment_definition.name.item), &ref_type)?;
}
Ok(())
}