graphql_cody 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +5 -0
- data/MIT-LICENSE +20 -0
- data/lib/generators/graphql/core.rb +74 -0
- data/lib/generators/graphql/enum_generator.rb +33 -0
- data/lib/generators/graphql/install_generator.rb +190 -0
- data/lib/generators/graphql/interface_generator.rb +27 -0
- data/lib/generators/graphql/loader_generator.rb +21 -0
- data/lib/generators/graphql/mutation_generator.rb +55 -0
- data/lib/generators/graphql/object_generator.rb +79 -0
- data/lib/generators/graphql/relay.rb +63 -0
- data/lib/generators/graphql/relay_generator.rb +21 -0
- data/lib/generators/graphql/scalar_generator.rb +20 -0
- data/lib/generators/graphql/templates/base_argument.erb +6 -0
- data/lib/generators/graphql/templates/base_connection.erb +8 -0
- data/lib/generators/graphql/templates/base_edge.erb +8 -0
- data/lib/generators/graphql/templates/base_enum.erb +6 -0
- data/lib/generators/graphql/templates/base_field.erb +7 -0
- data/lib/generators/graphql/templates/base_input_object.erb +7 -0
- data/lib/generators/graphql/templates/base_interface.erb +9 -0
- data/lib/generators/graphql/templates/base_mutation.erb +10 -0
- data/lib/generators/graphql/templates/base_object.erb +7 -0
- data/lib/generators/graphql/templates/base_scalar.erb +6 -0
- data/lib/generators/graphql/templates/base_union.erb +6 -0
- data/lib/generators/graphql/templates/enum.erb +7 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +52 -0
- data/lib/generators/graphql/templates/interface.erb +8 -0
- data/lib/generators/graphql/templates/loader.erb +19 -0
- data/lib/generators/graphql/templates/mutation.erb +16 -0
- data/lib/generators/graphql/templates/mutation_type.erb +12 -0
- data/lib/generators/graphql/templates/node_type.erb +9 -0
- data/lib/generators/graphql/templates/object.erb +8 -0
- data/lib/generators/graphql/templates/query_type.erb +15 -0
- data/lib/generators/graphql/templates/scalar.erb +15 -0
- data/lib/generators/graphql/templates/schema.erb +27 -0
- data/lib/generators/graphql/templates/union.erb +7 -0
- data/lib/generators/graphql/type_generator.rb +98 -0
- data/lib/generators/graphql/union_generator.rb +33 -0
- data/lib/graphql/analysis/analyze_query.rb +98 -0
- data/lib/graphql/analysis/ast/analyzer.rb +84 -0
- data/lib/graphql/analysis/ast/field_usage.rb +51 -0
- data/lib/graphql/analysis/ast/max_query_complexity.rb +23 -0
- data/lib/graphql/analysis/ast/max_query_depth.rb +22 -0
- data/lib/graphql/analysis/ast/query_complexity.rb +230 -0
- data/lib/graphql/analysis/ast/query_depth.rb +56 -0
- data/lib/graphql/analysis/ast/visitor.rb +268 -0
- data/lib/graphql/analysis/ast.rb +91 -0
- data/lib/graphql/analysis/field_usage.rb +45 -0
- data/lib/graphql/analysis/max_query_complexity.rb +26 -0
- data/lib/graphql/analysis/max_query_depth.rb +26 -0
- data/lib/graphql/analysis/query_complexity.rb +88 -0
- data/lib/graphql/analysis/query_depth.rb +43 -0
- data/lib/graphql/analysis/reducer_state.rb +48 -0
- data/lib/graphql/analysis.rb +9 -0
- data/lib/graphql/analysis_error.rb +5 -0
- data/lib/graphql/argument.rb +131 -0
- data/lib/graphql/authorization.rb +82 -0
- data/lib/graphql/backtrace/inspect_result.rb +50 -0
- data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
- data/lib/graphql/backtrace/table.rb +159 -0
- data/lib/graphql/backtrace/traced_error.rb +54 -0
- data/lib/graphql/backtrace/tracer.rb +81 -0
- data/lib/graphql/backtrace.rb +64 -0
- data/lib/graphql/backwards_compatibility.rb +61 -0
- data/lib/graphql/base_type.rb +230 -0
- data/lib/graphql/boolean_type.rb +2 -0
- data/lib/graphql/coercion_error.rb +13 -0
- data/lib/graphql/compatibility/execution_specification/counter_schema.rb +53 -0
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +200 -0
- data/lib/graphql/compatibility/execution_specification.rb +436 -0
- data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +111 -0
- data/lib/graphql/compatibility/lazy_execution_specification.rb +215 -0
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +87 -0
- data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +79 -0
- data/lib/graphql/compatibility/query_parser_specification.rb +266 -0
- data/lib/graphql/compatibility/schema_parser_specification.rb +682 -0
- data/lib/graphql/compatibility.rb +5 -0
- data/lib/graphql/dataloader/null_dataloader.rb +22 -0
- data/lib/graphql/dataloader/request.rb +19 -0
- data/lib/graphql/dataloader/request_all.rb +19 -0
- data/lib/graphql/dataloader/source.rb +155 -0
- data/lib/graphql/dataloader.rb +308 -0
- data/lib/graphql/define/assign_argument.rb +12 -0
- data/lib/graphql/define/assign_connection.rb +13 -0
- data/lib/graphql/define/assign_enum_value.rb +18 -0
- data/lib/graphql/define/assign_global_id_field.rb +11 -0
- data/lib/graphql/define/assign_mutation_function.rb +34 -0
- data/lib/graphql/define/assign_object_field.rb +42 -0
- data/lib/graphql/define/defined_object_proxy.rb +53 -0
- data/lib/graphql/define/instance_definable.rb +240 -0
- data/lib/graphql/define/no_definition_error.rb +7 -0
- data/lib/graphql/define/non_null_with_bang.rb +16 -0
- data/lib/graphql/define/type_definer.rb +31 -0
- data/lib/graphql/define.rb +31 -0
- data/lib/graphql/deprecated_dsl.rb +55 -0
- data/lib/graphql/deprecation.rb +9 -0
- data/lib/graphql/dig.rb +19 -0
- data/lib/graphql/directive/deprecated_directive.rb +2 -0
- data/lib/graphql/directive/include_directive.rb +2 -0
- data/lib/graphql/directive/skip_directive.rb +2 -0
- data/lib/graphql/directive.rb +107 -0
- data/lib/graphql/enum_type.rb +133 -0
- data/lib/graphql/execution/directive_checks.rb +37 -0
- data/lib/graphql/execution/errors.rb +163 -0
- data/lib/graphql/execution/execute.rb +333 -0
- data/lib/graphql/execution/flatten.rb +40 -0
- data/lib/graphql/execution/instrumentation.rb +92 -0
- data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
- data/lib/graphql/execution/interpreter/arguments.rb +88 -0
- data/lib/graphql/execution/interpreter/arguments_cache.rb +103 -0
- data/lib/graphql/execution/interpreter/execution_errors.rb +29 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +18 -0
- data/lib/graphql/execution/interpreter/resolve.rb +70 -0
- data/lib/graphql/execution/interpreter/runtime.rb +949 -0
- data/lib/graphql/execution/interpreter.rb +122 -0
- data/lib/graphql/execution/lazy/lazy_method_map.rb +98 -0
- data/lib/graphql/execution/lazy/resolve.rb +91 -0
- data/lib/graphql/execution/lazy.rb +83 -0
- data/lib/graphql/execution/lookahead.rb +307 -0
- data/lib/graphql/execution/multiplex.rb +214 -0
- data/lib/graphql/execution/typecast.rb +50 -0
- data/lib/graphql/execution.rb +11 -0
- data/lib/graphql/execution_error.rb +58 -0
- data/lib/graphql/field/resolve.rb +59 -0
- data/lib/graphql/field.rb +226 -0
- data/lib/graphql/filter.rb +53 -0
- data/lib/graphql/float_type.rb +2 -0
- data/lib/graphql/function.rb +128 -0
- data/lib/graphql/id_type.rb +2 -0
- data/lib/graphql/input_object_type.rb +138 -0
- data/lib/graphql/int_type.rb +2 -0
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/integer_encoding_error.rb +36 -0
- data/lib/graphql/interface_type.rb +72 -0
- data/lib/graphql/internal_representation/document.rb +27 -0
- data/lib/graphql/internal_representation/node.rb +206 -0
- data/lib/graphql/internal_representation/print.rb +51 -0
- data/lib/graphql/internal_representation/rewrite.rb +184 -0
- data/lib/graphql/internal_representation/scope.rb +88 -0
- data/lib/graphql/internal_representation/visit.rb +36 -0
- data/lib/graphql/internal_representation.rb +7 -0
- data/lib/graphql/introspection/base_object.rb +13 -0
- data/lib/graphql/introspection/directive_location_enum.rb +15 -0
- data/lib/graphql/introspection/directive_type.rb +29 -0
- data/lib/graphql/introspection/dynamic_fields.rb +17 -0
- data/lib/graphql/introspection/entry_points.rb +35 -0
- data/lib/graphql/introspection/enum_value_type.rb +23 -0
- data/lib/graphql/introspection/field_type.rb +28 -0
- data/lib/graphql/introspection/input_value_type.rb +67 -0
- data/lib/graphql/introspection/introspection_query.rb +7 -0
- data/lib/graphql/introspection/schema_type.rb +44 -0
- data/lib/graphql/introspection/type_kind_enum.rb +13 -0
- data/lib/graphql/introspection/type_type.rb +95 -0
- data/lib/graphql/introspection.rb +114 -0
- data/lib/graphql/invalid_name_error.rb +11 -0
- data/lib/graphql/invalid_null_error.rb +50 -0
- data/lib/graphql/language/block_string.rb +99 -0
- data/lib/graphql/language/cache.rb +37 -0
- data/lib/graphql/language/definition_slice.rb +41 -0
- data/lib/graphql/language/document_from_schema_definition.rb +347 -0
- data/lib/graphql/language/generation.rb +24 -0
- data/lib/graphql/language/lexer.rb +1467 -0
- data/lib/graphql/language/lexer.rl +258 -0
- data/lib/graphql/language/nodes.rb +707 -0
- data/lib/graphql/language/parser.rb +1974 -0
- data/lib/graphql/language/parser.y +544 -0
- data/lib/graphql/language/printer.rb +366 -0
- data/lib/graphql/language/sanitized_printer.rb +222 -0
- data/lib/graphql/language/token.rb +34 -0
- data/lib/graphql/language/visitor.rb +242 -0
- data/lib/graphql/language.rb +36 -0
- data/lib/graphql/list_type.rb +80 -0
- data/lib/graphql/load_application_object_failed_error.rb +22 -0
- data/lib/graphql/name_validator.rb +11 -0
- data/lib/graphql/non_null_type.rb +71 -0
- data/lib/graphql/object_type.rb +130 -0
- data/lib/graphql/pagination/active_record_relation_connection.rb +48 -0
- data/lib/graphql/pagination/array_connection.rb +77 -0
- data/lib/graphql/pagination/connection.rb +226 -0
- data/lib/graphql/pagination/connections.rb +160 -0
- data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
- data/lib/graphql/pagination/relation_connection.rb +196 -0
- data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
- data/lib/graphql/pagination.rb +6 -0
- data/lib/graphql/parse_error.rb +24 -0
- data/lib/graphql/query/arguments.rb +189 -0
- data/lib/graphql/query/arguments_cache.rb +24 -0
- data/lib/graphql/query/context.rb +371 -0
- data/lib/graphql/query/executor.rb +52 -0
- data/lib/graphql/query/fingerprint.rb +26 -0
- data/lib/graphql/query/input_validation_result.rb +43 -0
- data/lib/graphql/query/literal_input.rb +136 -0
- data/lib/graphql/query/null_context.rb +55 -0
- data/lib/graphql/query/result.rb +63 -0
- data/lib/graphql/query/serial_execution/field_resolution.rb +92 -0
- data/lib/graphql/query/serial_execution/operation_resolution.rb +19 -0
- data/lib/graphql/query/serial_execution/selection_resolution.rb +23 -0
- data/lib/graphql/query/serial_execution/value_resolution.rb +87 -0
- data/lib/graphql/query/serial_execution.rb +40 -0
- data/lib/graphql/query/validation_pipeline.rb +139 -0
- data/lib/graphql/query/variable_validation_error.rb +44 -0
- data/lib/graphql/query/variables.rb +78 -0
- data/lib/graphql/query.rb +454 -0
- data/lib/graphql/railtie.rb +117 -0
- data/lib/graphql/rake_task/validate.rb +63 -0
- data/lib/graphql/rake_task.rb +145 -0
- data/lib/graphql/relay/array_connection.rb +83 -0
- data/lib/graphql/relay/base_connection.rb +189 -0
- data/lib/graphql/relay/connection_instrumentation.rb +54 -0
- data/lib/graphql/relay/connection_resolve.rb +43 -0
- data/lib/graphql/relay/connection_type.rb +41 -0
- data/lib/graphql/relay/edge.rb +27 -0
- data/lib/graphql/relay/edge_type.rb +19 -0
- data/lib/graphql/relay/edges_instrumentation.rb +39 -0
- data/lib/graphql/relay/global_id_resolve.rb +18 -0
- data/lib/graphql/relay/mongo_relation_connection.rb +50 -0
- data/lib/graphql/relay/mutation/instrumentation.rb +23 -0
- data/lib/graphql/relay/mutation/resolve.rb +56 -0
- data/lib/graphql/relay/mutation/result.rb +38 -0
- data/lib/graphql/relay/mutation.rb +106 -0
- data/lib/graphql/relay/node.rb +39 -0
- data/lib/graphql/relay/page_info.rb +7 -0
- data/lib/graphql/relay/range_add.rb +59 -0
- data/lib/graphql/relay/relation_connection.rb +188 -0
- data/lib/graphql/relay/type_extensions.rb +32 -0
- data/lib/graphql/relay.rb +18 -0
- data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
- data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
- data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
- data/lib/graphql/rubocop.rb +4 -0
- data/lib/graphql/runtime_type_error.rb +5 -0
- data/lib/graphql/scalar_type.rb +91 -0
- data/lib/graphql/schema/addition.rb +247 -0
- data/lib/graphql/schema/argument.rb +383 -0
- data/lib/graphql/schema/base_64_bp.rb +26 -0
- data/lib/graphql/schema/base_64_encoder.rb +21 -0
- data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +47 -0
- data/lib/graphql/schema/build_from_definition/resolve_map.rb +78 -0
- data/lib/graphql/schema/build_from_definition.rb +477 -0
- data/lib/graphql/schema/built_in_types.rb +12 -0
- data/lib/graphql/schema/catchall_middleware.rb +35 -0
- data/lib/graphql/schema/default_parse_error.rb +10 -0
- data/lib/graphql/schema/default_type_error.rb +17 -0
- data/lib/graphql/schema/directive/deprecated.rb +18 -0
- data/lib/graphql/schema/directive/feature.rb +66 -0
- data/lib/graphql/schema/directive/flagged.rb +57 -0
- data/lib/graphql/schema/directive/include.rb +25 -0
- data/lib/graphql/schema/directive/skip.rb +25 -0
- data/lib/graphql/schema/directive/transform.rb +60 -0
- data/lib/graphql/schema/directive.rb +210 -0
- data/lib/graphql/schema/enum.rb +193 -0
- data/lib/graphql/schema/enum_value.rb +97 -0
- data/lib/graphql/schema/field/connection_extension.rb +76 -0
- data/lib/graphql/schema/field/scope_extension.rb +22 -0
- data/lib/graphql/schema/field.rb +880 -0
- data/lib/graphql/schema/field_extension.rb +69 -0
- data/lib/graphql/schema/find_inherited_value.rb +36 -0
- data/lib/graphql/schema/finder.rb +155 -0
- data/lib/graphql/schema/input_object.rb +253 -0
- data/lib/graphql/schema/interface.rb +136 -0
- data/lib/graphql/schema/introspection_system.rb +169 -0
- data/lib/graphql/schema/invalid_type_error.rb +7 -0
- data/lib/graphql/schema/late_bound_type.rb +33 -0
- data/lib/graphql/schema/list.rb +75 -0
- data/lib/graphql/schema/loader.rb +226 -0
- data/lib/graphql/schema/member/accepts_definition.rb +159 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +129 -0
- data/lib/graphql/schema/member/build_type.rb +180 -0
- data/lib/graphql/schema/member/cached_graphql_definition.rb +31 -0
- data/lib/graphql/schema/member/graphql_type_names.rb +21 -0
- data/lib/graphql/schema/member/has_arguments.rb +332 -0
- data/lib/graphql/schema/member/has_ast_node.rb +20 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
- data/lib/graphql/schema/member/has_directives.rb +98 -0
- data/lib/graphql/schema/member/has_fields.rb +163 -0
- data/lib/graphql/schema/member/has_interfaces.rb +90 -0
- data/lib/graphql/schema/member/has_path.rb +25 -0
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
- data/lib/graphql/schema/member/has_validators.rb +31 -0
- data/lib/graphql/schema/member/instrumentation.rb +131 -0
- data/lib/graphql/schema/member/relay_shortcuts.rb +47 -0
- data/lib/graphql/schema/member/scoped.rb +21 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +38 -0
- data/lib/graphql/schema/member/validates_input.rb +33 -0
- data/lib/graphql/schema/member.rb +161 -0
- data/lib/graphql/schema/middleware_chain.rb +82 -0
- data/lib/graphql/schema/mutation.rb +94 -0
- data/lib/graphql/schema/non_null.rb +67 -0
- data/lib/graphql/schema/null_mask.rb +11 -0
- data/lib/graphql/schema/object.rb +150 -0
- data/lib/graphql/schema/possible_types.rb +44 -0
- data/lib/graphql/schema/printer.rb +100 -0
- data/lib/graphql/schema/relay_classic_mutation.rb +160 -0
- data/lib/graphql/schema/rescue_middleware.rb +60 -0
- data/lib/graphql/schema/resolver/has_payload_type.rb +96 -0
- data/lib/graphql/schema/resolver.rb +397 -0
- data/lib/graphql/schema/scalar.rb +69 -0
- data/lib/graphql/schema/subscription.rb +155 -0
- data/lib/graphql/schema/timeout.rb +123 -0
- data/lib/graphql/schema/timeout_middleware.rb +88 -0
- data/lib/graphql/schema/traversal.rb +228 -0
- data/lib/graphql/schema/type_expression.rb +43 -0
- data/lib/graphql/schema/type_membership.rb +48 -0
- data/lib/graphql/schema/union.rb +95 -0
- data/lib/graphql/schema/unique_within_type.rb +34 -0
- data/lib/graphql/schema/validation.rb +313 -0
- data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
- data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
- data/lib/graphql/schema/validator/exclusion_validator.rb +33 -0
- data/lib/graphql/schema/validator/format_validator.rb +48 -0
- data/lib/graphql/schema/validator/inclusion_validator.rb +35 -0
- data/lib/graphql/schema/validator/length_validator.rb +59 -0
- data/lib/graphql/schema/validator/numericality_validator.rb +82 -0
- data/lib/graphql/schema/validator/required_validator.rb +68 -0
- data/lib/graphql/schema/validator.rb +174 -0
- data/lib/graphql/schema/warden.rb +409 -0
- data/lib/graphql/schema/wrapper.rb +29 -0
- data/lib/graphql/schema.rb +1945 -0
- data/lib/graphql/static_validation/all_rules.rb +40 -0
- data/lib/graphql/static_validation/base_visitor.rb +217 -0
- data/lib/graphql/static_validation/default_visitor.rb +15 -0
- data/lib/graphql/static_validation/definition_dependencies.rb +198 -0
- data/lib/graphql/static_validation/error.rb +46 -0
- data/lib/graphql/static_validation/interpreter_visitor.rb +14 -0
- data/lib/graphql/static_validation/literal_validator.rb +139 -0
- data/lib/graphql/static_validation/no_validate_visitor.rb +10 -0
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +66 -0
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +48 -0
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +31 -0
- data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +71 -0
- data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +37 -0
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +23 -0
- data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +29 -0
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +65 -0
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +31 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +30 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +32 -0
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +73 -0
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +31 -0
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +418 -0
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +53 -0
- data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +30 -0
- data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +73 -0
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +35 -0
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +39 -0
- data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +21 -0
- data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +29 -0
- data/lib/graphql/static_validation/rules/fragments_are_named.rb +16 -0
- data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +26 -0
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +37 -0
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +30 -0
- data/lib/graphql/static_validation/rules/fragments_are_used.rb +32 -0
- data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +29 -0
- data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
- data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +17 -0
- data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +41 -0
- data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +25 -0
- data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +36 -0
- data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +28 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +37 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +35 -0
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +59 -0
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +35 -0
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +17 -0
- data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +50 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +29 -0
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +46 -0
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +39 -0
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +24 -0
- data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +29 -0
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +153 -0
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +38 -0
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +39 -0
- data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +32 -0
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +155 -0
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +37 -0
- data/lib/graphql/static_validation/type_stack.rb +216 -0
- data/lib/graphql/static_validation/validation_context.rb +49 -0
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +96 -0
- data/lib/graphql/static_validation.rb +19 -0
- data/lib/graphql/string_encoding_error.rb +20 -0
- data/lib/graphql/string_type.rb +2 -0
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +245 -0
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +81 -0
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
- data/lib/graphql/subscriptions/event.rb +144 -0
- data/lib/graphql/subscriptions/instrumentation.rb +79 -0
- data/lib/graphql/subscriptions/serialize.rb +138 -0
- data/lib/graphql/subscriptions/subscription_root.rb +76 -0
- data/lib/graphql/subscriptions.rb +299 -0
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +35 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +173 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +51 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +76 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +51 -0
- data/lib/graphql/tracing/platform_tracing.rb +139 -0
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +32 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +67 -0
- data/lib/graphql/tracing/scout_tracing.rb +54 -0
- data/lib/graphql/tracing/skylight_tracing.rb +70 -0
- data/lib/graphql/tracing/statsd_tracing.rb +42 -0
- data/lib/graphql/tracing.rb +95 -0
- data/lib/graphql/type_kinds.rb +77 -0
- data/lib/graphql/types/big_int.rb +23 -0
- data/lib/graphql/types/boolean.rb +18 -0
- data/lib/graphql/types/float.rb +19 -0
- data/lib/graphql/types/id.rb +24 -0
- data/lib/graphql/types/int.rb +36 -0
- data/lib/graphql/types/iso_8601_date.rb +34 -0
- data/lib/graphql/types/iso_8601_date_time.rb +65 -0
- data/lib/graphql/types/json.rb +25 -0
- data/lib/graphql/types/relay/base_connection.rb +39 -0
- data/lib/graphql/types/relay/base_edge.rb +29 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +156 -0
- data/lib/graphql/types/relay/default_relay.rb +27 -0
- data/lib/graphql/types/relay/edge_behaviors.rb +53 -0
- data/lib/graphql/types/relay/has_node_field.rb +41 -0
- data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
- data/lib/graphql/types/relay/node.rb +15 -0
- data/lib/graphql/types/relay/node_behaviors.rb +15 -0
- data/lib/graphql/types/relay/node_field.rb +25 -0
- data/lib/graphql/types/relay/nodes_field.rb +27 -0
- data/lib/graphql/types/relay/page_info.rb +11 -0
- data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
- data/lib/graphql/types/relay.rb +41 -0
- data/lib/graphql/types/string.rb +29 -0
- data/lib/graphql/types.rb +11 -0
- data/lib/graphql/unauthorized_error.rb +29 -0
- data/lib/graphql/unauthorized_field_error.rb +23 -0
- data/lib/graphql/union_type.rb +115 -0
- data/lib/graphql/unresolved_type_error.rb +35 -0
- data/lib/graphql/upgrader/member.rb +937 -0
- data/lib/graphql/upgrader/schema.rb +38 -0
- data/lib/graphql/version.rb +4 -0
- data/lib/graphql.rb +168 -0
- data/readme.md +49 -0
- metadata +714 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
# Default rules for {GraphQL::StaticValidation::Validator}
|
5
|
+
#
|
6
|
+
# Order is important here. Some validators return {GraphQL::Language::Visitor::SKIP}
|
7
|
+
# which stops the visit on that node. That way it doesn't try to find fields on types that
|
8
|
+
# don't exist, etc.
|
9
|
+
ALL_RULES = [
|
10
|
+
GraphQL::StaticValidation::NoDefinitionsArePresent,
|
11
|
+
GraphQL::StaticValidation::DirectivesAreDefined,
|
12
|
+
GraphQL::StaticValidation::DirectivesAreInValidLocations,
|
13
|
+
GraphQL::StaticValidation::UniqueDirectivesPerLocation,
|
14
|
+
GraphQL::StaticValidation::OperationNamesAreValid,
|
15
|
+
GraphQL::StaticValidation::FragmentNamesAreUnique,
|
16
|
+
GraphQL::StaticValidation::FragmentsAreFinite,
|
17
|
+
GraphQL::StaticValidation::FragmentsAreNamed,
|
18
|
+
GraphQL::StaticValidation::FragmentsAreUsed,
|
19
|
+
GraphQL::StaticValidation::FragmentTypesExist,
|
20
|
+
GraphQL::StaticValidation::FragmentsAreOnCompositeTypes,
|
21
|
+
GraphQL::StaticValidation::FragmentSpreadsArePossible,
|
22
|
+
GraphQL::StaticValidation::FieldsAreDefinedOnType,
|
23
|
+
GraphQL::StaticValidation::FieldsWillMerge,
|
24
|
+
GraphQL::StaticValidation::FieldsHaveAppropriateSelections,
|
25
|
+
GraphQL::StaticValidation::ArgumentsAreDefined,
|
26
|
+
GraphQL::StaticValidation::ArgumentLiteralsAreCompatible,
|
27
|
+
GraphQL::StaticValidation::RequiredArgumentsArePresent,
|
28
|
+
GraphQL::StaticValidation::RequiredInputObjectAttributesArePresent,
|
29
|
+
GraphQL::StaticValidation::ArgumentNamesAreUnique,
|
30
|
+
GraphQL::StaticValidation::VariableNamesAreUnique,
|
31
|
+
GraphQL::StaticValidation::VariablesAreInputTypes,
|
32
|
+
GraphQL::StaticValidation::VariableDefaultValuesAreCorrectlyTyped,
|
33
|
+
GraphQL::StaticValidation::VariablesAreUsedAndDefined,
|
34
|
+
GraphQL::StaticValidation::VariableUsagesAreAllowed,
|
35
|
+
GraphQL::StaticValidation::MutationRootExists,
|
36
|
+
GraphQL::StaticValidation::SubscriptionRootExists,
|
37
|
+
GraphQL::StaticValidation::InputObjectNamesAreUnique,
|
38
|
+
]
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class BaseVisitor < GraphQL::Language::Visitor
|
5
|
+
def initialize(document, context)
|
6
|
+
@path = []
|
7
|
+
@object_types = []
|
8
|
+
@directives = []
|
9
|
+
@field_definitions = []
|
10
|
+
@argument_definitions = []
|
11
|
+
@directive_definitions = []
|
12
|
+
@context = context
|
13
|
+
@schema = context.schema
|
14
|
+
super(document)
|
15
|
+
end
|
16
|
+
|
17
|
+
# This will be overwritten by {InternalRepresentation::Rewrite} if it's included
|
18
|
+
def rewrite_document
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :context
|
23
|
+
|
24
|
+
# @return [Array<GraphQL::ObjectType>] Types whose scope we've entered
|
25
|
+
attr_reader :object_types
|
26
|
+
|
27
|
+
# @return [Array<String>] The nesting of the current position in the AST
|
28
|
+
def path
|
29
|
+
@path.dup
|
30
|
+
end
|
31
|
+
|
32
|
+
# Build a class to visit the AST and perform validation,
|
33
|
+
# or use a pre-built class if rules is `ALL_RULES` or empty.
|
34
|
+
# @param rules [Array<Module, Class>]
|
35
|
+
# @param rewrite [Boolean] if `false`, don't include rewrite
|
36
|
+
# @return [Class] A class for validating `rules` during visitation
|
37
|
+
def self.including_rules(rules, rewrite: true)
|
38
|
+
if rules.empty?
|
39
|
+
if rewrite
|
40
|
+
NoValidateVisitor
|
41
|
+
else
|
42
|
+
# It's not doing _anything?!?_
|
43
|
+
BaseVisitor
|
44
|
+
end
|
45
|
+
elsif rules == ALL_RULES
|
46
|
+
if rewrite
|
47
|
+
DefaultVisitor
|
48
|
+
else
|
49
|
+
InterpreterVisitor
|
50
|
+
end
|
51
|
+
else
|
52
|
+
visitor_class = Class.new(self) do
|
53
|
+
include(GraphQL::StaticValidation::DefinitionDependencies)
|
54
|
+
end
|
55
|
+
|
56
|
+
rules.reverse_each do |r|
|
57
|
+
# If it's a class, it gets attached later.
|
58
|
+
if !r.is_a?(Class)
|
59
|
+
visitor_class.include(r)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
if rewrite
|
64
|
+
visitor_class.include(GraphQL::InternalRepresentation::Rewrite)
|
65
|
+
end
|
66
|
+
visitor_class.include(ContextMethods)
|
67
|
+
visitor_class
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
module ContextMethods
|
72
|
+
def on_operation_definition(node, parent)
|
73
|
+
object_type = @schema.root_type_for_operation(node.operation_type)
|
74
|
+
push_type(object_type)
|
75
|
+
@path.push("#{node.operation_type}#{node.name ? " #{node.name}" : ""}")
|
76
|
+
super
|
77
|
+
@object_types.pop
|
78
|
+
@path.pop
|
79
|
+
end
|
80
|
+
|
81
|
+
def on_fragment_definition(node, parent)
|
82
|
+
on_fragment_with_type(node) do
|
83
|
+
@path.push("fragment #{node.name}")
|
84
|
+
super
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def on_inline_fragment(node, parent)
|
89
|
+
on_fragment_with_type(node) do
|
90
|
+
@path.push("...#{node.type ? " on #{node.type.to_query_string}" : ""}")
|
91
|
+
super
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def on_field(node, parent)
|
96
|
+
parent_type = @object_types.last
|
97
|
+
field_definition = @schema.get_field(parent_type, node.name, @context.query.context)
|
98
|
+
@field_definitions.push(field_definition)
|
99
|
+
if !field_definition.nil?
|
100
|
+
next_object_type = field_definition.type.unwrap
|
101
|
+
push_type(next_object_type)
|
102
|
+
else
|
103
|
+
push_type(nil)
|
104
|
+
end
|
105
|
+
@path.push(node.alias || node.name)
|
106
|
+
super
|
107
|
+
@field_definitions.pop
|
108
|
+
@object_types.pop
|
109
|
+
@path.pop
|
110
|
+
end
|
111
|
+
|
112
|
+
def on_directive(node, parent)
|
113
|
+
directive_defn = @schema.directives[node.name]
|
114
|
+
@directive_definitions.push(directive_defn)
|
115
|
+
super
|
116
|
+
@directive_definitions.pop
|
117
|
+
end
|
118
|
+
|
119
|
+
def on_argument(node, parent)
|
120
|
+
argument_defn = if (arg = @argument_definitions.last)
|
121
|
+
arg_type = arg.type.unwrap
|
122
|
+
if arg_type.kind.input_object?
|
123
|
+
@context.warden.get_argument(arg_type, node.name)
|
124
|
+
else
|
125
|
+
nil
|
126
|
+
end
|
127
|
+
elsif (directive_defn = @directive_definitions.last)
|
128
|
+
@context.warden.get_argument(directive_defn, node.name)
|
129
|
+
elsif (field_defn = @field_definitions.last)
|
130
|
+
@context.warden.get_argument(field_defn, node.name)
|
131
|
+
else
|
132
|
+
nil
|
133
|
+
end
|
134
|
+
|
135
|
+
@argument_definitions.push(argument_defn)
|
136
|
+
@path.push(node.name)
|
137
|
+
super
|
138
|
+
@argument_definitions.pop
|
139
|
+
@path.pop
|
140
|
+
end
|
141
|
+
|
142
|
+
def on_fragment_spread(node, parent)
|
143
|
+
@path.push("... #{node.name}")
|
144
|
+
super
|
145
|
+
@path.pop
|
146
|
+
end
|
147
|
+
|
148
|
+
def on_input_object(node, parent)
|
149
|
+
arg_defn = @argument_definitions.last
|
150
|
+
if arg_defn && arg_defn.type.list?
|
151
|
+
@path.push(parent.children.index(node))
|
152
|
+
super
|
153
|
+
@path.pop
|
154
|
+
else
|
155
|
+
super
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# @return [GraphQL::BaseType] The current object type
|
160
|
+
def type_definition
|
161
|
+
@object_types.last
|
162
|
+
end
|
163
|
+
|
164
|
+
# @return [GraphQL::BaseType] The type which the current type came from
|
165
|
+
def parent_type_definition
|
166
|
+
@object_types[-2]
|
167
|
+
end
|
168
|
+
|
169
|
+
# @return [GraphQL::Field, nil] The most-recently-entered GraphQL::Field, if currently inside one
|
170
|
+
def field_definition
|
171
|
+
@field_definitions.last
|
172
|
+
end
|
173
|
+
|
174
|
+
# @return [GraphQL::Directive, nil] The most-recently-entered GraphQL::Directive, if currently inside one
|
175
|
+
def directive_definition
|
176
|
+
@directive_definitions.last
|
177
|
+
end
|
178
|
+
|
179
|
+
# @return [GraphQL::Argument, nil] The most-recently-entered GraphQL::Argument, if currently inside one
|
180
|
+
def argument_definition
|
181
|
+
# Don't get the _last_ one because that's the current one.
|
182
|
+
# Get the second-to-last one, which is the parent of the current one.
|
183
|
+
@argument_definitions[-2]
|
184
|
+
end
|
185
|
+
|
186
|
+
private
|
187
|
+
|
188
|
+
def on_fragment_with_type(node)
|
189
|
+
object_type = if node.type
|
190
|
+
@context.warden.get_type(node.type.name)
|
191
|
+
else
|
192
|
+
@object_types.last
|
193
|
+
end
|
194
|
+
push_type(object_type)
|
195
|
+
yield(node)
|
196
|
+
@object_types.pop
|
197
|
+
@path.pop
|
198
|
+
end
|
199
|
+
|
200
|
+
def push_type(t)
|
201
|
+
@object_types.push(t)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
private
|
206
|
+
|
207
|
+
def add_error(error, path: nil)
|
208
|
+
if @context.too_many_errors?
|
209
|
+
throw :too_many_validation_errors
|
210
|
+
end
|
211
|
+
error.path ||= (path || @path.dup)
|
212
|
+
context.errors << error
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class DefaultVisitor < BaseVisitor
|
5
|
+
include(GraphQL::StaticValidation::DefinitionDependencies)
|
6
|
+
|
7
|
+
StaticValidation::ALL_RULES.reverse_each do |r|
|
8
|
+
include(r)
|
9
|
+
end
|
10
|
+
|
11
|
+
include(GraphQL::InternalRepresentation::Rewrite)
|
12
|
+
include(ContextMethods)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
# Track fragment dependencies for operations
|
5
|
+
# and expose the fragment definitions which
|
6
|
+
# are used by a given operation
|
7
|
+
module DefinitionDependencies
|
8
|
+
attr_reader :dependencies
|
9
|
+
|
10
|
+
def initialize(*)
|
11
|
+
super
|
12
|
+
@defdep_node_paths = {}
|
13
|
+
|
14
|
+
# { name => [node, ...] } pairs for fragments (although duplicate-named fragments are _invalid_, they are _possible_)
|
15
|
+
@defdep_fragment_definitions = Hash.new{ |h, k| h[k] = [] }
|
16
|
+
|
17
|
+
# This tracks dependencies from fragment to Node where it was used
|
18
|
+
# { fragment_definition_name => [dependent_node, dependent_node]}
|
19
|
+
@defdep_dependent_definitions = Hash.new { |h, k| h[k] = Set.new }
|
20
|
+
|
21
|
+
# First-level usages of spreads within definitions
|
22
|
+
# (When a key has an empty list as its value,
|
23
|
+
# we can resolve that key's dependents)
|
24
|
+
# { definition_node => [node, node ...] }
|
25
|
+
@defdep_immediate_dependencies = Hash.new { |h, k| h[k] = Set.new }
|
26
|
+
|
27
|
+
# When we encounter a spread,
|
28
|
+
# this node is the one who depends on it
|
29
|
+
@defdep_current_parent = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def on_document(node, parent)
|
33
|
+
node.definitions.each do |definition|
|
34
|
+
if definition.is_a? GraphQL::Language::Nodes::FragmentDefinition
|
35
|
+
@defdep_fragment_definitions[definition.name] << definition
|
36
|
+
end
|
37
|
+
end
|
38
|
+
super
|
39
|
+
@dependencies = dependency_map { |defn, spreads, frag|
|
40
|
+
context.on_dependency_resolve_handlers.each { |h| h.call(defn, spreads, frag) }
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def on_operation_definition(node, prev_node)
|
45
|
+
@defdep_node_paths[node.name] = NodeWithPath.new(node, context.path)
|
46
|
+
@defdep_current_parent = node
|
47
|
+
super
|
48
|
+
@defdep_current_parent = nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def on_fragment_definition(node, parent)
|
52
|
+
@defdep_node_paths[node] = NodeWithPath.new(node, context.path)
|
53
|
+
@defdep_current_parent = node
|
54
|
+
super
|
55
|
+
@defdep_current_parent = nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def on_fragment_spread(node, parent)
|
59
|
+
@defdep_node_paths[node] = NodeWithPath.new(node, context.path)
|
60
|
+
|
61
|
+
# Track both sides of the dependency
|
62
|
+
@defdep_dependent_definitions[node.name] << @defdep_current_parent
|
63
|
+
@defdep_immediate_dependencies[@defdep_current_parent] << node
|
64
|
+
super
|
65
|
+
end
|
66
|
+
|
67
|
+
# A map of operation definitions to an array of that operation's dependencies
|
68
|
+
# @return [DependencyMap]
|
69
|
+
def dependency_map(&block)
|
70
|
+
@dependency_map ||= resolve_dependencies(&block)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Map definition AST nodes to the definition AST nodes they depend on.
|
74
|
+
# Expose circular dependencies.
|
75
|
+
class DependencyMap
|
76
|
+
# @return [Array<GraphQL::Language::Nodes::FragmentDefinition>]
|
77
|
+
attr_reader :cyclical_definitions
|
78
|
+
|
79
|
+
# @return [Hash<Node, Array<GraphQL::Language::Nodes::FragmentSpread>>]
|
80
|
+
attr_reader :unmet_dependencies
|
81
|
+
|
82
|
+
# @return [Array<GraphQL::Language::Nodes::FragmentDefinition>]
|
83
|
+
attr_reader :unused_dependencies
|
84
|
+
|
85
|
+
def initialize
|
86
|
+
@dependencies = Hash.new { |h, k| h[k] = [] }
|
87
|
+
@cyclical_definitions = []
|
88
|
+
@unmet_dependencies = Hash.new { |h, k| h[k] = [] }
|
89
|
+
@unused_dependencies = []
|
90
|
+
end
|
91
|
+
|
92
|
+
# @return [Array<GraphQL::Language::Nodes::AbstractNode>] dependencies for `definition_node`
|
93
|
+
def [](definition_node)
|
94
|
+
@dependencies[definition_node]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class NodeWithPath
|
99
|
+
extend Forwardable
|
100
|
+
attr_reader :node, :path
|
101
|
+
def initialize(node, path)
|
102
|
+
@node = node
|
103
|
+
@path = path
|
104
|
+
end
|
105
|
+
|
106
|
+
def_delegators :@node, :name, :eql?, :hash
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
# Return a hash of { node => [node, node ... ]} pairs
|
112
|
+
# Keys are top-level definitions
|
113
|
+
# Values are arrays of flattened dependencies
|
114
|
+
def resolve_dependencies
|
115
|
+
dependency_map = DependencyMap.new
|
116
|
+
# Don't allow the loop to run more times
|
117
|
+
# than the number of fragments in the document
|
118
|
+
max_loops = 0
|
119
|
+
@defdep_fragment_definitions.each_value do |v|
|
120
|
+
max_loops += v.size
|
121
|
+
end
|
122
|
+
|
123
|
+
loops = 0
|
124
|
+
|
125
|
+
# Instead of tracking independent fragments _as you visit_,
|
126
|
+
# determine them at the end. This way, we can treat fragments with the
|
127
|
+
# same name as if they were the same name. If _any_ of the fragments
|
128
|
+
# with that name has a dependency, we record it.
|
129
|
+
independent_fragment_nodes = @defdep_fragment_definitions.values.flatten - @defdep_immediate_dependencies.keys
|
130
|
+
|
131
|
+
while fragment_node = independent_fragment_nodes.pop
|
132
|
+
loops += 1
|
133
|
+
if loops > max_loops
|
134
|
+
raise("Resolution loops exceeded the number of definitions; infinite loop detected. (Max: #{max_loops}, Current: #{loops})")
|
135
|
+
end
|
136
|
+
# Since it's independent, let's remove it from here.
|
137
|
+
# That way, we can use the remainder to identify cycles
|
138
|
+
@defdep_immediate_dependencies.delete(fragment_node)
|
139
|
+
fragment_usages = @defdep_dependent_definitions[fragment_node.name]
|
140
|
+
if fragment_usages.empty?
|
141
|
+
# If we didn't record any usages during the visit,
|
142
|
+
# then this fragment is unused.
|
143
|
+
dependency_map.unused_dependencies << @defdep_node_paths[fragment_node]
|
144
|
+
else
|
145
|
+
fragment_usages.each do |definition_node|
|
146
|
+
# Register the dependency AND second-order dependencies
|
147
|
+
dependency_map[definition_node] << fragment_node
|
148
|
+
dependency_map[definition_node].concat(dependency_map[fragment_node])
|
149
|
+
# Since we've registered it, remove it from our to-do list
|
150
|
+
deps = @defdep_immediate_dependencies[definition_node]
|
151
|
+
# Can't find a way to _just_ delete from `deps` and return the deleted entries
|
152
|
+
removed, remaining = deps.partition { |spread| spread.name == fragment_node.name }
|
153
|
+
@defdep_immediate_dependencies[definition_node] = remaining
|
154
|
+
if block_given?
|
155
|
+
yield(definition_node, removed, fragment_node)
|
156
|
+
end
|
157
|
+
if remaining.empty? &&
|
158
|
+
definition_node.is_a?(GraphQL::Language::Nodes::FragmentDefinition) &&
|
159
|
+
definition_node.name != fragment_node.name
|
160
|
+
# If all of this definition's dependencies have
|
161
|
+
# been resolved, we can now resolve its
|
162
|
+
# own dependents.
|
163
|
+
#
|
164
|
+
# But, it's possible to have a duplicate-named fragment here.
|
165
|
+
# Skip it in that case
|
166
|
+
independent_fragment_nodes << definition_node
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# If any dependencies were _unmet_
|
173
|
+
# (eg, spreads with no corresponding definition)
|
174
|
+
# then they're still in there
|
175
|
+
@defdep_immediate_dependencies.each do |defn_node, deps|
|
176
|
+
deps.each do |spread|
|
177
|
+
if !@defdep_fragment_definitions.key?(spread.name)
|
178
|
+
dependency_map.unmet_dependencies[@defdep_node_paths[defn_node]] << @defdep_node_paths[spread]
|
179
|
+
deps.delete(spread)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
if deps.empty?
|
183
|
+
@defdep_immediate_dependencies.delete(defn_node)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# Anything left in @immediate_dependencies is cyclical
|
188
|
+
cyclical_nodes = @defdep_immediate_dependencies.keys.map { |n| @defdep_node_paths[n] }
|
189
|
+
# @immediate_dependencies also includes operation names, but we don't care about
|
190
|
+
# those. They became nil when we looked them up on `@fragment_definitions`, so remove them.
|
191
|
+
cyclical_nodes.compact!
|
192
|
+
dependency_map.cyclical_definitions.concat(cyclical_nodes)
|
193
|
+
|
194
|
+
dependency_map
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
# Generates GraphQL-compliant validation message.
|
5
|
+
class Error
|
6
|
+
# Convenience for validators
|
7
|
+
module ErrorHelper
|
8
|
+
# Error `error_message` is located at `node`
|
9
|
+
def error(error_message, nodes, context: nil, path: nil, extensions: {})
|
10
|
+
path ||= context.path
|
11
|
+
nodes = Array(nodes)
|
12
|
+
GraphQL::StaticValidation::Error.new(error_message, nodes: nodes, path: path)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :message
|
17
|
+
attr_accessor :path
|
18
|
+
|
19
|
+
def initialize(message, path: nil, nodes: [])
|
20
|
+
@message = message
|
21
|
+
@nodes = Array(nodes)
|
22
|
+
@path = path
|
23
|
+
end
|
24
|
+
|
25
|
+
# A hash representation of this Message
|
26
|
+
def to_h
|
27
|
+
{
|
28
|
+
"message" => message,
|
29
|
+
"locations" => locations
|
30
|
+
}.tap { |h| h["path"] = path unless path.nil? }
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
attr_reader :nodes
|
36
|
+
|
37
|
+
def locations
|
38
|
+
nodes.map do |node|
|
39
|
+
h = {"line" => node.line, "column" => node.col}
|
40
|
+
h["filename"] = node.filename if node.filename
|
41
|
+
h
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class InterpreterVisitor < BaseVisitor
|
5
|
+
include(GraphQL::StaticValidation::DefinitionDependencies)
|
6
|
+
|
7
|
+
StaticValidation::ALL_RULES.reverse_each do |r|
|
8
|
+
include(r)
|
9
|
+
end
|
10
|
+
|
11
|
+
include(ContextMethods)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
# Test whether `ast_value` is a valid input for `type`
|
5
|
+
class LiteralValidator
|
6
|
+
def initialize(context:)
|
7
|
+
@context = context
|
8
|
+
@warden = context.warden
|
9
|
+
@invalid_response = GraphQL::Query::InputValidationResult.new(valid: false, problems: [])
|
10
|
+
@valid_response = GraphQL::Query::InputValidationResult.new(valid: true, problems: [])
|
11
|
+
end
|
12
|
+
|
13
|
+
def validate(ast_value, type)
|
14
|
+
catch(:invalid) do
|
15
|
+
recursively_validate(ast_value, type)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def recursively_validate(ast_value, type)
|
22
|
+
if type.nil?
|
23
|
+
# this means we're an undefined argument, see #present_input_field_values_are_valid
|
24
|
+
maybe_raise_if_invalid(ast_value) do
|
25
|
+
@invalid_response
|
26
|
+
end
|
27
|
+
elsif ast_value.is_a?(GraphQL::Language::Nodes::NullValue)
|
28
|
+
maybe_raise_if_invalid(ast_value) do
|
29
|
+
type.kind.non_null? ? @invalid_response : @valid_response
|
30
|
+
end
|
31
|
+
elsif type.kind.non_null?
|
32
|
+
maybe_raise_if_invalid(ast_value) do
|
33
|
+
ast_value.nil? ?
|
34
|
+
@invalid_response :
|
35
|
+
recursively_validate(ast_value, type.of_type)
|
36
|
+
end
|
37
|
+
elsif type.kind.list?
|
38
|
+
item_type = type.of_type
|
39
|
+
results = ensure_array(ast_value).map { |val| recursively_validate(val, item_type) }
|
40
|
+
merge_results(results)
|
41
|
+
elsif ast_value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
|
42
|
+
@valid_response
|
43
|
+
elsif type.kind.scalar? && constant_scalar?(ast_value)
|
44
|
+
maybe_raise_if_invalid(ast_value) do
|
45
|
+
type.validate_input(ast_value, @context)
|
46
|
+
end
|
47
|
+
elsif type.kind.enum?
|
48
|
+
maybe_raise_if_invalid(ast_value) do
|
49
|
+
if ast_value.is_a?(GraphQL::Language::Nodes::Enum)
|
50
|
+
type.validate_input(ast_value.name, @context)
|
51
|
+
else
|
52
|
+
# if our ast_value isn't an Enum it's going to be invalid so return false
|
53
|
+
@invalid_response
|
54
|
+
end
|
55
|
+
end
|
56
|
+
elsif type.kind.input_object? && ast_value.is_a?(GraphQL::Language::Nodes::InputObject)
|
57
|
+
maybe_raise_if_invalid(ast_value) do
|
58
|
+
merge_results([
|
59
|
+
required_input_fields_are_present(type, ast_value),
|
60
|
+
present_input_field_values_are_valid(type, ast_value)
|
61
|
+
])
|
62
|
+
end
|
63
|
+
else
|
64
|
+
maybe_raise_if_invalid(ast_value) do
|
65
|
+
@invalid_response
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# When `error_bubbling` is false, we want to bail on the first failure that we find.
|
71
|
+
# Use `throw` to escape the current call stack, returning the invalid response.
|
72
|
+
def maybe_raise_if_invalid(ast_value)
|
73
|
+
ret = yield
|
74
|
+
if !@context.schema.error_bubbling && !ret.valid?
|
75
|
+
throw(:invalid, ret)
|
76
|
+
else
|
77
|
+
ret
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# The GraphQL grammar supports variables embedded within scalars but graphql.js
|
82
|
+
# doesn't support it so we won't either for simplicity
|
83
|
+
def constant_scalar?(ast_value)
|
84
|
+
if ast_value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
|
85
|
+
false
|
86
|
+
elsif ast_value.is_a?(Array)
|
87
|
+
ast_value.all? { |element| constant_scalar?(element) }
|
88
|
+
elsif ast_value.is_a?(GraphQL::Language::Nodes::InputObject)
|
89
|
+
ast_value.arguments.all? { |arg| constant_scalar?(arg.value) }
|
90
|
+
else
|
91
|
+
true
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def required_input_fields_are_present(type, ast_node)
|
96
|
+
# TODO - would be nice to use these to create an error message so the caller knows
|
97
|
+
# that required fields are missing
|
98
|
+
required_field_names = @warden.arguments(type)
|
99
|
+
.select { |argument| argument.type.kind.non_null? && @warden.get_argument(type, argument.name) }
|
100
|
+
.map(&:name)
|
101
|
+
|
102
|
+
present_field_names = ast_node.arguments.map(&:name)
|
103
|
+
missing_required_field_names = required_field_names - present_field_names
|
104
|
+
if @context.schema.error_bubbling
|
105
|
+
missing_required_field_names.empty? ? @valid_response : @invalid_response
|
106
|
+
else
|
107
|
+
results = missing_required_field_names.map do |name|
|
108
|
+
arg_type = @warden.get_argument(type, name).type
|
109
|
+
recursively_validate(GraphQL::Language::Nodes::NullValue.new(name: name), arg_type)
|
110
|
+
end
|
111
|
+
merge_results(results)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def present_input_field_values_are_valid(type, ast_node)
|
116
|
+
results = ast_node.arguments.map do |value|
|
117
|
+
field = @warden.get_argument(type, value.name)
|
118
|
+
# we want to call validate on an argument even if it's an invalid one
|
119
|
+
# so that our raise exception is on it instead of the entire InputObject
|
120
|
+
field_type = field && field.type
|
121
|
+
recursively_validate(value.value, field_type)
|
122
|
+
end
|
123
|
+
merge_results(results)
|
124
|
+
end
|
125
|
+
|
126
|
+
def ensure_array(value)
|
127
|
+
value.is_a?(Array) ? value : [value]
|
128
|
+
end
|
129
|
+
|
130
|
+
def merge_results(results_list)
|
131
|
+
merged_result = Query::InputValidationResult.new
|
132
|
+
results_list.each do |inner_result|
|
133
|
+
merged_result.merge_result!([], inner_result)
|
134
|
+
end
|
135
|
+
merged_result
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module StaticValidation
|
4
|
+
class NoValidateVisitor < StaticValidation::BaseVisitor
|
5
|
+
include(GraphQL::InternalRepresentation::Rewrite)
|
6
|
+
include(GraphQL::StaticValidation::DefinitionDependencies)
|
7
|
+
include(ContextMethods)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|