fn make_prop()

in compiler/crates/relay-typegen/src/lib.rs [1052:1195]


    fn make_prop(
        &mut self,
        type_selection: TypeSelection,
        unmasked: bool,
        concrete_type: Option<Type>,
    ) -> Prop {
        let optional = type_selection.is_conditional();
        if self.generating_updatable_types && optional {
            panic!(
                "When generating types for updatable operations and fragments, we should never generate optional fields! This indicates a bug in Relay. type_selection: {:?}",
                type_selection
            );
        }

        match type_selection {
            TypeSelection::LinkedField(linked_field) => {
                let key = linked_field.field_name_or_alias;

                if self.generating_updatable_types {
                    // TODO check whether the field is `node` or `nodes` on `Query`. If so, it should not be
                    // updatable.

                    let (just_fragments, no_fragments) =
                        extract_fragments(linked_field.node_selections);

                    let getter_object_props =
                        self.selections_to_babel(no_fragments.into_iter(), unmasked, None);
                    let getter_return_value = self
                        .transform_scalar_type(&linked_field.node_type, Some(getter_object_props));

                    let setter_parameter = if just_fragments.is_empty() {
                        if linked_field.node_type.is_list() {
                            AST::RawType(intern!("[]"))
                        } else {
                            AST::RawType(intern!("null | void"))
                        }
                    } else {
                        let setter_parameter = AST::Union(
                            	SortedASTList::new(
                                just_fragments
                                    .iter()
                                    .map(|fragment_spread| {
                                        let type_condition_info =  fragment_spread
                                            .type_condition_info
                                            .expect("Fragment spreads in updatable queries should have TypeConditionInfo");
                                        let (key, value) = match type_condition_info {
                                            TypeConditionInfo::Abstract => (format!("__is{}", fragment_spread.fragment_name).intern(), AST::String),
                                            TypeConditionInfo::Concrete { concrete_type } => ("__typename".intern(), AST::StringLiteral(StringLiteral(concrete_type))),
                                        };
                                        let fragment_spread_or_concrete_type_marker = Prop::KeyValuePair(KeyValuePairProp {
                                            key,
                                            value,
                                            read_only: true,
                                            optional: false,
                                        });
                                        let assignable_fragment_spread_ref= Prop::KeyValuePair(KeyValuePairProp {
                                            key: *KEY_FRAGMENT_SPREADS,
                                            value: AST::FragmentReferenceType(
                                                fragment_spread.fragment_name,
                                            ),
                                            read_only: true,
                                            optional: false,
                                        });
                                        let client_id_field = Prop::KeyValuePair(KeyValuePairProp {
                                            key: "__id".intern(),
                                            value: AST::String,
                                            read_only: true,
                                            optional: false,
                                        });

                                        AST::InexactObject(InexactObject::new(vec![
                                            assignable_fragment_spread_ref,
                                            fragment_spread_or_concrete_type_marker,
                                            client_id_field,
                                        ], self.should_sort_typegen_items))
                                    })
                                    .collect(),
                            self.should_sort_typegen_items));
                        if linked_field.node_type.is_list() {
                            AST::ReadOnlyArray(Box::new(setter_parameter))
                        } else {
                            AST::Nullable(Box::new(setter_parameter))
                        }
                    };

                    Prop::GetterSetterPair(GetterSetterPairProp {
                        key,
                        getter_return_value,
                        setter_parameter,
                    })
                } else {
                    let object_props = self.selections_to_babel(
                        hashmap_into_values(linked_field.node_selections),
                        unmasked,
                        None,
                    );
                    let value =
                        self.transform_scalar_type(&linked_field.node_type, Some(object_props));

                    Prop::KeyValuePair(KeyValuePairProp {
                        key,
                        value,
                        optional,
                        read_only: true,
                    })
                }
            }
            TypeSelection::ScalarField(scalar_field) => {
                if scalar_field.special_field == Some(ScalarFieldSpecialSchemaField::TypeName) {
                    if let Some(concrete_type) = concrete_type {
                        Prop::KeyValuePair(KeyValuePairProp {
                            key: scalar_field.field_name_or_alias,
                            value: AST::StringLiteral(StringLiteral(
                                self.schema.get_type_name(concrete_type),
                            )),
                            optional,
                            read_only: true,
                        })
                    } else {
                        Prop::KeyValuePair(KeyValuePairProp {
                            key: scalar_field.field_name_or_alias,
                            value: scalar_field.value,
                            optional,
                            read_only: true,
                        })
                    }
                } else {
                    Prop::KeyValuePair(KeyValuePairProp {
                        key: scalar_field.field_name_or_alias,
                        value: scalar_field.value,
                        optional,
                        // all fields outside of updatable operations are read-only, and within updatable operations,
                        // all special fields are read only
                        read_only: !self.generating_updatable_types
                            || scalar_field.special_field.is_some(),
                    })
                }
            }
            _ => panic!(
                "Unexpected TypeSelection variant in make_prop, {:?}",
                type_selection
            ),
        }
    }