fn build_fragment_spread_arguments()

in compiler/crates/graphql-ir/src/build.rs [589:684]


    fn build_fragment_spread_arguments(
        &mut self,
        signature: &FragmentSignature,
        arg_list: &List<graphql_syntax::Argument>,
        validation_level: ValidationLevel,
    ) -> DiagnosticsResult<Vec<Argument>> {
        let mut has_invalid_arg = false;
        let mut errors = Vec::new();
        for variable_definition in &signature.variable_definitions {
            if variable_definition_requires_argument(variable_definition)
                && arg_list
                    .items
                    .named(variable_definition.name.item)
                    .is_none()
            {
                errors.push(
                    Diagnostic::error(
                        ValidationMessage::MissingRequiredFragmentArgument {
                            argument_name: variable_definition.name.item,
                        },
                        self.location.with_span(arg_list.span),
                    )
                    .annotate(
                        "defined on the fragment here",
                        variable_definition.name.location,
                    ),
                );
            }
        }
        if !errors.is_empty() {
            return Err(errors);
        }
        let result: DiagnosticsResult<Vec<Argument>> = arg_list
            .items
            .iter()
            .map(|arg| {
                if let Some(argument_definition) =
                    signature.variable_definitions.named(arg.name.value)
                {
                    // TODO: We didn't use to enforce types of @args/@argDefs properly, which resulted
                    // in a lot of code that is technically valid but doesn't type-check. Specifically,
                    // many fragment @argDefs are typed as non-null but used in places that accept a
                    // nullable value. Similarly, the corresponding @args pass nullable values. This
                    // works since ultimately a nullable T flows into a nullable T, but isn't
                    // technically correct. There are also @argDefs are typed with different types,
                    // but the persist query allowed them as the types are the same underlyingly.
                    // NOTE: We keep the same behavior as JS compiler for now, where we don't validate
                    // types of variables passed to @args at all
                    let arg_result = self.build_argument(
                        arg,
                        &argument_definition.type_,
                        ValidationLevel::Strict,
                    );
                    if arg_result.is_err() && validation_level == ValidationLevel::Loose {
                        has_invalid_arg = true;
                        self.build_argument(arg, &argument_definition.type_, ValidationLevel::Loose)
                    } else {
                        arg_result
                    }
                } else if validation_level == ValidationLevel::Loose {
                    has_invalid_arg = true;
                    Ok(self.build_argument(
                        arg,
                        self.schema.unchecked_argument_type_sentinel(),
                        ValidationLevel::Loose,
                    )?)
                } else {
                    let possible_argument_names = signature
                        .variable_definitions
                        .iter()
                        .map(|arg_def| arg_def.name.item)
                        .collect::<Vec<_>>();
                    let suggestions = suggestion_list::suggestion_list(
                        arg.name.value,
                        &possible_argument_names,
                        5,
                    );
                    Err(vec![Diagnostic::error_with_data(
                        ValidationMessageWithData::UnknownArgument {
                            argument_name: arg.name.value,
                            suggestions,
                        },
                        self.location.with_span(arg.span),
                    )])
                }
            })
            .collect();
        if validation_level == ValidationLevel::Loose && !has_invalid_arg {
            Err(vec![Diagnostic::error(
                ValidationMessage::UnnecessaryUncheckedArgumentsDirective,
                self.location.with_span(arg_list.span),
            )])
        } else {
            result
        }
    }