graphql 1.12.12 → 2.4.8
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 +4 -4
- data/lib/generators/graphql/core.rb +3 -8
- data/lib/generators/graphql/enum_generator.rb +4 -10
- data/lib/generators/graphql/field_extractor.rb +31 -0
- data/lib/generators/graphql/input_generator.rb +50 -0
- data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
- data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +2 -0
- data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +60 -4
- data/lib/generators/graphql/interface_generator.rb +7 -7
- data/lib/generators/graphql/mutation_create_generator.rb +22 -0
- data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
- data/lib/generators/graphql/mutation_generator.rb +5 -30
- data/lib/generators/graphql/mutation_update_generator.rb +22 -0
- data/lib/generators/graphql/object_generator.rb +10 -38
- data/lib/generators/graphql/orm_mutations_base.rb +40 -0
- data/lib/generators/graphql/relay.rb +23 -12
- data/lib/generators/graphql/scalar_generator.rb +4 -2
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +2 -0
- data/lib/generators/graphql/templates/base_edge.erb +2 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_resolver.erb +8 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/enum.erb +5 -1
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
- data/lib/generators/graphql/templates/input.erb +9 -0
- data/lib/generators/graphql/templates/interface.erb +4 -2
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +3 -1
- data/lib/generators/graphql/templates/mutation_create.erb +20 -0
- data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
- data/lib/generators/graphql/templates/mutation_update.erb +21 -0
- data/lib/generators/graphql/templates/node_type.erb +2 -0
- data/lib/generators/graphql/templates/object.erb +4 -2
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/scalar.erb +3 -1
- data/lib/generators/graphql/templates/schema.erb +22 -2
- data/lib/generators/graphql/templates/union.erb +4 -2
- data/lib/generators/graphql/type_generator.rb +46 -10
- data/lib/generators/graphql/union_generator.rb +5 -5
- data/lib/graphql/analysis/analyzer.rb +89 -0
- data/lib/graphql/analysis/field_usage.rb +65 -28
- data/lib/graphql/analysis/max_query_complexity.rb +11 -17
- data/lib/graphql/analysis/max_query_depth.rb +13 -19
- data/lib/graphql/analysis/query_complexity.rb +156 -61
- data/lib/graphql/analysis/query_depth.rb +38 -23
- data/lib/graphql/analysis/visitor.rb +283 -0
- data/lib/graphql/analysis.rb +90 -6
- data/lib/graphql/autoload.rb +38 -0
- data/lib/graphql/backtrace/inspect_result.rb +0 -12
- data/lib/graphql/backtrace/table.rb +4 -22
- data/lib/graphql/backtrace/trace.rb +93 -0
- data/lib/graphql/backtrace/tracer.rb +8 -6
- data/lib/graphql/backtrace.rb +3 -8
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/current.rb +52 -0
- data/lib/graphql/dataloader/async_dataloader.rb +89 -0
- data/lib/graphql/dataloader/null_dataloader.rb +4 -2
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/dataloader/source.rb +125 -33
- data/lib/graphql/dataloader.rb +193 -143
- data/lib/graphql/date_encoding_error.rb +16 -0
- data/lib/graphql/dig.rb +1 -1
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/errors.rb +12 -81
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/arguments.rb +2 -2
- data/lib/graphql/execution/interpreter/arguments_cache.rb +33 -36
- data/lib/graphql/execution/interpreter/resolve.rb +38 -4
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +175 -0
- data/lib/graphql/execution/interpreter/runtime.rb +447 -403
- data/lib/graphql/execution/interpreter.rb +126 -80
- data/lib/graphql/execution/lazy.rb +11 -21
- data/lib/graphql/execution/lookahead.rb +133 -55
- data/lib/graphql/execution/multiplex.rb +4 -172
- data/lib/graphql/execution.rb +11 -4
- data/lib/graphql/integer_encoding_error.rb +18 -2
- data/lib/graphql/introspection/directive_location_enum.rb +2 -2
- data/lib/graphql/introspection/directive_type.rb +6 -4
- data/lib/graphql/introspection/dynamic_fields.rb +3 -8
- data/lib/graphql/introspection/entry_points.rb +11 -18
- data/lib/graphql/introspection/enum_value_type.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +4 -4
- data/lib/graphql/introspection/input_value_type.rb +10 -4
- data/lib/graphql/introspection/schema_type.rb +17 -15
- data/lib/graphql/introspection/type_type.rb +29 -16
- data/lib/graphql/introspection.rb +6 -2
- data/lib/graphql/invalid_null_error.rb +1 -1
- data/lib/graphql/language/block_string.rb +37 -25
- data/lib/graphql/language/cache.rb +13 -0
- data/lib/graphql/language/comment.rb +18 -0
- data/lib/graphql/language/definition_slice.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +122 -81
- data/lib/graphql/language/lexer.rb +364 -1467
- data/lib/graphql/language/nodes.rb +197 -106
- data/lib/graphql/language/parser.rb +799 -1920
- data/lib/graphql/language/printer.rb +372 -160
- data/lib/graphql/language/sanitized_printer.rb +25 -27
- data/lib/graphql/language/static_visitor.rb +167 -0
- data/lib/graphql/language/visitor.rb +188 -141
- data/lib/graphql/language.rb +62 -1
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/name_validator.rb +0 -4
- data/lib/graphql/pagination/active_record_relation_connection.rb +37 -8
- data/lib/graphql/pagination/array_connection.rb +8 -6
- data/lib/graphql/pagination/connection.rb +61 -7
- data/lib/graphql/pagination/connections.rb +22 -23
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/pagination/relation_connection.rb +60 -28
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +146 -222
- data/lib/graphql/query/input_validation_result.rb +10 -1
- data/lib/graphql/query/null_context.rb +15 -32
- data/lib/graphql/query/validation_pipeline.rb +15 -39
- data/lib/graphql/query/variable_validation_error.rb +3 -3
- data/lib/graphql/query/variables.rb +35 -17
- data/lib/graphql/query.rb +149 -82
- data/lib/graphql/railtie.rb +15 -109
- data/lib/graphql/rake_task/validate.rb +1 -1
- data/lib/graphql/rake_task.rb +30 -11
- data/lib/graphql/relay/range_add.rb +9 -16
- data/lib/graphql/relay.rb +0 -15
- 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/graphql/field_type_in_block.rb +144 -0
- data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
- data/lib/graphql/rubocop.rb +6 -0
- data/lib/graphql/schema/addition.rb +98 -54
- data/lib/graphql/schema/always_visible.rb +14 -0
- data/lib/graphql/schema/argument.rb +179 -82
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +77 -39
- data/lib/graphql/schema/directive/feature.rb +1 -1
- data/lib/graphql/schema/directive/flagged.rb +4 -4
- data/lib/graphql/schema/directive/include.rb +1 -1
- data/lib/graphql/schema/directive/one_of.rb +24 -0
- data/lib/graphql/schema/directive/skip.rb +1 -1
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive/transform.rb +2 -2
- data/lib/graphql/schema/directive.rb +36 -22
- data/lib/graphql/schema/enum.rb +158 -63
- data/lib/graphql/schema/enum_value.rb +12 -21
- data/lib/graphql/schema/field/connection_extension.rb +7 -17
- data/lib/graphql/schema/field/scope_extension.rb +8 -1
- data/lib/graphql/schema/field.rb +521 -359
- data/lib/graphql/schema/field_extension.rb +86 -2
- data/lib/graphql/schema/find_inherited_value.rb +3 -7
- data/lib/graphql/schema/finder.rb +5 -5
- data/lib/graphql/schema/has_single_input_argument.rb +160 -0
- data/lib/graphql/schema/input_object.rb +148 -99
- data/lib/graphql/schema/interface.rb +41 -64
- data/lib/graphql/schema/introspection_system.rb +12 -26
- data/lib/graphql/schema/late_bound_type.rb +12 -2
- data/lib/graphql/schema/list.rb +18 -7
- data/lib/graphql/schema/loader.rb +6 -5
- data/lib/graphql/schema/member/base_dsl_methods.rb +32 -18
- data/lib/graphql/schema/member/build_type.rb +16 -13
- data/lib/graphql/schema/member/has_arguments.rb +270 -86
- data/lib/graphql/schema/member/has_ast_node.rb +12 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
- data/lib/graphql/schema/member/has_directives.rb +81 -61
- data/lib/graphql/schema/member/has_fields.rb +169 -31
- data/lib/graphql/schema/member/has_interfaces.rb +143 -0
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/member/has_validators.rb +32 -6
- data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +16 -0
- data/lib/graphql/schema/member/validates_input.rb +6 -6
- data/lib/graphql/schema/member.rb +1 -6
- data/lib/graphql/schema/mutation.rb +7 -9
- data/lib/graphql/schema/non_null.rb +7 -7
- data/lib/graphql/schema/object.rb +38 -119
- data/lib/graphql/schema/printer.rb +24 -25
- data/lib/graphql/schema/relay_classic_mutation.rb +13 -91
- data/lib/graphql/schema/resolver/has_payload_type.rb +46 -11
- data/lib/graphql/schema/resolver.rb +118 -115
- data/lib/graphql/schema/scalar.rb +20 -21
- data/lib/graphql/schema/subscription.rb +95 -21
- data/lib/graphql/schema/timeout.rb +25 -29
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/type_membership.rb +21 -4
- data/lib/graphql/schema/union.rb +16 -16
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema/validator/all_validator.rb +62 -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 +3 -1
- data/lib/graphql/schema/validator/format_validator.rb +4 -5
- data/lib/graphql/schema/validator/inclusion_validator.rb +3 -1
- data/lib/graphql/schema/validator/length_validator.rb +5 -3
- data/lib/graphql/schema/validator/numericality_validator.rb +13 -2
- data/lib/graphql/schema/validator/required_validator.rb +56 -18
- data/lib/graphql/schema/validator.rb +38 -28
- data/lib/graphql/schema/visibility/migration.rb +188 -0
- data/lib/graphql/schema/visibility/profile.rb +359 -0
- data/lib/graphql/schema/visibility/visit.rb +190 -0
- data/lib/graphql/schema/visibility.rb +294 -0
- data/lib/graphql/schema/warden.rb +423 -134
- data/lib/graphql/schema/wrapper.rb +0 -5
- data/lib/graphql/schema.rb +1015 -1057
- data/lib/graphql/static_validation/all_rules.rb +3 -1
- data/lib/graphql/static_validation/base_visitor.rb +15 -28
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -2
- data/lib/graphql/static_validation/error.rb +3 -1
- data/lib/graphql/static_validation/literal_validator.rb +24 -7
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +4 -3
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +13 -7
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +15 -13
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +13 -5
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +62 -35
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
- data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
- data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +7 -5
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +14 -8
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +14 -8
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
- data/lib/graphql/static_validation/validation_context.rb +32 -6
- data/lib/graphql/static_validation/validator.rb +11 -27
- data/lib/graphql/static_validation.rb +0 -3
- data/lib/graphql/string_encoding_error.rb +13 -3
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +49 -11
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +40 -1
- data/lib/graphql/subscriptions/event.rb +87 -38
- data/lib/graphql/subscriptions/serialize.rb +27 -3
- data/lib/graphql/subscriptions.rb +63 -49
- data/lib/graphql/testing/helpers.rb +155 -0
- data/lib/graphql/testing.rb +2 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +6 -20
- data/lib/graphql/tracing/appoptics_trace.rb +253 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +4 -2
- data/lib/graphql/tracing/appsignal_trace.rb +79 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +17 -0
- data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
- data/lib/graphql/tracing/data_dog_trace.rb +185 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +27 -15
- data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +11 -28
- data/lib/graphql/tracing/legacy_trace.rb +12 -0
- data/lib/graphql/tracing/new_relic_trace.rb +77 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
- data/lib/graphql/tracing/notifications_trace.rb +45 -0
- data/lib/graphql/tracing/notifications_tracing.rb +61 -0
- data/lib/graphql/tracing/null_trace.rb +9 -0
- data/lib/graphql/tracing/platform_trace.rb +118 -0
- data/lib/graphql/tracing/platform_tracing.rb +46 -49
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +6 -2
- data/lib/graphql/tracing/prometheus_trace.rb +94 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +5 -3
- data/lib/graphql/tracing/scout_trace.rb +74 -0
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +114 -0
- data/lib/graphql/tracing/statsd_trace.rb +58 -0
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +79 -0
- data/lib/graphql/tracing.rb +29 -52
- data/lib/graphql/type_kinds.rb +7 -4
- data/lib/graphql/types/big_int.rb +5 -1
- data/lib/graphql/types/int.rb +1 -1
- data/lib/graphql/types/iso_8601_date.rb +17 -6
- data/lib/graphql/types/iso_8601_date_time.rb +12 -1
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/base_connection.rb +16 -6
- data/lib/graphql/types/relay/connection_behaviors.rb +92 -32
- data/lib/graphql/types/relay/edge_behaviors.rb +46 -7
- data/lib/graphql/types/relay/has_node_field.rb +2 -2
- data/lib/graphql/types/relay/has_nodes_field.rb +2 -2
- data/lib/graphql/types/relay/node_behaviors.rb +12 -2
- data/lib/graphql/types/relay/page_info_behaviors.rb +11 -2
- data/lib/graphql/types/relay.rb +0 -3
- data/lib/graphql/types/string.rb +2 -2
- data/lib/graphql/types.rb +18 -10
- data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
- data/lib/graphql/unauthorized_error.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +82 -137
- data/readme.md +13 -6
- metadata +127 -186
- data/lib/graphql/analysis/analyze_query.rb +0 -98
- data/lib/graphql/analysis/ast/analyzer.rb +0 -84
- data/lib/graphql/analysis/ast/field_usage.rb +0 -28
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -23
- data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
- data/lib/graphql/analysis/ast/query_complexity.rb +0 -234
- data/lib/graphql/analysis/ast/query_depth.rb +0 -56
- data/lib/graphql/analysis/ast/visitor.rb +0 -268
- data/lib/graphql/analysis/ast.rb +0 -91
- data/lib/graphql/analysis/reducer_state.rb +0 -48
- data/lib/graphql/argument.rb +0 -131
- data/lib/graphql/authorization.rb +0 -82
- data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
- data/lib/graphql/backwards_compatibility.rb +0 -61
- data/lib/graphql/base_type.rb +0 -230
- data/lib/graphql/boolean_type.rb +0 -2
- data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
- data/lib/graphql/compatibility/execution_specification.rb +0 -436
- data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
- data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
- data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
- data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
- data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
- data/lib/graphql/compatibility.rb +0 -5
- data/lib/graphql/define/assign_argument.rb +0 -12
- data/lib/graphql/define/assign_connection.rb +0 -13
- data/lib/graphql/define/assign_enum_value.rb +0 -18
- data/lib/graphql/define/assign_global_id_field.rb +0 -11
- data/lib/graphql/define/assign_mutation_function.rb +0 -34
- data/lib/graphql/define/assign_object_field.rb +0 -42
- data/lib/graphql/define/defined_object_proxy.rb +0 -53
- data/lib/graphql/define/instance_definable.rb +0 -240
- data/lib/graphql/define/no_definition_error.rb +0 -7
- data/lib/graphql/define/non_null_with_bang.rb +0 -16
- data/lib/graphql/define/type_definer.rb +0 -31
- data/lib/graphql/define.rb +0 -31
- data/lib/graphql/deprecated_dsl.rb +0 -47
- data/lib/graphql/deprecation.rb +0 -13
- data/lib/graphql/directive/deprecated_directive.rb +0 -2
- data/lib/graphql/directive/include_directive.rb +0 -2
- data/lib/graphql/directive/skip_directive.rb +0 -2
- data/lib/graphql/directive.rb +0 -111
- data/lib/graphql/enum_type.rb +0 -129
- data/lib/graphql/execution/execute.rb +0 -333
- data/lib/graphql/execution/flatten.rb +0 -40
- data/lib/graphql/execution/lazy/resolve.rb +0 -91
- data/lib/graphql/execution/typecast.rb +0 -50
- data/lib/graphql/field/resolve.rb +0 -59
- data/lib/graphql/field.rb +0 -226
- data/lib/graphql/filter.rb +0 -53
- data/lib/graphql/float_type.rb +0 -2
- data/lib/graphql/function.rb +0 -128
- data/lib/graphql/id_type.rb +0 -2
- data/lib/graphql/input_object_type.rb +0 -138
- data/lib/graphql/int_type.rb +0 -2
- data/lib/graphql/interface_type.rb +0 -72
- data/lib/graphql/internal_representation/document.rb +0 -27
- data/lib/graphql/internal_representation/node.rb +0 -206
- data/lib/graphql/internal_representation/print.rb +0 -51
- data/lib/graphql/internal_representation/rewrite.rb +0 -184
- data/lib/graphql/internal_representation/scope.rb +0 -88
- data/lib/graphql/internal_representation/visit.rb +0 -36
- data/lib/graphql/internal_representation.rb +0 -7
- data/lib/graphql/language/lexer.rl +0 -262
- data/lib/graphql/language/parser.y +0 -543
- data/lib/graphql/language/token.rb +0 -38
- data/lib/graphql/list_type.rb +0 -80
- data/lib/graphql/non_null_type.rb +0 -71
- data/lib/graphql/object_type.rb +0 -130
- data/lib/graphql/query/arguments.rb +0 -189
- data/lib/graphql/query/arguments_cache.rb +0 -24
- data/lib/graphql/query/executor.rb +0 -52
- data/lib/graphql/query/literal_input.rb +0 -136
- data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
- data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
- data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
- data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
- data/lib/graphql/query/serial_execution.rb +0 -40
- data/lib/graphql/relay/array_connection.rb +0 -83
- data/lib/graphql/relay/base_connection.rb +0 -189
- data/lib/graphql/relay/connection_instrumentation.rb +0 -54
- data/lib/graphql/relay/connection_resolve.rb +0 -43
- data/lib/graphql/relay/connection_type.rb +0 -41
- data/lib/graphql/relay/edge.rb +0 -27
- data/lib/graphql/relay/edge_type.rb +0 -19
- data/lib/graphql/relay/edges_instrumentation.rb +0 -40
- data/lib/graphql/relay/global_id_resolve.rb +0 -18
- data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
- data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
- data/lib/graphql/relay/mutation/resolve.rb +0 -56
- data/lib/graphql/relay/mutation/result.rb +0 -38
- data/lib/graphql/relay/mutation.rb +0 -106
- data/lib/graphql/relay/node.rb +0 -39
- data/lib/graphql/relay/page_info.rb +0 -7
- data/lib/graphql/relay/relation_connection.rb +0 -188
- data/lib/graphql/relay/type_extensions.rb +0 -32
- data/lib/graphql/scalar_type.rb +0 -91
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/schema/catchall_middleware.rb +0 -35
- data/lib/graphql/schema/default_parse_error.rb +0 -10
- data/lib/graphql/schema/default_type_error.rb +0 -17
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
- data/lib/graphql/schema/member/accepts_definition.rb +0 -152
- data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -31
- data/lib/graphql/schema/member/instrumentation.rb +0 -131
- data/lib/graphql/schema/middleware_chain.rb +0 -82
- data/lib/graphql/schema/possible_types.rb +0 -44
- data/lib/graphql/schema/rescue_middleware.rb +0 -60
- data/lib/graphql/schema/timeout_middleware.rb +0 -88
- data/lib/graphql/schema/traversal.rb +0 -228
- data/lib/graphql/schema/validation.rb +0 -313
- data/lib/graphql/static_validation/default_visitor.rb +0 -15
- data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/string_type.rb +0 -2
- data/lib/graphql/subscriptions/instrumentation.rb +0 -79
- data/lib/graphql/subscriptions/subscription_root.rb +0 -76
- data/lib/graphql/tracing/skylight_tracing.rb +0 -70
- data/lib/graphql/types/relay/default_relay.rb +0 -27
- data/lib/graphql/types/relay/node_field.rb +0 -25
- data/lib/graphql/types/relay/nodes_field.rb +0 -27
- data/lib/graphql/union_type.rb +0 -115
- data/lib/graphql/upgrader/member.rb +0 -937
- data/lib/graphql/upgrader/schema.rb +0 -38
@@ -1,937 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
begin
|
3
|
-
require 'parser/current'
|
4
|
-
rescue LoadError
|
5
|
-
raise LoadError, "GraphQL::Upgrader requires the 'parser' gem, please install it and/or add it to your Gemfile"
|
6
|
-
end
|
7
|
-
|
8
|
-
module GraphQL
|
9
|
-
module Upgrader
|
10
|
-
GRAPHQL_TYPES = '(Object|InputObject|Interface|Enum|Scalar|Union)'
|
11
|
-
|
12
|
-
class Transform
|
13
|
-
# @param input_text [String] Untransformed GraphQL-Ruby code
|
14
|
-
# @return [String] The input text, with a transformation applied if necessary
|
15
|
-
def apply(input_text)
|
16
|
-
raise GraphQL::RequiredImplementationMissingError, "Return transformed text here"
|
17
|
-
end
|
18
|
-
|
19
|
-
# Recursively transform a `.define`-DSL-based type expression into a class-ready expression, for example:
|
20
|
-
#
|
21
|
-
# - `types[X]` -> `[X, null: true]`
|
22
|
-
# - `types[X.to_non_null_type]` -> `[X]`
|
23
|
-
# - `Int` -> `Integer`
|
24
|
-
# - `X!` -> `X`
|
25
|
-
#
|
26
|
-
# Notice that `!` is removed sometimes, because it doesn't exist in the class API.
|
27
|
-
#
|
28
|
-
# @param type_expr [String] A `.define`-ready expression of a return type or input type
|
29
|
-
# @return [String] A class-ready expression of the same type`
|
30
|
-
def normalize_type_expression(type_expr, preserve_bang: false)
|
31
|
-
case type_expr
|
32
|
-
when /\A!/
|
33
|
-
# Handle the bang, normalize the inside
|
34
|
-
"#{preserve_bang ? "!" : ""}#{normalize_type_expression(type_expr[1..-1], preserve_bang: preserve_bang)}"
|
35
|
-
when /\Atypes\[.*\]\Z/
|
36
|
-
# Unwrap the brackets, normalize, then re-wrap
|
37
|
-
inner_type = type_expr[6..-2]
|
38
|
-
if inner_type.start_with?("!")
|
39
|
-
nullable = false
|
40
|
-
inner_type = inner_type[1..-1]
|
41
|
-
elsif inner_type.end_with?(".to_non_null_type")
|
42
|
-
nullable = false
|
43
|
-
inner_type = inner_type[0...-17]
|
44
|
-
else
|
45
|
-
nullable = true
|
46
|
-
end
|
47
|
-
|
48
|
-
"[#{normalize_type_expression(inner_type, preserve_bang: preserve_bang)}#{nullable ? ", null: true" : ""}]"
|
49
|
-
when /\Atypes\./
|
50
|
-
# Remove the prefix
|
51
|
-
normalize_type_expression(type_expr[6..-1], preserve_bang: preserve_bang)
|
52
|
-
when /\A->/
|
53
|
-
# Remove the proc wrapper, don't re-apply it
|
54
|
-
# because stabby is not supported in class-based definition
|
55
|
-
# (and shouldn't ever be necessary)
|
56
|
-
unwrapped = type_expr
|
57
|
-
.sub(/\A->\s?\{\s*/, "")
|
58
|
-
.sub(/\s*\}/, "")
|
59
|
-
normalize_type_expression(unwrapped, preserve_bang: preserve_bang)
|
60
|
-
when "Int"
|
61
|
-
"Integer"
|
62
|
-
else
|
63
|
-
type_expr
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def underscorize(str)
|
68
|
-
str
|
69
|
-
.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2') # URLDecoder -> URL_Decoder
|
70
|
-
.gsub(/([a-z\d])([A-Z])/,'\1_\2') # someThing -> some_Thing
|
71
|
-
.downcase
|
72
|
-
end
|
73
|
-
|
74
|
-
def apply_processor(input_text, processor)
|
75
|
-
ruby_ast = Parser::CurrentRuby.parse(input_text)
|
76
|
-
processor.process(ruby_ast)
|
77
|
-
processor
|
78
|
-
rescue Parser::SyntaxError
|
79
|
-
puts "Error text:"
|
80
|
-
puts input_text
|
81
|
-
raise
|
82
|
-
end
|
83
|
-
|
84
|
-
def reindent_lines(input_text, from_indent:, to_indent:)
|
85
|
-
prev_indent = " " * from_indent
|
86
|
-
next_indent = " " * to_indent
|
87
|
-
# For each line, remove the previous indent, then add the new indent
|
88
|
-
lines = input_text.split("\n").map do |line|
|
89
|
-
line = line.sub(prev_indent, "")
|
90
|
-
"#{next_indent}#{line}".rstrip
|
91
|
-
end
|
92
|
-
lines.join("\n")
|
93
|
-
end
|
94
|
-
|
95
|
-
# Remove trailing whitespace
|
96
|
-
def trim_lines(input_text)
|
97
|
-
input_text.gsub(/ +$/, "")
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
# Turns `{X} = GraphQL::{Y}Type.define do` into `class {X} < Types::Base{Y}`.
|
102
|
-
class TypeDefineToClassTransform < Transform
|
103
|
-
# @param base_class_pattern [String] Replacement pattern for the base class name. Use this if your base classes have nonstandard names.
|
104
|
-
def initialize(base_class_pattern: "Types::Base\\3")
|
105
|
-
@find_pattern = /( *)([a-zA-Z_0-9:]*) = GraphQL::#{GRAPHQL_TYPES}Type\.define do/
|
106
|
-
@replace_pattern = "\\1class \\2 < #{base_class_pattern}"
|
107
|
-
@interface_replace_pattern = "\\1module \\2\n\\1 include #{base_class_pattern}"
|
108
|
-
end
|
109
|
-
|
110
|
-
def apply(input_text)
|
111
|
-
if input_text.include?("GraphQL::InterfaceType.define")
|
112
|
-
input_text.sub(@find_pattern, @interface_replace_pattern)
|
113
|
-
else
|
114
|
-
input_text.sub(@find_pattern, @replace_pattern)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
# Turns `{X} = GraphQL::Relay::Mutation.define do` into `class {X} < Mutations::BaseMutation`
|
120
|
-
class MutationDefineToClassTransform < Transform
|
121
|
-
# @param base_class_name [String] Replacement pattern for the base class name. Use this if your Mutation base class has a nonstandard name.
|
122
|
-
def initialize(base_class_name: "Mutations::BaseMutation")
|
123
|
-
@find_pattern = /([a-zA-Z_0-9:]*) = GraphQL::Relay::Mutation.define do/
|
124
|
-
@replace_pattern = "class \\1 < #{base_class_name}"
|
125
|
-
end
|
126
|
-
|
127
|
-
def apply(input_text)
|
128
|
-
input_text.gsub(@find_pattern, @replace_pattern)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
# Remove `name "Something"` if it is redundant with the class name.
|
133
|
-
# Or, if it is not redundant, move it to `graphql_name "Something"`.
|
134
|
-
class NameTransform < Transform
|
135
|
-
def apply(transformable)
|
136
|
-
last_type_defn = transformable
|
137
|
-
.split("\n")
|
138
|
-
.select { |line| line.include?("class ") || line.include?("module ")}
|
139
|
-
.last
|
140
|
-
|
141
|
-
if last_type_defn && (matches = last_type_defn.match(/(class|module) (?<type_name>[a-zA-Z_0-9:]*)( <|$)/))
|
142
|
-
type_name = matches[:type_name]
|
143
|
-
# Get the name without any prefixes or suffixes
|
144
|
-
type_name_without_the_type_part = type_name.split('::').last.gsub(/Type$/, '')
|
145
|
-
# Find an overridden name value
|
146
|
-
if matches = transformable.match(/ name ('|")(?<overridden_name>.*)('|")/)
|
147
|
-
name = matches[:overridden_name]
|
148
|
-
if type_name_without_the_type_part != name
|
149
|
-
# If the overridden name is still required, use `graphql_name` for it
|
150
|
-
transformable = transformable.gsub(/ name (.*)/, ' graphql_name \1')
|
151
|
-
else
|
152
|
-
# Otherwise, remove it altogether
|
153
|
-
transformable = transformable.gsub(/\s+name ('|").*('|")/, '')
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
transformable
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
# Remove newlines -- normalize the text for processing
|
163
|
-
class RemoveNewlinesTransform
|
164
|
-
def apply(input_text)
|
165
|
-
keep_looking = true
|
166
|
-
while keep_looking do
|
167
|
-
keep_looking = false
|
168
|
-
# Find the `field` call (or other method), and an open paren, but not a close paren, or a comma between arguments
|
169
|
-
input_text = input_text.gsub(/(?<field>(?:field|input_field|return_field|connection|argument)(?:\([^)]*|.*,))\n\s*(?<next_line>.+)/) do
|
170
|
-
keep_looking = true
|
171
|
-
field = $~[:field].chomp
|
172
|
-
next_line = $~[:next_line]
|
173
|
-
|
174
|
-
"#{field} #{next_line}"
|
175
|
-
end
|
176
|
-
end
|
177
|
-
input_text
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
# Remove parens from method call - normalize for processing
|
182
|
-
class RemoveMethodParensTransform < Transform
|
183
|
-
def apply(input_text)
|
184
|
-
input_text.sub(
|
185
|
-
/(field|input_field|return_field|connection|argument)\( *(.*?) *\)( *)/,
|
186
|
-
'\1 \2\3'
|
187
|
-
)
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
# Move `type X` to be the second positional argument to `field ...`
|
192
|
-
class PositionalTypeArgTransform < Transform
|
193
|
-
def apply(input_text)
|
194
|
-
input_text.gsub(
|
195
|
-
/(?<field>(?:field|input_field|return_field|connection|argument) :(?:[a-zA-Z_0-9]*)) do(?<block_contents>.*?)[ ]*type (?<return_type>.*?)\n/m
|
196
|
-
) do
|
197
|
-
field = $~[:field]
|
198
|
-
block_contents = $~[:block_contents]
|
199
|
-
return_type = normalize_type_expression($~[:return_type], preserve_bang: true)
|
200
|
-
|
201
|
-
"#{field}, #{return_type} do#{block_contents}"
|
202
|
-
end
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
# Find a configuration in the block and move it to a kwarg,
|
207
|
-
# for example
|
208
|
-
# ```
|
209
|
-
# do
|
210
|
-
# property :thing
|
211
|
-
# end
|
212
|
-
# ```
|
213
|
-
# becomes:
|
214
|
-
# ```
|
215
|
-
# property: thing
|
216
|
-
# ```
|
217
|
-
class ConfigurationToKwargTransform < Transform
|
218
|
-
def initialize(kwarg:)
|
219
|
-
@kwarg = kwarg
|
220
|
-
end
|
221
|
-
|
222
|
-
def apply(input_text)
|
223
|
-
input_text.gsub(
|
224
|
-
/(?<field>(?:field|return_field|input_field|connection|argument).*) do(?<block_contents>.*?)[ ]*#{@kwarg} (?<kwarg_value>.*?)\n/m
|
225
|
-
) do
|
226
|
-
field = $~[:field]
|
227
|
-
block_contents = $~[:block_contents]
|
228
|
-
kwarg_value = $~[:kwarg_value].strip
|
229
|
-
|
230
|
-
"#{field}, #{@kwarg}: #{kwarg_value} do#{block_contents}"
|
231
|
-
end
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
# Transform `property:` kwarg to `method:` kwarg
|
236
|
-
class PropertyToMethodTransform < Transform
|
237
|
-
def apply(input_text)
|
238
|
-
input_text.gsub /property:/, 'method:'
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
# Find a keyword whose value is a string or symbol,
|
243
|
-
# and if the value is equivalent to the field name,
|
244
|
-
# remove the keyword altogether.
|
245
|
-
class RemoveRedundantKwargTransform < Transform
|
246
|
-
def initialize(kwarg:)
|
247
|
-
@kwarg = kwarg
|
248
|
-
@finder_pattern = /(field|return_field|input_field|connection|argument) :(?<name>[a-zA-Z_0-9]*).*#{@kwarg}: ['":](?<kwarg_value>[a-zA-Z_0-9?!]+)['"]?/
|
249
|
-
end
|
250
|
-
|
251
|
-
def apply(input_text)
|
252
|
-
if input_text =~ @finder_pattern
|
253
|
-
field_name = $~[:name]
|
254
|
-
kwarg_value = $~[:kwarg_value]
|
255
|
-
if field_name == kwarg_value
|
256
|
-
# It's redundant, remove it
|
257
|
-
input_text = input_text.sub(/, #{@kwarg}: ['":]#{kwarg_value}['"]?/, "")
|
258
|
-
end
|
259
|
-
end
|
260
|
-
input_text
|
261
|
-
end
|
262
|
-
end
|
263
|
-
|
264
|
-
# Take camelized field names and convert them to underscore case.
|
265
|
-
# (They'll be automatically camelized later.)
|
266
|
-
class UnderscoreizeFieldNameTransform < Transform
|
267
|
-
def apply(input_text)
|
268
|
-
input_text.gsub /(?<field_type>input_field|return_field|field|connection|argument) :(?<name>[a-zA-Z_0-9_]*)/ do
|
269
|
-
field_type = $~[:field_type]
|
270
|
-
camelized_name = $~[:name]
|
271
|
-
underscored_name = underscorize(camelized_name)
|
272
|
-
"#{field_type} :#{underscored_name}"
|
273
|
-
end
|
274
|
-
end
|
275
|
-
end
|
276
|
-
|
277
|
-
class ProcToClassMethodTransform < Transform
|
278
|
-
# @param proc_name [String] The name of the proc to be moved to `def self.#{proc_name}`
|
279
|
-
def initialize(proc_name)
|
280
|
-
@proc_name = proc_name
|
281
|
-
# This will tell us whether to operate on the input or not
|
282
|
-
@proc_check_pattern = /#{proc_name}\s?->/
|
283
|
-
end
|
284
|
-
|
285
|
-
def apply(input_text)
|
286
|
-
if input_text =~ @proc_check_pattern
|
287
|
-
processor = apply_processor(input_text, NamedProcProcessor.new(@proc_name))
|
288
|
-
processor.proc_to_method_sections.reverse.each do |proc_to_method_section|
|
289
|
-
proc_body = input_text[proc_to_method_section.proc_body_start..proc_to_method_section.proc_body_end]
|
290
|
-
method_defn_indent = " " * proc_to_method_section.proc_defn_indent
|
291
|
-
method_defn = "def self.#{@proc_name}(#{proc_to_method_section.proc_arg_names.join(", ")})\n#{method_defn_indent} #{proc_body}\n#{method_defn_indent}end\n"
|
292
|
-
method_defn = trim_lines(method_defn)
|
293
|
-
# replace the proc with the new method
|
294
|
-
input_text[proc_to_method_section.proc_defn_start..proc_to_method_section.proc_defn_end] = method_defn
|
295
|
-
end
|
296
|
-
end
|
297
|
-
input_text
|
298
|
-
end
|
299
|
-
|
300
|
-
class NamedProcProcessor < Parser::AST::Processor
|
301
|
-
attr_reader :proc_to_method_sections
|
302
|
-
def initialize(proc_name)
|
303
|
-
@proc_name_sym = proc_name.to_sym
|
304
|
-
@proc_to_method_sections = []
|
305
|
-
end
|
306
|
-
|
307
|
-
class ProcToMethodSection
|
308
|
-
attr_accessor :proc_arg_names, :proc_defn_start, :proc_defn_end, :proc_defn_indent, :proc_body_start, :proc_body_end, :inside_proc
|
309
|
-
|
310
|
-
def initialize
|
311
|
-
# @proc_name_sym = proc_name.to_sym
|
312
|
-
@proc_arg_names = nil
|
313
|
-
# Beginning of the `#{proc_name} -> {...}` call
|
314
|
-
@proc_defn_start = nil
|
315
|
-
# End of the last `end/}`
|
316
|
-
@proc_defn_end = nil
|
317
|
-
# Amount of whitespace to insert to the rewritten body
|
318
|
-
@proc_defn_indent = nil
|
319
|
-
# First statement of the proc
|
320
|
-
@proc_body_start = nil
|
321
|
-
# End of last statement in the proc
|
322
|
-
@proc_body_end = nil
|
323
|
-
# Used for identifying the proper block
|
324
|
-
@inside_proc = false
|
325
|
-
end
|
326
|
-
end
|
327
|
-
|
328
|
-
def on_send(node)
|
329
|
-
receiver, method_name, _args = *node
|
330
|
-
if method_name == @proc_name_sym && receiver.nil?
|
331
|
-
proc_section = ProcToMethodSection.new
|
332
|
-
source_exp = node.loc.expression
|
333
|
-
proc_section.proc_defn_start = source_exp.begin.begin_pos
|
334
|
-
proc_section.proc_defn_end = source_exp.end.end_pos
|
335
|
-
proc_section.proc_defn_indent = source_exp.column
|
336
|
-
proc_section.inside_proc = true
|
337
|
-
|
338
|
-
@proc_to_method_sections << proc_section
|
339
|
-
end
|
340
|
-
res = super(node)
|
341
|
-
@inside_proc = false
|
342
|
-
res
|
343
|
-
end
|
344
|
-
|
345
|
-
def on_block(node)
|
346
|
-
send_node, args_node, body_node = node.children
|
347
|
-
_receiver, method_name, _send_args_node = *send_node
|
348
|
-
if method_name == :lambda && !@proc_to_method_sections.empty? && @proc_to_method_sections[-1].inside_proc
|
349
|
-
proc_to_method_section = @proc_to_method_sections[-1]
|
350
|
-
|
351
|
-
source_exp = body_node.loc.expression
|
352
|
-
proc_to_method_section.proc_arg_names = args_node.children.map { |arg_node| arg_node.children[0].to_s }
|
353
|
-
proc_to_method_section.proc_body_start = source_exp.begin.begin_pos
|
354
|
-
proc_to_method_section.proc_body_end = source_exp.end.end_pos
|
355
|
-
proc_to_method_section.inside_proc = false
|
356
|
-
end
|
357
|
-
super(node)
|
358
|
-
end
|
359
|
-
end
|
360
|
-
end
|
361
|
-
|
362
|
-
class MutationResolveProcToMethodTransform < Transform
|
363
|
-
# @param proc_name [String] The name of the proc to be moved to `def self.#{proc_name}`
|
364
|
-
def initialize(proc_name: "resolve")
|
365
|
-
@proc_name = proc_name
|
366
|
-
end
|
367
|
-
|
368
|
-
# TODO dedup with ResolveProcToMethodTransform
|
369
|
-
def apply(input_text)
|
370
|
-
if input_text =~ /GraphQL::Relay::Mutation\.define/
|
371
|
-
named_proc_processor = apply_processor(input_text, ProcToClassMethodTransform::NamedProcProcessor.new(@proc_name))
|
372
|
-
resolve_proc_processor = apply_processor(input_text, ResolveProcToMethodTransform::ResolveProcProcessor.new)
|
373
|
-
|
374
|
-
named_proc_processor.proc_to_method_sections.zip(resolve_proc_processor.resolve_proc_sections).reverse.each do |pair|
|
375
|
-
proc_to_method_section, resolve_proc_section = *pair
|
376
|
-
proc_body = input_text[proc_to_method_section.proc_body_start..proc_to_method_section.proc_body_end]
|
377
|
-
method_defn_indent = " " * proc_to_method_section.proc_defn_indent
|
378
|
-
|
379
|
-
obj_arg_name, args_arg_name, ctx_arg_name = resolve_proc_section.proc_arg_names
|
380
|
-
# This is not good, it will hit false positives
|
381
|
-
# Should use AST to make this substitution
|
382
|
-
if obj_arg_name != "_"
|
383
|
-
proc_body.gsub!(/([^\w:.]|^)#{obj_arg_name}([^\w:]|$)/, '\1object\2')
|
384
|
-
end
|
385
|
-
if ctx_arg_name != "_"
|
386
|
-
proc_body.gsub!(/([^\w:.]|^)#{ctx_arg_name}([^\w:]|$)/, '\1context\2')
|
387
|
-
end
|
388
|
-
|
389
|
-
method_defn = "def #{@proc_name}(**#{args_arg_name})\n#{method_defn_indent} #{proc_body}\n#{method_defn_indent}end\n"
|
390
|
-
method_defn = trim_lines(method_defn)
|
391
|
-
# Update usage of args keys
|
392
|
-
method_defn = method_defn.gsub(/#{args_arg_name}(?<method_begin>\.key\?\(?|\[)["':](?<arg_name>[a-zA-Z0-9_]+)["']?(?<method_end>\]|\))?/) do
|
393
|
-
method_begin = $~[:method_begin]
|
394
|
-
arg_name = underscorize($~[:arg_name])
|
395
|
-
method_end = $~[:method_end]
|
396
|
-
"#{args_arg_name}#{method_begin}:#{arg_name}#{method_end}"
|
397
|
-
end
|
398
|
-
# replace the proc with the new method
|
399
|
-
input_text[proc_to_method_section.proc_defn_start..proc_to_method_section.proc_defn_end] = method_defn
|
400
|
-
end
|
401
|
-
end
|
402
|
-
input_text
|
403
|
-
end
|
404
|
-
end
|
405
|
-
|
406
|
-
# Find hash literals which are returned from mutation resolves,
|
407
|
-
# and convert their keys to underscores. This catches a lot of cases but misses
|
408
|
-
# hashes which are initialized anywhere except in the return expression.
|
409
|
-
class UnderscorizeMutationHashTransform < Transform
|
410
|
-
def apply(input_text)
|
411
|
-
if input_text =~ /def resolve\(\*\*/
|
412
|
-
processor = apply_processor(input_text, ReturnedHashLiteralProcessor.new)
|
413
|
-
# Use reverse_each to avoid messing up positions
|
414
|
-
processor.keys_to_upgrade.reverse_each do |key_data|
|
415
|
-
underscored_key = underscorize(key_data[:key].to_s)
|
416
|
-
if key_data[:operator] == ":"
|
417
|
-
input_text[key_data[:start]...key_data[:end]] = underscored_key
|
418
|
-
else
|
419
|
-
input_text[key_data[:start]...key_data[:end]] = ":#{underscored_key}"
|
420
|
-
end
|
421
|
-
end
|
422
|
-
end
|
423
|
-
input_text
|
424
|
-
end
|
425
|
-
|
426
|
-
class ReturnedHashLiteralProcessor < Parser::AST::Processor
|
427
|
-
attr_reader :keys_to_upgrade
|
428
|
-
def initialize
|
429
|
-
@keys_to_upgrade = []
|
430
|
-
end
|
431
|
-
|
432
|
-
def on_def(node)
|
433
|
-
method_name, _args, body = *node
|
434
|
-
if method_name == :resolve
|
435
|
-
possible_returned_hashes = find_returned_hashes(body, returning: false)
|
436
|
-
possible_returned_hashes.each do |hash_node|
|
437
|
-
pairs = *hash_node
|
438
|
-
pairs.each do |pair_node|
|
439
|
-
if pair_node.type == :pair # Skip over :kwsplat
|
440
|
-
pair_k, _pair_v = *pair_node
|
441
|
-
if pair_k.type == :sym && pair_k.children[0].to_s =~ /[a-z][A-Z]/ # Does it have any camelcase boundaries?
|
442
|
-
source_exp = pair_k.loc.expression
|
443
|
-
@keys_to_upgrade << {
|
444
|
-
start: source_exp.begin.begin_pos,
|
445
|
-
end: source_exp.end.end_pos,
|
446
|
-
key: pair_k.children[0],
|
447
|
-
operator: pair_node.loc.operator.source,
|
448
|
-
}
|
449
|
-
end
|
450
|
-
end
|
451
|
-
end
|
452
|
-
end
|
453
|
-
end
|
454
|
-
|
455
|
-
end
|
456
|
-
|
457
|
-
private
|
458
|
-
|
459
|
-
# Look for hash nodes, starting from `node`.
|
460
|
-
# Return hash nodes that are valid candiates for returning from this method.
|
461
|
-
def find_returned_hashes(node, returning:)
|
462
|
-
if node.is_a?(Array)
|
463
|
-
*possible_returns, last_expression = *node
|
464
|
-
return possible_returns.map { |c| find_returned_hashes(c, returning: false) }.flatten +
|
465
|
-
# Check the last expression of a method body
|
466
|
-
find_returned_hashes(last_expression, returning: returning)
|
467
|
-
end
|
468
|
-
|
469
|
-
case node.type
|
470
|
-
when :hash
|
471
|
-
if returning
|
472
|
-
[node]
|
473
|
-
else
|
474
|
-
# This is some random hash literal
|
475
|
-
[]
|
476
|
-
end
|
477
|
-
when :begin
|
478
|
-
# Check the last expression of a method body
|
479
|
-
find_returned_hashes(node.children, returning: true)
|
480
|
-
when :resbody
|
481
|
-
_condition, _assign, body = *node
|
482
|
-
find_returned_hashes(body, returning: returning)
|
483
|
-
when :kwbegin
|
484
|
-
find_returned_hashes(node.children, returning: returning)
|
485
|
-
when :rescue
|
486
|
-
try_body, rescue_body, _ensure_body = *node
|
487
|
-
find_returned_hashes(try_body, returning: returning) + find_returned_hashes(rescue_body, returning: returning)
|
488
|
-
when :block
|
489
|
-
# Check methods with blocks for possible returns
|
490
|
-
method_call, _args, *body = *node
|
491
|
-
if method_call.type == :send
|
492
|
-
find_returned_hashes(body, returning: returning)
|
493
|
-
end
|
494
|
-
when :if
|
495
|
-
# Check each branch of a conditional
|
496
|
-
_condition, *branches = *node
|
497
|
-
branches.compact.map { |b| find_returned_hashes(b, returning: returning) }.flatten
|
498
|
-
when :return
|
499
|
-
find_returned_hashes(node.children.first, returning: true)
|
500
|
-
else
|
501
|
-
[]
|
502
|
-
end
|
503
|
-
rescue
|
504
|
-
p "--- UnderscorizeMutationHashTransform crashed on node: ---"
|
505
|
-
p node
|
506
|
-
raise
|
507
|
-
end
|
508
|
-
|
509
|
-
end
|
510
|
-
end
|
511
|
-
|
512
|
-
class ResolveProcToMethodTransform < Transform
|
513
|
-
def apply(input_text)
|
514
|
-
if input_text =~ /resolve\(? ?->/
|
515
|
-
# - Find the proc literal
|
516
|
-
# - Get the three argument names (obj, arg, ctx)
|
517
|
-
# - Get the proc body
|
518
|
-
# - Find and replace:
|
519
|
-
# - The ctx argument becomes `context`
|
520
|
-
# - The obj argument becomes `object`
|
521
|
-
# - Args is trickier:
|
522
|
-
# - If it's not used, remove it
|
523
|
-
# - If it's used, abandon ship and make it `**args`
|
524
|
-
# - Convert string args access to symbol access, since it's a Ruby **splat
|
525
|
-
# - Convert camelized arg names to underscored arg names
|
526
|
-
# - (It would be nice to correctly become Ruby kwargs, but that might be too hard)
|
527
|
-
# - Add a `# TODO` comment to the method source?
|
528
|
-
# - Rebuild the method:
|
529
|
-
# - use the field name as the method name
|
530
|
-
# - handle args as described above
|
531
|
-
# - put the modified proc body as the method body
|
532
|
-
|
533
|
-
input_text.match(/(?<field_type>input_field|field|connection|argument) :(?<name>[a-zA-Z_0-9_]*)/)
|
534
|
-
field_name = $~[:name]
|
535
|
-
processor = apply_processor(input_text, ResolveProcProcessor.new)
|
536
|
-
|
537
|
-
processor.resolve_proc_sections.reverse.each do |resolve_proc_section|
|
538
|
-
proc_body = input_text[resolve_proc_section.proc_start..resolve_proc_section.proc_end]
|
539
|
-
obj_arg_name, args_arg_name, ctx_arg_name = resolve_proc_section.proc_arg_names
|
540
|
-
# This is not good, it will hit false positives
|
541
|
-
# Should use AST to make this substitution
|
542
|
-
if obj_arg_name != "_"
|
543
|
-
proc_body.gsub!(/([^\w:.]|^)#{obj_arg_name}([^\w:]|$)/, '\1object\2')
|
544
|
-
end
|
545
|
-
if ctx_arg_name != "_"
|
546
|
-
proc_body.gsub!(/([^\w:.]|^)#{ctx_arg_name}([^\w:]|$)/, '\1context\2')
|
547
|
-
end
|
548
|
-
|
549
|
-
method_def_indent = " " * (resolve_proc_section.resolve_indent - 2)
|
550
|
-
# Turn the proc body into a method body
|
551
|
-
method_body = reindent_lines(proc_body, from_indent: resolve_proc_section.resolve_indent + 2, to_indent: resolve_proc_section.resolve_indent)
|
552
|
-
# Add `def... end`
|
553
|
-
method_def = if input_text.include?("argument ")
|
554
|
-
# This field has arguments
|
555
|
-
"def #{field_name}(**#{args_arg_name})"
|
556
|
-
else
|
557
|
-
# No field arguments, so, no method arguments
|
558
|
-
"def #{field_name}"
|
559
|
-
end
|
560
|
-
# Wrap the body in def ... end
|
561
|
-
method_body = "\n#{method_def_indent}#{method_def}\n#{method_body}\n#{method_def_indent}end\n"
|
562
|
-
# Update Argument access to be underscore and symbols
|
563
|
-
# Update `args[...]` and `args.key?`
|
564
|
-
method_body = method_body.gsub(/#{args_arg_name}(?<method_begin>\.key\?\(?|\[)["':](?<arg_name>[a-zA-Z0-9_]+)["']?(?<method_end>\]|\))?/) do
|
565
|
-
method_begin = $~[:method_begin]
|
566
|
-
arg_name = underscorize($~[:arg_name])
|
567
|
-
method_end = $~[:method_end]
|
568
|
-
"#{args_arg_name}#{method_begin}:#{arg_name}#{method_end}"
|
569
|
-
end
|
570
|
-
|
571
|
-
# Replace the resolve proc with the method
|
572
|
-
input_text[resolve_proc_section.resolve_start..resolve_proc_section.resolve_end] = ""
|
573
|
-
# The replacement above might have left some preceeding whitespace,
|
574
|
-
# so remove it by deleting all whitespace chars before `resolve`:
|
575
|
-
preceeding_whitespace = resolve_proc_section.resolve_start - 1
|
576
|
-
while input_text[preceeding_whitespace] == " " && preceeding_whitespace > 0
|
577
|
-
input_text[preceeding_whitespace] = ""
|
578
|
-
preceeding_whitespace -= 1
|
579
|
-
end
|
580
|
-
input_text += method_body
|
581
|
-
input_text
|
582
|
-
end
|
583
|
-
end
|
584
|
-
|
585
|
-
input_text
|
586
|
-
end
|
587
|
-
|
588
|
-
class ResolveProcProcessor < Parser::AST::Processor
|
589
|
-
attr_reader :resolve_proc_sections
|
590
|
-
def initialize
|
591
|
-
@resolve_proc_sections = []
|
592
|
-
end
|
593
|
-
|
594
|
-
class ResolveProcSection
|
595
|
-
attr_accessor :proc_start, :proc_end, :proc_arg_names, :resolve_start, :resolve_end, :resolve_indent
|
596
|
-
def initialize
|
597
|
-
@proc_arg_names = nil
|
598
|
-
@resolve_start = nil
|
599
|
-
@resolve_end = nil
|
600
|
-
@resolve_indent = nil
|
601
|
-
@proc_start = nil
|
602
|
-
@proc_end = nil
|
603
|
-
end
|
604
|
-
end
|
605
|
-
|
606
|
-
def on_send(node)
|
607
|
-
receiver, method_name, _args = *node
|
608
|
-
if method_name == :resolve && receiver.nil?
|
609
|
-
resolve_proc_section = ResolveProcSection.new
|
610
|
-
source_exp = node.loc.expression
|
611
|
-
resolve_proc_section.resolve_start = source_exp.begin.begin_pos
|
612
|
-
resolve_proc_section.resolve_end = source_exp.end.end_pos
|
613
|
-
resolve_proc_section.resolve_indent = source_exp.column
|
614
|
-
|
615
|
-
@resolve_proc_sections << resolve_proc_section
|
616
|
-
end
|
617
|
-
super(node)
|
618
|
-
end
|
619
|
-
|
620
|
-
def on_block(node)
|
621
|
-
send_node, args_node, body_node = node.children
|
622
|
-
_receiver, method_name, _send_args_node = *send_node
|
623
|
-
# Assume that the first three-argument proc we enter is the resolve
|
624
|
-
if (
|
625
|
-
method_name == :lambda && args_node.children.size == 3 &&
|
626
|
-
!@resolve_proc_sections.empty? && @resolve_proc_sections[-1].proc_arg_names.nil?
|
627
|
-
)
|
628
|
-
resolve_proc_section = @resolve_proc_sections[-1]
|
629
|
-
source_exp = body_node.loc.expression
|
630
|
-
resolve_proc_section.proc_arg_names = args_node.children.map { |arg_node| arg_node.children[0].to_s }
|
631
|
-
resolve_proc_section.proc_start = source_exp.begin.begin_pos
|
632
|
-
resolve_proc_section.proc_end = source_exp.end.end_pos
|
633
|
-
end
|
634
|
-
super(node)
|
635
|
-
end
|
636
|
-
end
|
637
|
-
end
|
638
|
-
|
639
|
-
# Transform `interfaces [A, B, C]` to `implements A\nimplements B\nimplements C\n`
|
640
|
-
class InterfacesToImplementsTransform < Transform
|
641
|
-
PATTERN = /(?<indent>\s*)(?:interfaces) \[\s*(?<interfaces>(?:[a-zA-Z_0-9:\.,\s]+))\]/m
|
642
|
-
def apply(input_text)
|
643
|
-
input_text.gsub(PATTERN) do
|
644
|
-
indent = $~[:indent]
|
645
|
-
interfaces = $~[:interfaces].split(',').map(&:strip).reject(&:empty?)
|
646
|
-
# Preserve leading newlines before the `interfaces ...`
|
647
|
-
# call, but don't re-insert them between `implements` calls.
|
648
|
-
extra_leading_newlines = "\n" * (indent[/^\n*/].length - 1)
|
649
|
-
indent = indent.sub(/^\n*/m, "")
|
650
|
-
interfaces_calls = interfaces
|
651
|
-
.map { |interface| "\n#{indent}implements #{interface}" }
|
652
|
-
.join
|
653
|
-
extra_leading_newlines + interfaces_calls
|
654
|
-
end
|
655
|
-
end
|
656
|
-
end
|
657
|
-
|
658
|
-
# Transform `possible_types [A, B, C]` to `possible_types(A, B, C)`
|
659
|
-
class PossibleTypesTransform < Transform
|
660
|
-
PATTERN = /(?<indent>\s*)(?:possible_types) \[\s*(?<possible_types>(?:[a-zA-Z_0-9:\.,\s]+))\]/m
|
661
|
-
def apply(input_text)
|
662
|
-
input_text.gsub(PATTERN) do
|
663
|
-
indent = $~[:indent]
|
664
|
-
possible_types = $~[:possible_types].split(',').map(&:strip).reject(&:empty?)
|
665
|
-
extra_leading_newlines = indent[/^\n*/]
|
666
|
-
method_indent = indent.sub(/^\n*/m, "")
|
667
|
-
type_indent = " " + method_indent
|
668
|
-
possible_types_call = "#{method_indent}possible_types(\n#{possible_types.map { |t| "#{type_indent}#{t},"}.join("\n")}\n#{method_indent})"
|
669
|
-
extra_leading_newlines + trim_lines(possible_types_call)
|
670
|
-
end
|
671
|
-
end
|
672
|
-
end
|
673
|
-
|
674
|
-
class UpdateMethodSignatureTransform < Transform
|
675
|
-
def apply(input_text)
|
676
|
-
input_text.scan(/(?:input_field|field|return_field|connection|argument) .*$/).each do |field|
|
677
|
-
matches = /(?<field_type>input_field|return_field|field|connection|argument) :(?<name>[a-zA-Z_0-9_]*)?(:?, +(?<return_type>([A-Za-z\[\]\.\!_0-9\(\)]|::|-> ?\{ ?| ?\})+))?(?<remainder>( |,|$).*)/.match(field)
|
678
|
-
if matches
|
679
|
-
name = matches[:name]
|
680
|
-
return_type = matches[:return_type]
|
681
|
-
remainder = matches[:remainder]
|
682
|
-
field_type = matches[:field_type]
|
683
|
-
with_block = remainder.gsub!(/\ do$/, '')
|
684
|
-
|
685
|
-
remainder.gsub! /,$/, ''
|
686
|
-
remainder.gsub! /^,/, ''
|
687
|
-
remainder.chomp!
|
688
|
-
|
689
|
-
if return_type
|
690
|
-
non_nullable = return_type.sub! /(^|[^\[])!/, '\1'
|
691
|
-
non_nullable ||= return_type.sub! /([^\[])\.to_non_null_type([^\]]|$)/, '\1'
|
692
|
-
nullable = !non_nullable
|
693
|
-
return_type = normalize_type_expression(return_type)
|
694
|
-
else
|
695
|
-
non_nullable = nil
|
696
|
-
nullable = nil
|
697
|
-
end
|
698
|
-
|
699
|
-
input_text.sub!(field) do
|
700
|
-
is_argument = ['argument', 'input_field'].include?(field_type)
|
701
|
-
f = "#{is_argument ? 'argument' : 'field'} :#{name}"
|
702
|
-
|
703
|
-
if return_type
|
704
|
-
f += ", #{return_type}"
|
705
|
-
end
|
706
|
-
|
707
|
-
unless remainder.empty?
|
708
|
-
f += ',' + remainder
|
709
|
-
end
|
710
|
-
|
711
|
-
if is_argument
|
712
|
-
if nullable
|
713
|
-
f += ', required: false'
|
714
|
-
elsif non_nullable
|
715
|
-
f += ', required: true'
|
716
|
-
end
|
717
|
-
else
|
718
|
-
if nullable
|
719
|
-
f += ', null: true'
|
720
|
-
elsif non_nullable
|
721
|
-
f += ', null: false'
|
722
|
-
end
|
723
|
-
end
|
724
|
-
|
725
|
-
if field_type == 'connection'
|
726
|
-
f += ', connection: true'
|
727
|
-
end
|
728
|
-
|
729
|
-
if with_block
|
730
|
-
f += ' do'
|
731
|
-
end
|
732
|
-
|
733
|
-
f
|
734
|
-
end
|
735
|
-
end
|
736
|
-
end
|
737
|
-
|
738
|
-
input_text
|
739
|
-
end
|
740
|
-
end
|
741
|
-
|
742
|
-
class RemoveEmptyBlocksTransform < Transform
|
743
|
-
def apply(input_text)
|
744
|
-
input_text.gsub(/\s*do\s*end/m, "")
|
745
|
-
end
|
746
|
-
end
|
747
|
-
|
748
|
-
# Remove redundant newlines, which may have trailing spaces
|
749
|
-
# Remove double newline after `do`
|
750
|
-
# Remove double newline before `end`
|
751
|
-
# Remove lines with whitespace only
|
752
|
-
class RemoveExcessWhitespaceTransform < Transform
|
753
|
-
def apply(input_text)
|
754
|
-
input_text
|
755
|
-
.gsub(/\n{3,}/m, "\n\n")
|
756
|
-
.gsub(/do\n{2,}/m, "do\n")
|
757
|
-
.gsub(/\n{2,}(\s*)end/m, "\n\\1end")
|
758
|
-
.gsub(/\n +\n/m, "\n\n")
|
759
|
-
end
|
760
|
-
end
|
761
|
-
|
762
|
-
# Skip this file if you see any `field`
|
763
|
-
# helpers with `null: true` or `null: false` keywords
|
764
|
-
# or `argument` helpers with `required:` keywords,
|
765
|
-
# because it's already been transformed
|
766
|
-
class SkipOnNullKeyword
|
767
|
-
def skip?(input_text)
|
768
|
-
input_text =~ /field.*null: (true|false)/ || input_text =~ /argument.*required: (true|false)/
|
769
|
-
end
|
770
|
-
end
|
771
|
-
|
772
|
-
class Member
|
773
|
-
def initialize(member, skip: SkipOnNullKeyword, type_transforms: DEFAULT_TYPE_TRANSFORMS, field_transforms: DEFAULT_FIELD_TRANSFORMS, clean_up_transforms: DEFAULT_CLEAN_UP_TRANSFORMS)
|
774
|
-
GraphQL::Deprecation.warn "#{self.class} will be removed from GraphQL-Ruby 2.0 (but there's no point in using it after you've transformed your code, anyways)"
|
775
|
-
@member = member
|
776
|
-
@skip = skip
|
777
|
-
@type_transforms = type_transforms
|
778
|
-
@field_transforms = field_transforms
|
779
|
-
@clean_up_transforms = clean_up_transforms
|
780
|
-
end
|
781
|
-
|
782
|
-
DEFAULT_TYPE_TRANSFORMS = [
|
783
|
-
TypeDefineToClassTransform,
|
784
|
-
MutationResolveProcToMethodTransform, # Do this before switching to class, so we can detect that its a mutation
|
785
|
-
UnderscorizeMutationHashTransform,
|
786
|
-
MutationDefineToClassTransform,
|
787
|
-
NameTransform,
|
788
|
-
InterfacesToImplementsTransform,
|
789
|
-
PossibleTypesTransform,
|
790
|
-
ProcToClassMethodTransform.new("coerce_input"),
|
791
|
-
ProcToClassMethodTransform.new("coerce_result"),
|
792
|
-
ProcToClassMethodTransform.new("resolve_type"),
|
793
|
-
]
|
794
|
-
|
795
|
-
DEFAULT_FIELD_TRANSFORMS = [
|
796
|
-
RemoveNewlinesTransform,
|
797
|
-
RemoveMethodParensTransform,
|
798
|
-
PositionalTypeArgTransform,
|
799
|
-
ConfigurationToKwargTransform.new(kwarg: "property"),
|
800
|
-
ConfigurationToKwargTransform.new(kwarg: "description"),
|
801
|
-
ConfigurationToKwargTransform.new(kwarg: "deprecation_reason"),
|
802
|
-
ConfigurationToKwargTransform.new(kwarg: "hash_key"),
|
803
|
-
PropertyToMethodTransform,
|
804
|
-
UnderscoreizeFieldNameTransform,
|
805
|
-
ResolveProcToMethodTransform,
|
806
|
-
UpdateMethodSignatureTransform,
|
807
|
-
RemoveRedundantKwargTransform.new(kwarg: "hash_key"),
|
808
|
-
RemoveRedundantKwargTransform.new(kwarg: "method"),
|
809
|
-
]
|
810
|
-
|
811
|
-
DEFAULT_CLEAN_UP_TRANSFORMS = [
|
812
|
-
RemoveExcessWhitespaceTransform,
|
813
|
-
RemoveEmptyBlocksTransform,
|
814
|
-
]
|
815
|
-
|
816
|
-
def upgrade
|
817
|
-
type_source = @member.dup
|
818
|
-
should_skip = @skip.new.skip?(type_source)
|
819
|
-
# return the unmodified code
|
820
|
-
if should_skip
|
821
|
-
return type_source
|
822
|
-
end
|
823
|
-
# Transforms on type defn code:
|
824
|
-
type_source = apply_transforms(type_source, @type_transforms)
|
825
|
-
# Transforms on each field:
|
826
|
-
field_sources = find_fields(type_source)
|
827
|
-
field_sources.each do |field_source|
|
828
|
-
transformed_field_source = apply_transforms(field_source.dup, @field_transforms)
|
829
|
-
# Replace the original source code with the transformed source code:
|
830
|
-
type_source = type_source.gsub(field_source, transformed_field_source)
|
831
|
-
end
|
832
|
-
# Clean-up:
|
833
|
-
type_source = apply_transforms(type_source, @clean_up_transforms)
|
834
|
-
# Return the transformed source:
|
835
|
-
type_source
|
836
|
-
end
|
837
|
-
|
838
|
-
def upgradeable?
|
839
|
-
return false if @member.include? '< GraphQL::Schema::'
|
840
|
-
return false if @member =~ /< Types::Base#{GRAPHQL_TYPES}/
|
841
|
-
|
842
|
-
true
|
843
|
-
end
|
844
|
-
|
845
|
-
private
|
846
|
-
|
847
|
-
def apply_transforms(source_code, transforms, idx: 0)
|
848
|
-
next_transform = transforms[idx]
|
849
|
-
case next_transform
|
850
|
-
when nil
|
851
|
-
# We got to the end of the list
|
852
|
-
source_code
|
853
|
-
when Class
|
854
|
-
# Apply a class
|
855
|
-
next_source_code = next_transform.new.apply(source_code)
|
856
|
-
apply_transforms(next_source_code, transforms, idx: idx + 1)
|
857
|
-
else
|
858
|
-
# Apply an already-initialized object which responds to `apply`
|
859
|
-
next_source_code = next_transform.apply(source_code)
|
860
|
-
apply_transforms(next_source_code, transforms, idx: idx + 1)
|
861
|
-
end
|
862
|
-
end
|
863
|
-
|
864
|
-
# Parse the type, find calls to `field` and `connection`
|
865
|
-
# Return strings containing those calls
|
866
|
-
def find_fields(type_source)
|
867
|
-
type_ast = Parser::CurrentRuby.parse(type_source)
|
868
|
-
finder = FieldFinder.new
|
869
|
-
finder.process(type_ast)
|
870
|
-
field_sources = []
|
871
|
-
# For each of the locations we found, extract the text for that definition.
|
872
|
-
# The text will be transformed independently,
|
873
|
-
# then the transformed text will replace the original text.
|
874
|
-
FieldFinder::DEFINITION_METHODS.each do |def_method|
|
875
|
-
finder.locations[def_method].each do |name, (starting_idx, ending_idx)|
|
876
|
-
field_source = type_source[starting_idx..ending_idx]
|
877
|
-
field_sources << field_source
|
878
|
-
end
|
879
|
-
end
|
880
|
-
# Here's a crazy thing: the transformation is pure,
|
881
|
-
# so definitions like `argument :id, types.ID` can be transformed once
|
882
|
-
# then replaced everywhere. So:
|
883
|
-
# - make a unique array here
|
884
|
-
# - use `gsub` after performing the transformation.
|
885
|
-
field_sources.uniq!
|
886
|
-
field_sources
|
887
|
-
rescue Parser::SyntaxError
|
888
|
-
puts "Error Source:"
|
889
|
-
puts type_source
|
890
|
-
raise
|
891
|
-
end
|
892
|
-
|
893
|
-
class FieldFinder < Parser::AST::Processor
|
894
|
-
# These methods are definition DSLs which may accept a block,
|
895
|
-
# each of these definitions is passed for transformation in its own right.
|
896
|
-
# `field` and `connection` take priority. In fact, they upgrade their
|
897
|
-
# own arguments, so those upgrades turn out to be no-ops.
|
898
|
-
DEFINITION_METHODS = [:field, :connection, :input_field, :return_field, :argument]
|
899
|
-
attr_reader :locations
|
900
|
-
|
901
|
-
def initialize
|
902
|
-
# Pairs of `{ { method_name => { name => [start, end] } }`,
|
903
|
-
# since fields/arguments are unique by name, within their category
|
904
|
-
@locations = Hash.new { |h,k| h[k] = {} }
|
905
|
-
end
|
906
|
-
|
907
|
-
# @param send_node [node] The node which might be a `field` call, etc
|
908
|
-
# @param source_node [node] The node whose source defines the bounds of the definition (eg, the surrounding block)
|
909
|
-
def add_location(send_node:,source_node:)
|
910
|
-
receiver_node, method_name, *arg_nodes = *send_node
|
911
|
-
# Implicit self and one of the recognized methods
|
912
|
-
if receiver_node.nil? && DEFINITION_METHODS.include?(method_name)
|
913
|
-
name = arg_nodes[0]
|
914
|
-
# This field may have already been added because
|
915
|
-
# we find `(block ...)` nodes _before_ we find `(send ...)` nodes.
|
916
|
-
if @locations[method_name][name].nil?
|
917
|
-
starting_idx = source_node.loc.expression.begin.begin_pos
|
918
|
-
ending_idx = source_node.loc.expression.end.end_pos
|
919
|
-
@locations[method_name][name] = [starting_idx, ending_idx]
|
920
|
-
end
|
921
|
-
end
|
922
|
-
end
|
923
|
-
|
924
|
-
def on_block(node)
|
925
|
-
send_node, _args_node, _body_node = *node
|
926
|
-
add_location(send_node: send_node, source_node: node)
|
927
|
-
super(node)
|
928
|
-
end
|
929
|
-
|
930
|
-
def on_send(node)
|
931
|
-
add_location(send_node: node, source_node: node)
|
932
|
-
super(node)
|
933
|
-
end
|
934
|
-
end
|
935
|
-
end
|
936
|
-
end
|
937
|
-
end
|