fn transform_no_inline_fragment()

in compiler/crates/relay-transforms/src/apply_fragment_arguments/mod.rs [346:447]


    fn transform_no_inline_fragment(
        &mut self,
        fragment: &FragmentDefinition,
        directive: &Directive,
    ) {
        // If we have already computed, we can return early
        if let Some((_, provided_variables)) = self.split_operations.get(&fragment.name.item) {
            for (name, def) in provided_variables {
                self.provided_variables.insert(*name, def.clone());
            }
            return;
        }

        // We do not need to to write normalization files for base fragments
        let is_base = self.base_fragment_names.contains(&fragment.name.item);
        if !is_base && !self.no_inline_feature.is_enabled_for(fragment.name.item) {
            self.errors.push(Diagnostic::error(
                format!(
                    "Invalid usage of @no_inline on fragment '{}': this feature is gated and currently set to: {}",
                    fragment.name.item, self.no_inline_feature
                ),
                directive.name.location,
            ));
        }

        // save the context used by the enclosing operation / fragment
        let mut saved_provided_vars = std::mem::take(&mut self.provided_variables);
        let saved_scope = std::mem::replace(&mut self.scope, no_inline_fragment_scope(fragment));

        self.extract_provided_variables(fragment);
        let fragment = self
            .default_transform_fragment(fragment)
            .unwrap_or_else(|| fragment.clone());
        let FragmentDefinition {
            name,
            mut directives,
            mut variable_definitions,
            selections,
            type_condition,
            ..
        } = fragment;

        for variable in &mut variable_definitions {
            variable.name.item = format_local_variable(fragment.name.item, variable.name.item);
        }
        let mut metadata = SplitOperationMetadata {
            derived_from: fragment.name.item,
            parent_documents: Default::default(),
            raw_response_type: is_raw_response_type_enabled(directive),
        };
        // - A fragment with user defined @no_inline always produces a $normalization file. The `parent_document` of
        // that file is the fragment itself as it gets deleted iff that fragment is deleted or no longer
        // has the @no_inline directive.
        // - A fragment with @no_inline generated by @module, `parent_documents` also include fragments that
        // spread the current fragment with @module
        metadata.parent_documents.insert(fragment.name.item);
        let parent_documents_arg = directive.arguments.named(*PARENT_DOCUMENTS_ARG);
        if let Some(Value::Constant(ConstantValue::List(parent_documents))) =
            parent_documents_arg.map(|arg| &arg.value.item)
        {
            for val in parent_documents {
                if let ConstantValue::String(name) = val {
                    metadata.parent_documents.insert(*name);
                } else {
                    panic!("Expected item in the parent_documents to be a StringKey.")
                }
            }
        }
        directives.push(metadata.to_directive());
        let normalization_name = get_normalization_operation_name(name.item).intern();
        let operation = if is_base {
            None
        } else {
            Some(OperationDefinition {
                name: WithLocation::new(name.location, normalization_name),
                type_: type_condition,
                variable_definitions,
                directives,
                selections,
                kind: OperationKind::Query,
            })
        };

        if self.program.operation(normalization_name).is_some() {
            self.errors.push(Diagnostic::error(
                format!(
                    "Invalid usage of @no_inline on fragment '{}' - @no_inline is only allowed on allowlisted fragments loaded with @module",
                    fragment.name.item,
                ),
                directive.name.location,
            ));
        }
        self.split_operations.insert(
            fragment.name.item,
            (operation, self.provided_variables.clone()),
        );

        // add this fragment's provided variables to that of the enclosing operation / fragment
        saved_provided_vars.extend(self.provided_variables.drain(..).into_iter());
        self.provided_variables = saved_provided_vars;
        self.scope = saved_scope;
    }