graphql 2.0.32 → 2.5.22
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/detailed_trace_generator.rb +77 -0
- data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
- data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
- data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +49 -0
- data/lib/generators/graphql/orm_mutations_base.rb +1 -1
- 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/create_graphql_detailed_traces.erb +10 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +2 -0
- data/lib/generators/graphql/templates/node_type.erb +2 -0
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +5 -0
- data/lib/generators/graphql/type_generator.rb +1 -1
- data/lib/graphql/analysis/analyzer.rb +90 -0
- data/lib/graphql/analysis/field_usage.rb +82 -0
- data/lib/graphql/analysis/max_query_complexity.rb +20 -0
- data/lib/graphql/analysis/max_query_depth.rb +20 -0
- data/lib/graphql/analysis/query_complexity.rb +263 -0
- data/lib/graphql/analysis/query_depth.rb +58 -0
- data/lib/graphql/analysis/visitor.rb +280 -0
- data/lib/graphql/analysis.rb +95 -1
- data/lib/graphql/autoload.rb +38 -0
- data/lib/graphql/backtrace/table.rb +118 -55
- data/lib/graphql/backtrace.rb +1 -19
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/current.rb +57 -0
- data/lib/graphql/dashboard/application_controller.rb +41 -0
- data/lib/graphql/dashboard/detailed_traces.rb +47 -0
- data/lib/graphql/dashboard/installable.rb +22 -0
- data/lib/graphql/dashboard/landings_controller.rb +9 -0
- data/lib/graphql/dashboard/limiters.rb +93 -0
- data/lib/graphql/dashboard/operation_store.rb +199 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
- data/lib/graphql/dashboard/statics/charts.min.css +1 -0
- data/lib/graphql/dashboard/statics/dashboard.css +30 -0
- data/lib/graphql/dashboard/statics/dashboard.js +143 -0
- data/lib/graphql/dashboard/statics/header-icon.png +0 -0
- data/lib/graphql/dashboard/statics/icon.png +0 -0
- data/lib/graphql/dashboard/statics_controller.rb +31 -0
- data/lib/graphql/dashboard/subscriptions.rb +97 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +24 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
- data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
- data/lib/graphql/dashboard.rb +96 -0
- data/lib/graphql/dataloader/active_record_association_source.rb +84 -0
- data/lib/graphql/dataloader/active_record_source.rb +47 -0
- data/lib/graphql/dataloader/async_dataloader.rb +112 -0
- data/lib/graphql/dataloader/null_dataloader.rb +55 -10
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/dataloader/source.rb +35 -12
- data/lib/graphql/dataloader.rb +224 -149
- data/lib/graphql/date_encoding_error.rb +1 -1
- data/lib/graphql/dig.rb +2 -1
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
- data/lib/graphql/execution/interpreter/resolve.rb +23 -25
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +228 -0
- data/lib/graphql/execution/interpreter/runtime.rb +363 -434
- data/lib/graphql/execution/interpreter.rb +91 -164
- data/lib/graphql/execution/lookahead.rb +105 -31
- data/lib/graphql/execution/multiplex.rb +7 -6
- data/lib/graphql/execution/next/field_resolve_step.rb +711 -0
- data/lib/graphql/execution/next/load_argument_step.rb +60 -0
- data/lib/graphql/execution/next/prepare_object_step.rb +129 -0
- data/lib/graphql/execution/next/runner.rb +389 -0
- data/lib/graphql/execution/next/selections_step.rb +37 -0
- data/lib/graphql/execution/next.rb +70 -0
- data/lib/graphql/execution.rb +1 -0
- data/lib/graphql/execution_error.rb +13 -10
- data/lib/graphql/introspection/directive_location_enum.rb +1 -1
- data/lib/graphql/introspection/directive_type.rb +7 -3
- data/lib/graphql/introspection/dynamic_fields.rb +5 -1
- data/lib/graphql/introspection/entry_points.rb +20 -6
- data/lib/graphql/introspection/enum_value_type.rb +5 -5
- data/lib/graphql/introspection/field_type.rb +13 -5
- data/lib/graphql/introspection/input_value_type.rb +21 -13
- data/lib/graphql/introspection/schema_type.rb +8 -11
- data/lib/graphql/introspection/type_type.rb +64 -28
- data/lib/graphql/invalid_name_error.rb +1 -1
- data/lib/graphql/invalid_null_error.rb +26 -17
- data/lib/graphql/language/block_string.rb +34 -18
- 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 +90 -61
- data/lib/graphql/language/lexer.rb +319 -193
- data/lib/graphql/language/nodes.rb +136 -77
- data/lib/graphql/language/parser.rb +807 -1985
- data/lib/graphql/language/printer.rb +324 -151
- data/lib/graphql/language/sanitized_printer.rb +21 -23
- data/lib/graphql/language/static_visitor.rb +171 -0
- data/lib/graphql/language/visitor.rb +23 -83
- data/lib/graphql/language.rb +71 -1
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/pagination/array_connection.rb +6 -6
- data/lib/graphql/pagination/connection.rb +30 -1
- data/lib/graphql/pagination/connections.rb +32 -0
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +82 -144
- data/lib/graphql/query/null_context.rb +15 -18
- data/lib/graphql/query/partial.rb +179 -0
- data/lib/graphql/query/validation_pipeline.rb +4 -4
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query/variables.rb +3 -3
- data/lib/graphql/query.rb +126 -81
- data/lib/graphql/railtie.rb +16 -6
- data/lib/graphql/rake_task.rb +3 -12
- data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
- 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 +2 -0
- data/lib/graphql/schema/addition.rb +26 -13
- data/lib/graphql/schema/always_visible.rb +7 -2
- data/lib/graphql/schema/argument.rb +75 -9
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +123 -60
- data/lib/graphql/schema/directive/flagged.rb +4 -2
- data/lib/graphql/schema/directive/one_of.rb +12 -0
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive.rb +54 -2
- data/lib/graphql/schema/enum.rb +110 -27
- data/lib/graphql/schema/enum_value.rb +10 -2
- data/lib/graphql/schema/field/connection_extension.rb +15 -49
- data/lib/graphql/schema/field/scope_extension.rb +23 -7
- data/lib/graphql/schema/field.rb +245 -118
- data/lib/graphql/schema/field_extension.rb +34 -1
- data/lib/graphql/schema/has_single_input_argument.rb +160 -0
- data/lib/graphql/schema/input_object.rb +116 -60
- data/lib/graphql/schema/interface.rb +34 -16
- data/lib/graphql/schema/introspection_system.rb +8 -17
- data/lib/graphql/schema/late_bound_type.rb +4 -0
- data/lib/graphql/schema/list.rb +3 -3
- data/lib/graphql/schema/loader.rb +3 -4
- data/lib/graphql/schema/member/base_dsl_methods.rb +18 -2
- data/lib/graphql/schema/member/has_arguments.rb +132 -100
- data/lib/graphql/schema/member/has_authorization.rb +35 -0
- data/lib/graphql/schema/member/has_dataloader.rb +99 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
- data/lib/graphql/schema/member/has_directives.rb +4 -4
- data/lib/graphql/schema/member/has_fields.rb +115 -15
- data/lib/graphql/schema/member/has_interfaces.rb +26 -12
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/member/has_validators.rb +1 -1
- data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +17 -4
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- data/lib/graphql/schema/member.rb +6 -0
- data/lib/graphql/schema/mutation.rb +7 -0
- data/lib/graphql/schema/object.rb +34 -8
- data/lib/graphql/schema/printer.rb +9 -7
- data/lib/graphql/schema/ractor_shareable.rb +79 -0
- data/lib/graphql/schema/relay_classic_mutation.rb +6 -129
- data/lib/graphql/schema/resolver.rb +90 -32
- data/lib/graphql/schema/scalar.rb +4 -9
- data/lib/graphql/schema/subscription.rb +63 -10
- data/lib/graphql/schema/timeout.rb +19 -2
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/union.rb +2 -2
- 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/required_validator.rb +92 -11
- data/lib/graphql/schema/validator.rb +3 -1
- data/lib/graphql/schema/visibility/migration.rb +188 -0
- data/lib/graphql/schema/visibility/profile.rb +445 -0
- data/lib/graphql/schema/visibility/visit.rb +190 -0
- data/lib/graphql/schema/visibility.rb +311 -0
- data/lib/graphql/schema/warden.rb +275 -103
- data/lib/graphql/schema.rb +950 -210
- data/lib/graphql/static_validation/all_rules.rb +3 -3
- data/lib/graphql/static_validation/base_visitor.rb +7 -6
- data/lib/graphql/static_validation/literal_validator.rb +6 -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 +3 -2
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
- 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 +47 -13
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +88 -25
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
- 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_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/not_single_subscription_error.rb +25 -0
- data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +5 -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_and_single_subscription_selection.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +7 -3
- 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 +2 -2
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
- data/lib/graphql/static_validation/validation_context.rb +21 -5
- data/lib/graphql/static_validation/validator.rb +9 -1
- data/lib/graphql/static_validation.rb +0 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +8 -5
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
- data/lib/graphql/subscriptions/event.rb +21 -4
- data/lib/graphql/subscriptions/serialize.rb +3 -1
- data/lib/graphql/subscriptions.rb +21 -17
- data/lib/graphql/testing/helpers.rb +161 -0
- data/lib/graphql/testing/mock_action_cable.rb +111 -0
- data/lib/graphql/testing.rb +3 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
- data/lib/graphql/tracing/appoptics_trace.rb +7 -3
- data/lib/graphql/tracing/appoptics_tracing.rb +9 -2
- data/lib/graphql/tracing/appsignal_trace.rb +32 -59
- data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
- data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
- data/lib/graphql/tracing/data_dog_trace.rb +46 -162
- data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
- data/lib/graphql/tracing/detailed_trace/active_record_backend.rb +74 -0
- data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
- data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
- data/lib/graphql/tracing/detailed_trace.rb +156 -0
- data/lib/graphql/tracing/legacy_hooks_trace.rb +75 -0
- data/lib/graphql/tracing/legacy_trace.rb +4 -61
- data/lib/graphql/tracing/monitor_trace.rb +283 -0
- data/lib/graphql/tracing/new_relic_trace.rb +47 -54
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
- data/lib/graphql/tracing/notifications_trace.rb +183 -37
- data/lib/graphql/tracing/notifications_tracing.rb +2 -0
- data/lib/graphql/tracing/null_trace.rb +9 -0
- data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
- data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
- data/lib/graphql/tracing/perfetto_trace.rb +864 -0
- data/lib/graphql/tracing/platform_tracing.rb +3 -1
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +5 -1
- data/lib/graphql/tracing/prometheus_trace.rb +73 -73
- data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
- data/lib/graphql/tracing/scout_trace.rb +32 -58
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +82 -0
- data/lib/graphql/tracing/statsd_trace.rb +33 -45
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +112 -1
- data/lib/graphql/tracing.rb +31 -28
- data/lib/graphql/type_kinds.rb +2 -1
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +44 -2
- data/lib/graphql/types/relay/edge_behaviors.rb +18 -0
- data/lib/graphql/types/relay/has_node_field.rb +13 -8
- data/lib/graphql/types/relay/has_nodes_field.rb +13 -8
- data/lib/graphql/types/relay/node_behaviors.rb +13 -2
- data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
- data/lib/graphql/types.rb +18 -10
- data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
- data/lib/graphql/unauthorized_error.rb +5 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +71 -54
- data/readme.md +12 -2
- metadata +233 -37
- data/lib/graphql/analysis/ast/analyzer.rb +0 -84
- data/lib/graphql/analysis/ast/field_usage.rb +0 -57
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
- data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
- data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
- data/lib/graphql/analysis/ast/query_depth.rb +0 -55
- data/lib/graphql/analysis/ast/visitor.rb +0 -276
- data/lib/graphql/analysis/ast.rb +0 -81
- data/lib/graphql/backtrace/inspect_result.rb +0 -50
- data/lib/graphql/backtrace/trace.rb +0 -96
- data/lib/graphql/backtrace/tracer.rb +0 -80
- data/lib/graphql/deprecation.rb +0 -9
- data/lib/graphql/filter.rb +0 -59
- data/lib/graphql/language/parser.y +0 -560
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
- data/lib/graphql/schema/null_mask.rb +0 -11
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
|
@@ -4,37 +4,12 @@ require 'set'
|
|
|
4
4
|
|
|
5
5
|
module GraphQL
|
|
6
6
|
class Schema
|
|
7
|
-
# Restrict access to a {GraphQL::Schema} with a user-defined
|
|
7
|
+
# Restrict access to a {GraphQL::Schema} with a user-defined `visible?` implementations.
|
|
8
8
|
#
|
|
9
9
|
# When validating and executing a query, all access to schema members
|
|
10
10
|
# should go through a warden. If you access the schema directly,
|
|
11
11
|
# you may show a client something that it shouldn't be allowed to see.
|
|
12
12
|
#
|
|
13
|
-
# @example Hiding private fields
|
|
14
|
-
# private_members = -> (member, ctx) { member.metadata[:private] }
|
|
15
|
-
# result = Schema.execute(query_string, except: private_members)
|
|
16
|
-
#
|
|
17
|
-
# @example Custom filter implementation
|
|
18
|
-
# # It must respond to `#call(member)`.
|
|
19
|
-
# class MissingRequiredFlags
|
|
20
|
-
# def initialize(user)
|
|
21
|
-
# @user = user
|
|
22
|
-
# end
|
|
23
|
-
#
|
|
24
|
-
# # Return `false` if any required flags are missing
|
|
25
|
-
# def call(member, ctx)
|
|
26
|
-
# member.metadata[:required_flags].any? do |flag|
|
|
27
|
-
# !@user.has_flag?(flag)
|
|
28
|
-
# end
|
|
29
|
-
# end
|
|
30
|
-
# end
|
|
31
|
-
#
|
|
32
|
-
# # Then, use the custom filter in query:
|
|
33
|
-
# missing_required_flags = MissingRequiredFlags.new(current_user)
|
|
34
|
-
#
|
|
35
|
-
# # This query can only access members which match the user's flags
|
|
36
|
-
# result = Schema.execute(query_string, except: missing_required_flags)
|
|
37
|
-
#
|
|
38
13
|
# @api private
|
|
39
14
|
class Warden
|
|
40
15
|
def self.from_context(context)
|
|
@@ -44,6 +19,17 @@ module GraphQL
|
|
|
44
19
|
PassThruWarden
|
|
45
20
|
end
|
|
46
21
|
|
|
22
|
+
def self.types_from_context(context)
|
|
23
|
+
context.types || PassThruWarden
|
|
24
|
+
rescue NoMethodError
|
|
25
|
+
# this might be a hash which won't respond to #warden
|
|
26
|
+
PassThruWarden
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.use(schema)
|
|
30
|
+
# no-op
|
|
31
|
+
end
|
|
32
|
+
|
|
47
33
|
# @param visibility_method [Symbol] a Warden method to call for this entry
|
|
48
34
|
# @param entry [Object, Array<Object>] One or more definitions for a given name in a GraphQL Schema
|
|
49
35
|
# @param context [GraphQL::Query::Context]
|
|
@@ -85,23 +71,34 @@ module GraphQL
|
|
|
85
71
|
def visible_type_membership?(tm, ctx); tm.visible?(ctx); end
|
|
86
72
|
def interface_type_memberships(obj_t, ctx); obj_t.interface_type_memberships; end
|
|
87
73
|
def arguments(owner, ctx); owner.arguments(ctx); end
|
|
74
|
+
def loadable?(type, ctx); type.visible?(ctx); end
|
|
75
|
+
def loadable_possible_types(type, ctx); type.possible_types(ctx); end
|
|
76
|
+
def visibility_profile
|
|
77
|
+
@visibility_profile ||= Warden::VisibilityProfile.new(self)
|
|
78
|
+
end
|
|
88
79
|
end
|
|
89
80
|
end
|
|
90
81
|
|
|
91
82
|
class NullWarden
|
|
92
83
|
def initialize(_filter = nil, context:, schema:)
|
|
93
84
|
@schema = schema
|
|
85
|
+
@visibility_profile = Warden::VisibilityProfile.new(self)
|
|
94
86
|
end
|
|
95
87
|
|
|
88
|
+
# No-op, but for compatibility:
|
|
89
|
+
attr_writer :skip_warning
|
|
90
|
+
|
|
91
|
+
attr_reader :visibility_profile
|
|
92
|
+
|
|
96
93
|
def visible_field?(field_defn, _ctx = nil, owner = nil); true; end
|
|
97
94
|
def visible_argument?(arg_defn, _ctx = nil); true; end
|
|
98
95
|
def visible_type?(type_defn, _ctx = nil); true; end
|
|
99
|
-
def visible_enum_value?(enum_value, _ctx = nil);
|
|
96
|
+
def visible_enum_value?(enum_value, _ctx = nil); enum_value.visible?(Query::NullContext.instance); end
|
|
100
97
|
def visible_type_membership?(type_membership, _ctx = nil); true; end
|
|
101
98
|
def interface_type_memberships(obj_type, _ctx = nil); obj_type.interface_type_memberships; end
|
|
102
|
-
def get_type(type_name); @schema.get_type(type_name); end # rubocop:disable Development/ContextIsPassedCop
|
|
99
|
+
def get_type(type_name); @schema.get_type(type_name, Query::NullContext.instance, false); end # rubocop:disable Development/ContextIsPassedCop
|
|
103
100
|
def arguments(argument_owner, ctx = nil); argument_owner.all_argument_definitions; end
|
|
104
|
-
def enum_values(enum_defn); enum_defn.enum_values; end # rubocop:disable Development/ContextIsPassedCop
|
|
101
|
+
def enum_values(enum_defn); enum_defn.enum_values(Query::NullContext.instance); end # rubocop:disable Development/ContextIsPassedCop
|
|
105
102
|
def get_argument(parent_type, argument_name); parent_type.get_argument(argument_name); end # rubocop:disable Development/ContextIsPassedCop
|
|
106
103
|
def types; @schema.types; end # rubocop:disable Development/ContextIsPassedCop
|
|
107
104
|
def root_type_for_operation(op_name); @schema.root_type_for_operation(op_name); end
|
|
@@ -109,37 +106,117 @@ module GraphQL
|
|
|
109
106
|
def fields(type_defn); type_defn.all_field_definitions; end # rubocop:disable Development/ContextIsPassedCop
|
|
110
107
|
def get_field(parent_type, field_name); @schema.get_field(parent_type, field_name); end
|
|
111
108
|
def reachable_type?(type_name); true; end
|
|
109
|
+
def loadable?(type, _ctx); true; end
|
|
110
|
+
def loadable_possible_types(abstract_type, _ctx); union_type.possible_types; end
|
|
112
111
|
def reachable_types; @schema.types.values; end # rubocop:disable Development/ContextIsPassedCop
|
|
113
|
-
def possible_types(type_defn); @schema.possible_types(type_defn); end
|
|
112
|
+
def possible_types(type_defn); @schema.possible_types(type_defn, Query::NullContext.instance, false); end
|
|
114
113
|
def interfaces(obj_type); obj_type.interfaces; end
|
|
115
114
|
end
|
|
116
115
|
|
|
117
|
-
|
|
116
|
+
def visibility_profile
|
|
117
|
+
@visibility_profile ||= VisibilityProfile.new(self)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
class VisibilityProfile
|
|
121
|
+
def initialize(warden)
|
|
122
|
+
@warden = warden
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def directives
|
|
126
|
+
@warden.directives
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def directive_exists?(dir_name)
|
|
130
|
+
@warden.directives.any? { |d| d.graphql_name == dir_name }
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def type(name)
|
|
134
|
+
@warden.get_type(name)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def field(owner, field_name)
|
|
138
|
+
@warden.get_field(owner, field_name)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def argument(owner, arg_name)
|
|
142
|
+
@warden.get_argument(owner, arg_name)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def query_root
|
|
146
|
+
@warden.root_type_for_operation("query")
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def mutation_root
|
|
150
|
+
@warden.root_type_for_operation("mutation")
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def subscription_root
|
|
154
|
+
@warden.root_type_for_operation("subscription")
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def arguments(owner)
|
|
158
|
+
@warden.arguments(owner)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def fields(owner)
|
|
162
|
+
@warden.fields(owner)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def possible_types(type)
|
|
166
|
+
@warden.possible_types(type)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def enum_values(enum_type)
|
|
170
|
+
@warden.enum_values(enum_type)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def all_types
|
|
174
|
+
@warden.reachable_types
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def interfaces(obj_type)
|
|
178
|
+
@warden.interfaces(obj_type)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def loadable?(t, ctx) # TODO remove ctx here?
|
|
182
|
+
@warden.loadable?(t, ctx)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def loadable_possible_types(t, ctx)
|
|
186
|
+
@warden.loadable_possible_types(t, ctx)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def reachable_type?(type_name)
|
|
190
|
+
!!@warden.reachable_type?(type_name)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def visible_enum_value?(enum_value, ctx = nil)
|
|
194
|
+
@warden.visible_enum_value?(enum_value, ctx)
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
118
198
|
# @param context [GraphQL::Query::Context]
|
|
119
199
|
# @param schema [GraphQL::Schema]
|
|
120
|
-
def initialize(
|
|
200
|
+
def initialize(context:, schema:)
|
|
121
201
|
@schema = schema
|
|
122
202
|
# Cache these to avoid repeated hits to the inheritance chain when one isn't present
|
|
123
203
|
@query = @schema.query
|
|
124
204
|
@mutation = @schema.mutation
|
|
125
205
|
@subscription = @schema.subscription
|
|
126
206
|
@context = context
|
|
127
|
-
@visibility_cache =
|
|
128
|
-
read_through { |m| filter.call(m, context) }
|
|
129
|
-
else
|
|
130
|
-
read_through { |m| schema.visible?(m, context) }
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
@visibility_cache.compare_by_identity
|
|
207
|
+
@visibility_cache = read_through { |m| check_visible(schema, m) }
|
|
134
208
|
# Initialize all ivars to improve object shape consistency:
|
|
135
209
|
@types = @visible_types = @reachable_types = @visible_parent_fields =
|
|
136
210
|
@visible_possible_types = @visible_fields = @visible_arguments = @visible_enum_arrays =
|
|
137
211
|
@visible_enum_values = @visible_interfaces = @type_visibility = @type_memberships =
|
|
138
|
-
@visible_and_reachable_type = @unions = @unfiltered_interfaces =
|
|
139
|
-
@reachable_type_set =
|
|
212
|
+
@visible_and_reachable_type = @unions = @unfiltered_interfaces =
|
|
213
|
+
@reachable_type_set = @visibility_profile = @loadable_possible_types =
|
|
140
214
|
nil
|
|
215
|
+
@skip_warning = schema.plugins.any? { |(plugin, _opts)| plugin == GraphQL::Schema::Warden }
|
|
141
216
|
end
|
|
142
217
|
|
|
218
|
+
attr_writer :skip_warning
|
|
219
|
+
|
|
143
220
|
# @return [Hash<String, GraphQL::BaseType>] Visible types in the schema
|
|
144
221
|
def types
|
|
145
222
|
@types ||= begin
|
|
@@ -153,10 +230,30 @@ module GraphQL
|
|
|
153
230
|
end
|
|
154
231
|
end
|
|
155
232
|
|
|
233
|
+
# @return [Boolean] True if this type is used for `loads:` but not in the schema otherwise and not _explicitly_ hidden.
|
|
234
|
+
def loadable?(type, _ctx)
|
|
235
|
+
visible_type?(type) &&
|
|
236
|
+
!referenced?(type) &&
|
|
237
|
+
(type.respond_to?(:interfaces) ? interfaces(type).all? { |i| loadable?(i, _ctx) } : true)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# This abstract type was determined to be used for `loads` only.
|
|
241
|
+
# All its possible types are valid possibilities here -- no filtering.
|
|
242
|
+
def loadable_possible_types(abstract_type, _ctx)
|
|
243
|
+
@loadable_possible_types ||= read_through do |t|
|
|
244
|
+
if t.is_a?(Class) # union
|
|
245
|
+
t.possible_types
|
|
246
|
+
else
|
|
247
|
+
@schema.possible_types(abstract_type)
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
@loadable_possible_types[abstract_type]
|
|
251
|
+
end
|
|
252
|
+
|
|
156
253
|
# @return [GraphQL::BaseType, nil] The type named `type_name`, if it exists (else `nil`)
|
|
157
254
|
def get_type(type_name)
|
|
158
255
|
@visible_types ||= read_through do |name|
|
|
159
|
-
type_defn = @schema.get_type(name, @context)
|
|
256
|
+
type_defn = @schema.get_type(name, @context, false)
|
|
160
257
|
if type_defn && visible_and_reachable_type?(type_defn)
|
|
161
258
|
type_defn
|
|
162
259
|
else
|
|
@@ -203,7 +300,7 @@ module GraphQL
|
|
|
203
300
|
# @return [Array<GraphQL::BaseType>] The types which may be member of `type_defn`
|
|
204
301
|
def possible_types(type_defn)
|
|
205
302
|
@visible_possible_types ||= read_through { |type_defn|
|
|
206
|
-
pt = @schema.possible_types(type_defn, @context)
|
|
303
|
+
pt = @schema.possible_types(type_defn, @context, false)
|
|
207
304
|
pt.select { |t| visible_and_reachable_type?(t) }
|
|
208
305
|
}
|
|
209
306
|
@visible_possible_types[type_defn]
|
|
@@ -219,7 +316,16 @@ module GraphQL
|
|
|
219
316
|
# @param argument_owner [GraphQL::Field, GraphQL::InputObjectType]
|
|
220
317
|
# @return [Array<GraphQL::Argument>] Visible arguments on `argument_owner`
|
|
221
318
|
def arguments(argument_owner, ctx = nil)
|
|
222
|
-
@visible_arguments ||= read_through { |o|
|
|
319
|
+
@visible_arguments ||= read_through { |o|
|
|
320
|
+
args = o.arguments(@context)
|
|
321
|
+
if !args.empty?
|
|
322
|
+
args = args.values
|
|
323
|
+
args.select! { |a| visible_argument?(a, @context) }
|
|
324
|
+
args
|
|
325
|
+
else
|
|
326
|
+
EmptyObjects::EMPTY_ARRAY
|
|
327
|
+
end
|
|
328
|
+
}
|
|
223
329
|
@visible_arguments[argument_owner]
|
|
224
330
|
end
|
|
225
331
|
|
|
@@ -242,7 +348,13 @@ module GraphQL
|
|
|
242
348
|
|
|
243
349
|
# @return [Array<GraphQL::InterfaceType>] Visible interfaces implemented by `obj_type`
|
|
244
350
|
def interfaces(obj_type)
|
|
245
|
-
@visible_interfaces ||= read_through { |t|
|
|
351
|
+
@visible_interfaces ||= read_through { |t|
|
|
352
|
+
ints = t.interfaces(@context)
|
|
353
|
+
if !ints.empty?
|
|
354
|
+
ints.select! { |i| visible_type?(i) }
|
|
355
|
+
end
|
|
356
|
+
ints
|
|
357
|
+
}
|
|
246
358
|
@visible_interfaces[obj_type]
|
|
247
359
|
end
|
|
248
360
|
|
|
@@ -298,11 +410,26 @@ module GraphQL
|
|
|
298
410
|
next true if root_type?(type_defn) || type_defn.introspection?
|
|
299
411
|
|
|
300
412
|
if type_defn.kind.union?
|
|
301
|
-
|
|
413
|
+
!possible_types(type_defn).empty? && (referenced?(type_defn) || orphan_type?(type_defn))
|
|
302
414
|
elsif type_defn.kind.interface?
|
|
303
|
-
|
|
415
|
+
if !possible_types(type_defn).empty?
|
|
416
|
+
true
|
|
417
|
+
else
|
|
418
|
+
if @context.respond_to?(:logger) && (logger = @context.logger)
|
|
419
|
+
logger.debug { "Interface `#{type_defn.graphql_name}` hidden because it has no visible implementers" }
|
|
420
|
+
end
|
|
421
|
+
false
|
|
422
|
+
end
|
|
304
423
|
else
|
|
305
|
-
referenced?(type_defn)
|
|
424
|
+
if referenced?(type_defn)
|
|
425
|
+
true
|
|
426
|
+
elsif type_defn.kind.object?
|
|
427
|
+
# Show this object if it belongs to ...
|
|
428
|
+
interfaces(type_defn).any? { |t| referenced?(t) } || # an interface which is referenced in the schema
|
|
429
|
+
union_memberships(type_defn).any? { |t| referenced?(t) || orphan_type?(t) } # or a union which is referenced or added via orphan_types
|
|
430
|
+
else
|
|
431
|
+
false
|
|
432
|
+
end
|
|
306
433
|
end
|
|
307
434
|
end
|
|
308
435
|
|
|
@@ -357,37 +484,74 @@ module GraphQL
|
|
|
357
484
|
end
|
|
358
485
|
|
|
359
486
|
def referenced?(type_defn)
|
|
360
|
-
|
|
361
|
-
graphql_name = type_defn.unwrap.graphql_name
|
|
362
|
-
members = @references_to[graphql_name] || NO_REFERENCES
|
|
487
|
+
members = @schema.references_to(type_defn)
|
|
363
488
|
members.any? { |m| visible?(m) }
|
|
364
489
|
end
|
|
365
490
|
|
|
366
|
-
NO_REFERENCES = [].freeze
|
|
367
|
-
|
|
368
491
|
def orphan_type?(type_defn)
|
|
369
492
|
@schema.orphan_types.include?(type_defn)
|
|
370
493
|
end
|
|
371
494
|
|
|
372
|
-
def visible_abstract_type?(type_defn)
|
|
373
|
-
type_defn.kind.object? && (
|
|
374
|
-
interfaces(type_defn).any? ||
|
|
375
|
-
union_memberships(type_defn).any?
|
|
376
|
-
)
|
|
377
|
-
end
|
|
378
|
-
|
|
379
|
-
def visible_possible_types?(type_defn)
|
|
380
|
-
possible_types(type_defn).any? { |t| visible_and_reachable_type?(t) }
|
|
381
|
-
end
|
|
382
|
-
|
|
383
495
|
def visible?(member)
|
|
384
496
|
@visibility_cache[member]
|
|
385
497
|
end
|
|
386
498
|
|
|
387
499
|
def read_through
|
|
388
|
-
Hash.new { |h, k| h[k] = yield(k) }
|
|
500
|
+
Hash.new { |h, k| h[k] = yield(k) }.compare_by_identity
|
|
389
501
|
end
|
|
390
502
|
|
|
503
|
+
def check_visible(schema, member)
|
|
504
|
+
if schema.visible?(member, @context)
|
|
505
|
+
true
|
|
506
|
+
elsif @skip_warning
|
|
507
|
+
false
|
|
508
|
+
else
|
|
509
|
+
member_s = member.respond_to?(:path) ? member.path : member.inspect
|
|
510
|
+
member_type = case member
|
|
511
|
+
when Module
|
|
512
|
+
if member.respond_to?(:kind)
|
|
513
|
+
member.kind.name.downcase
|
|
514
|
+
else
|
|
515
|
+
""
|
|
516
|
+
end
|
|
517
|
+
when GraphQL::Schema::Field
|
|
518
|
+
"field"
|
|
519
|
+
when GraphQL::Schema::EnumValue
|
|
520
|
+
"enum value"
|
|
521
|
+
when GraphQL::Schema::Argument
|
|
522
|
+
"argument"
|
|
523
|
+
else
|
|
524
|
+
""
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
schema_s = schema.name ? "#{schema.name}'s" : ""
|
|
528
|
+
schema_name = schema.name ? "#{schema.name}" : "your schema"
|
|
529
|
+
warn(ADD_WARDEN_WARNING % { schema_s: schema_s, schema_name: schema_name, member: member_s, member_type: member_type })
|
|
530
|
+
@skip_warning = true # only warn once per query
|
|
531
|
+
# If there's no schema name, add the backtrace for additional context:
|
|
532
|
+
if schema_s == ""
|
|
533
|
+
puts caller.map { |l| " #{l}"}
|
|
534
|
+
end
|
|
535
|
+
false
|
|
536
|
+
end
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
ADD_WARDEN_WARNING = <<~WARNING
|
|
540
|
+
DEPRECATION: %{schema_s} "%{member}" %{member_type} returned `false` for `.visible?` but `GraphQL::Schema::Visibility` isn't configured yet.
|
|
541
|
+
|
|
542
|
+
Address this warning by adding:
|
|
543
|
+
|
|
544
|
+
use GraphQL::Schema::Visibility
|
|
545
|
+
|
|
546
|
+
to the definition for %{schema_name}. (Future GraphQL-Ruby versions won't check `.visible?` methods by default.)
|
|
547
|
+
|
|
548
|
+
Alternatively, for legacy behavior, add:
|
|
549
|
+
|
|
550
|
+
use GraphQL::Schema::Warden # legacy visibility behavior
|
|
551
|
+
|
|
552
|
+
For more information see: https://graphql-ruby.org/authorization/visibility.html
|
|
553
|
+
WARNING
|
|
554
|
+
|
|
391
555
|
def reachable_type_set
|
|
392
556
|
return @reachable_type_set if @reachable_type_set
|
|
393
557
|
|
|
@@ -416,54 +580,62 @@ module GraphQL
|
|
|
416
580
|
end
|
|
417
581
|
end
|
|
418
582
|
|
|
583
|
+
included_interface_possible_types_set = Set.new
|
|
584
|
+
|
|
419
585
|
until unvisited_types.empty?
|
|
420
586
|
type = unvisited_types.pop
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
587
|
+
visit_type(type, unvisited_types, @reachable_type_set, rt_hash, included_interface_possible_types_set, include_interface_possible_types: false)
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
@reachable_type_set
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
def visit_type(type, unvisited_types, visited_type_set, type_by_name_hash, included_interface_possible_types_set, include_interface_possible_types:)
|
|
594
|
+
if visited_type_set.add?(type) || (include_interface_possible_types && type.kind.interface? && included_interface_possible_types_set.add?(type))
|
|
595
|
+
type_by_name = type_by_name_hash[type.graphql_name] ||= type
|
|
596
|
+
if type_by_name != type
|
|
597
|
+
name_1, name_2 = [type.inspect, type_by_name.inspect].sort
|
|
598
|
+
raise DuplicateNamesError.new(
|
|
599
|
+
duplicated_name: type.graphql_name, duplicated_definition_1: name_1, duplicated_definition_2: name_2
|
|
600
|
+
)
|
|
601
|
+
end
|
|
602
|
+
if type.kind.input_object?
|
|
603
|
+
# recurse into visible arguments
|
|
604
|
+
arguments(type).each do |argument|
|
|
605
|
+
argument_type = argument.type.unwrap
|
|
606
|
+
unvisited_types << argument_type
|
|
427
607
|
end
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
# recurse into visible
|
|
436
|
-
|
|
437
|
-
unvisited_types <<
|
|
608
|
+
elsif type.kind.union?
|
|
609
|
+
# recurse into visible possible types
|
|
610
|
+
possible_types(type).each do |possible_type|
|
|
611
|
+
unvisited_types << possible_type
|
|
612
|
+
end
|
|
613
|
+
elsif type.kind.fields?
|
|
614
|
+
if type.kind.object?
|
|
615
|
+
# recurse into visible implemented interfaces
|
|
616
|
+
interfaces(type).each do |interface|
|
|
617
|
+
unvisited_types << interface
|
|
438
618
|
end
|
|
439
|
-
elsif
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
possible_types(type).each do |possible_type|
|
|
443
|
-
unvisited_types << possible_type
|
|
444
|
-
end
|
|
445
|
-
elsif type.kind.object?
|
|
446
|
-
# recurse into visible implemented interfaces
|
|
447
|
-
interfaces(type).each do |interface|
|
|
448
|
-
unvisited_types << interface
|
|
449
|
-
end
|
|
619
|
+
elsif include_interface_possible_types
|
|
620
|
+
possible_types(type).each do |pt|
|
|
621
|
+
unvisited_types << pt
|
|
450
622
|
end
|
|
623
|
+
end
|
|
624
|
+
# Don't visit interface possible types -- it's not enough to justify visibility
|
|
451
625
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
626
|
+
# recurse into visible fields
|
|
627
|
+
fields(type).each do |field|
|
|
628
|
+
field_type = field.type.unwrap
|
|
629
|
+
# In this case, if it's an interface, we want to include
|
|
630
|
+
visit_type(field_type, unvisited_types, visited_type_set, type_by_name_hash, included_interface_possible_types_set, include_interface_possible_types: true)
|
|
631
|
+
# recurse into visible arguments
|
|
632
|
+
arguments(field).each do |argument|
|
|
633
|
+
argument_type = argument.type.unwrap
|
|
634
|
+
unvisited_types << argument_type
|
|
461
635
|
end
|
|
462
636
|
end
|
|
463
637
|
end
|
|
464
638
|
end
|
|
465
|
-
|
|
466
|
-
@reachable_type_set
|
|
467
639
|
end
|
|
468
640
|
end
|
|
469
641
|
end
|