# frozen_string_literal: truemoduleGraphQLmoduleStaticValidationmoduleVariableUsagesAreAlloweddefinitialize(*)super# holds { name => ast_node } pairs@declared_variables={}enddefon_operation_definition(node,parent)@declared_variables=node.variables.each_with_object({}){|var,memo|memo[var.name]=var}superenddefon_argument(node,parent)node_values=ifnode.value.is_a?(Array)node.valueelse[node.value]endnode_values=node_values.select{|value|value.is_a?GraphQL::Language::Nodes::VariableIdentifier}ifnode_values.any?argument_owner=caseparentwhenGraphQL::Language::Nodes::Fieldcontext.field_definitionwhenGraphQL::Language::Nodes::Directivecontext.directive_definitionwhenGraphQL::Language::Nodes::InputObjectarg_type=context.argument_definition.type.unwrapifarg_type.kind.input_object?arg_typeelse# This is some kind of errornilendelseraise("Unexpected argument parent: #{parent}")endnode_values.eachdo|node_value|var_defn_ast=@declared_variables[node_value.name]# Might be undefined :(# VariablesAreUsedAndDefined can't finalize its search until the end of the document.var_defn_ast&&argument_owner&&validate_usage(argument_owner,node,var_defn_ast)endendsuperendprivatedefvalidate_usage(argument_owner,arg_node,ast_var)var_type=context.schema.type_from_ast(ast_var.type,context: context)ifvar_type.nil?returnendif!ast_var.default_value.nil?unlessvar_type.kind.non_null?# If the value is required, but the argument is not,# and yet there's a non-nil default, then we impliclty# make the argument also a required type.var_type=var_type.to_non_null_typeendendarg_defn=context.warden.get_argument(argument_owner,arg_node.name)arg_defn_type=arg_defn.type# If the argument is non-null, but it was given a default value,# then treat it as nullable in practice, see https://github.com/rmosolgo/graphql-ruby/issues/3793ifarg_defn_type.non_null?&&arg_defn.default_value?arg_defn_type=arg_defn_type.of_typeendvar_inner_type=var_type.unwraparg_inner_type=arg_defn_type.unwrapvar_type=wrap_var_type_with_depth_of_arg(var_type,arg_node)ifvar_inner_type!=arg_inner_typecreate_error("Type mismatch",var_type,ast_var,arg_defn,arg_node)elsiflist_dimension(var_type)!=list_dimension(arg_defn_type)create_error("List dimension mismatch",var_type,ast_var,arg_defn,arg_node)elsif!non_null_levels_match(arg_defn_type,var_type)create_error("Nullability mismatch",var_type,ast_var,arg_defn,arg_node)endenddefcreate_error(error_message,var_type,ast_var,arg_defn,arg_node)add_error(GraphQL::StaticValidation::VariableUsagesAreAllowedError.new("#{error_message} on variable $#{ast_var.name} and argument #{arg_node.name} (#{var_type.to_type_signature} / #{arg_defn.type.to_type_signature})",nodes: arg_node,name: ast_var.name,type: var_type.to_type_signature,argument: arg_node.name,error: error_message))enddefwrap_var_type_with_depth_of_arg(var_type,arg_node)arg_node_value=arg_node.valuereturnvar_typeunlessarg_node_value.is_a?(Array)new_var_type=var_typedepth_of_array(arg_node_value).timesdo# Since the array _is_ present, treat it like a non-null type# (It satisfies a non-null requirement AND a nullable requirement)new_var_type=new_var_type.to_list_type.to_non_null_typeendnew_var_typeend# @return [Integer] Returns the max depth of `array`, or `0` if it isn't an array at alldefdepth_of_array(array)casearraywhenArraymax_child_depth=0array.eachdo|item|item_depth=depth_of_array(item)ifitem_depth>max_child_depthmax_child_depth=item_depthendend1+max_child_depthelse0endenddeflist_dimension(type)iftype.kind.list?1+list_dimension(type.of_type)elsiftype.kind.non_null?list_dimension(type.of_type)else0endenddefnon_null_levels_match(arg_type,var_type)ifarg_type.kind.non_null?&&!var_type.kind.non_null?falseelsifarg_type.kind.wraps?&&var_type.kind.wraps?# If var_type is a non-null wrapper for a type, and arg_type is nullable, peel off the wrapper# That way, a var_type of `[DairyAnimal]!` works with an arg_type of `[DairyAnimal]`ifvar_type.kind.non_null?&&!arg_type.kind.non_null?var_type=var_type.of_typeendnon_null_levels_match(arg_type.of_type,var_type.of_type)elsetrueendendendendend