graphql 2.2.17 → 2.5.16

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.
Files changed (240) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
  3. data/lib/generators/graphql/install_generator.rb +46 -0
  4. data/lib/generators/graphql/orm_mutations_base.rb +1 -1
  5. data/lib/generators/graphql/templates/base_resolver.erb +2 -0
  6. data/lib/generators/graphql/templates/schema.erb +3 -0
  7. data/lib/generators/graphql/type_generator.rb +1 -1
  8. data/lib/graphql/analysis/analyzer.rb +90 -0
  9. data/lib/graphql/analysis/field_usage.rb +82 -0
  10. data/lib/graphql/analysis/max_query_complexity.rb +20 -0
  11. data/lib/graphql/analysis/max_query_depth.rb +20 -0
  12. data/lib/graphql/analysis/query_complexity.rb +263 -0
  13. data/lib/graphql/analysis/{ast/query_depth.rb → query_depth.rb} +23 -25
  14. data/lib/graphql/analysis/visitor.rb +280 -0
  15. data/lib/graphql/analysis.rb +95 -1
  16. data/lib/graphql/autoload.rb +38 -0
  17. data/lib/graphql/backtrace/table.rb +118 -55
  18. data/lib/graphql/backtrace.rb +1 -19
  19. data/lib/graphql/current.rb +57 -0
  20. data/lib/graphql/dashboard/detailed_traces.rb +47 -0
  21. data/lib/graphql/dashboard/installable.rb +22 -0
  22. data/lib/graphql/dashboard/limiters.rb +93 -0
  23. data/lib/graphql/dashboard/operation_store.rb +199 -0
  24. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
  25. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
  26. data/lib/graphql/dashboard/statics/charts.min.css +1 -0
  27. data/lib/graphql/dashboard/statics/dashboard.css +30 -0
  28. data/lib/graphql/dashboard/statics/dashboard.js +143 -0
  29. data/lib/graphql/dashboard/statics/header-icon.png +0 -0
  30. data/lib/graphql/dashboard/statics/icon.png +0 -0
  31. data/lib/graphql/dashboard/subscriptions.rb +96 -0
  32. data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
  33. data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
  34. data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
  35. data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
  36. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +23 -0
  37. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
  38. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
  39. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
  40. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
  41. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
  42. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
  43. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
  44. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
  45. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
  46. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
  47. data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
  48. data/lib/graphql/dashboard.rb +158 -0
  49. data/lib/graphql/dataloader/active_record_association_source.rb +84 -0
  50. data/lib/graphql/dataloader/active_record_source.rb +47 -0
  51. data/lib/graphql/dataloader/async_dataloader.rb +46 -19
  52. data/lib/graphql/dataloader/null_dataloader.rb +51 -10
  53. data/lib/graphql/dataloader/source.rb +20 -9
  54. data/lib/graphql/dataloader.rb +153 -45
  55. data/lib/graphql/date_encoding_error.rb +1 -1
  56. data/lib/graphql/dig.rb +2 -1
  57. data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
  58. data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
  59. data/lib/graphql/execution/interpreter/resolve.rb +23 -25
  60. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +63 -5
  61. data/lib/graphql/execution/interpreter/runtime.rb +321 -222
  62. data/lib/graphql/execution/interpreter.rb +23 -30
  63. data/lib/graphql/execution/lookahead.rb +18 -11
  64. data/lib/graphql/execution/multiplex.rb +6 -5
  65. data/lib/graphql/introspection/directive_location_enum.rb +1 -1
  66. data/lib/graphql/introspection/directive_type.rb +1 -1
  67. data/lib/graphql/introspection/entry_points.rb +2 -2
  68. data/lib/graphql/introspection/field_type.rb +1 -1
  69. data/lib/graphql/introspection/schema_type.rb +6 -11
  70. data/lib/graphql/introspection/type_type.rb +5 -5
  71. data/lib/graphql/invalid_name_error.rb +1 -1
  72. data/lib/graphql/invalid_null_error.rb +20 -17
  73. data/lib/graphql/language/cache.rb +13 -0
  74. data/lib/graphql/language/comment.rb +18 -0
  75. data/lib/graphql/language/document_from_schema_definition.rb +64 -35
  76. data/lib/graphql/language/lexer.rb +72 -42
  77. data/lib/graphql/language/nodes.rb +93 -52
  78. data/lib/graphql/language/parser.rb +168 -61
  79. data/lib/graphql/language/printer.rb +31 -15
  80. data/lib/graphql/language/sanitized_printer.rb +1 -1
  81. data/lib/graphql/language.rb +61 -1
  82. data/lib/graphql/pagination/connection.rb +1 -1
  83. data/lib/graphql/query/context/scoped_context.rb +1 -1
  84. data/lib/graphql/query/context.rb +46 -47
  85. data/lib/graphql/query/null_context.rb +3 -5
  86. data/lib/graphql/query/partial.rb +179 -0
  87. data/lib/graphql/query/validation_pipeline.rb +2 -2
  88. data/lib/graphql/query/variable_validation_error.rb +1 -1
  89. data/lib/graphql/query.rb +123 -69
  90. data/lib/graphql/railtie.rb +7 -0
  91. data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
  92. data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
  93. data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
  94. data/lib/graphql/rubocop.rb +2 -0
  95. data/lib/graphql/schema/addition.rb +26 -13
  96. data/lib/graphql/schema/always_visible.rb +7 -2
  97. data/lib/graphql/schema/argument.rb +57 -8
  98. data/lib/graphql/schema/build_from_definition.rb +116 -49
  99. data/lib/graphql/schema/directive/flagged.rb +4 -2
  100. data/lib/graphql/schema/directive.rb +54 -2
  101. data/lib/graphql/schema/enum.rb +107 -24
  102. data/lib/graphql/schema/enum_value.rb +10 -2
  103. data/lib/graphql/schema/field/connection_extension.rb +1 -1
  104. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  105. data/lib/graphql/schema/field.rb +134 -45
  106. data/lib/graphql/schema/field_extension.rb +1 -1
  107. data/lib/graphql/schema/has_single_input_argument.rb +6 -2
  108. data/lib/graphql/schema/input_object.rb +122 -64
  109. data/lib/graphql/schema/interface.rb +23 -5
  110. data/lib/graphql/schema/introspection_system.rb +6 -17
  111. data/lib/graphql/schema/late_bound_type.rb +4 -0
  112. data/lib/graphql/schema/list.rb +3 -3
  113. data/lib/graphql/schema/loader.rb +3 -2
  114. data/lib/graphql/schema/member/base_dsl_methods.rb +15 -0
  115. data/lib/graphql/schema/member/has_arguments.rb +44 -58
  116. data/lib/graphql/schema/member/has_dataloader.rb +62 -0
  117. data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
  118. data/lib/graphql/schema/member/has_directives.rb +4 -4
  119. data/lib/graphql/schema/member/has_fields.rb +26 -6
  120. data/lib/graphql/schema/member/has_interfaces.rb +6 -6
  121. data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
  122. data/lib/graphql/schema/member/has_validators.rb +1 -1
  123. data/lib/graphql/schema/member/relay_shortcuts.rb +1 -1
  124. data/lib/graphql/schema/member/type_system_helpers.rb +17 -4
  125. data/lib/graphql/schema/member.rb +1 -0
  126. data/lib/graphql/schema/mutation.rb +7 -0
  127. data/lib/graphql/schema/object.rb +25 -8
  128. data/lib/graphql/schema/printer.rb +1 -0
  129. data/lib/graphql/schema/ractor_shareable.rb +79 -0
  130. data/lib/graphql/schema/relay_classic_mutation.rb +0 -1
  131. data/lib/graphql/schema/resolver.rb +29 -23
  132. data/lib/graphql/schema/scalar.rb +1 -6
  133. data/lib/graphql/schema/subscription.rb +52 -6
  134. data/lib/graphql/schema/timeout.rb +19 -2
  135. data/lib/graphql/schema/type_expression.rb +2 -2
  136. data/lib/graphql/schema/union.rb +1 -1
  137. data/lib/graphql/schema/validator/all_validator.rb +62 -0
  138. data/lib/graphql/schema/validator/required_validator.rb +92 -11
  139. data/lib/graphql/schema/validator.rb +3 -1
  140. data/lib/graphql/schema/visibility/migration.rb +188 -0
  141. data/lib/graphql/schema/visibility/profile.rb +445 -0
  142. data/lib/graphql/schema/visibility/visit.rb +190 -0
  143. data/lib/graphql/schema/visibility.rb +311 -0
  144. data/lib/graphql/schema/warden.rb +190 -20
  145. data/lib/graphql/schema.rb +695 -167
  146. data/lib/graphql/static_validation/all_rules.rb +2 -2
  147. data/lib/graphql/static_validation/base_visitor.rb +6 -5
  148. data/lib/graphql/static_validation/literal_validator.rb +4 -4
  149. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  150. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
  151. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
  152. data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -3
  153. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
  154. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
  155. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +47 -13
  156. data/lib/graphql/static_validation/rules/fields_will_merge.rb +88 -25
  157. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
  158. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  159. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
  160. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  161. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  162. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
  163. data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
  164. data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
  165. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -4
  166. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +3 -3
  167. data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
  168. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +7 -3
  169. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
  170. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
  171. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
  172. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
  173. data/lib/graphql/static_validation/validation_context.rb +18 -2
  174. data/lib/graphql/static_validation/validator.rb +6 -1
  175. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +5 -3
  176. data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
  177. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
  178. data/lib/graphql/subscriptions/event.rb +13 -2
  179. data/lib/graphql/subscriptions/serialize.rb +1 -1
  180. data/lib/graphql/subscriptions.rb +7 -5
  181. data/lib/graphql/testing/helpers.rb +48 -16
  182. data/lib/graphql/testing/mock_action_cable.rb +111 -0
  183. data/lib/graphql/testing.rb +1 -0
  184. data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
  185. data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
  186. data/lib/graphql/tracing/appoptics_trace.rb +5 -1
  187. data/lib/graphql/tracing/appoptics_tracing.rb +7 -0
  188. data/lib/graphql/tracing/appsignal_trace.rb +32 -59
  189. data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
  190. data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
  191. data/lib/graphql/tracing/data_dog_trace.rb +46 -162
  192. data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
  193. data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
  194. data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
  195. data/lib/graphql/tracing/detailed_trace.rb +141 -0
  196. data/lib/graphql/tracing/legacy_hooks_trace.rb +1 -0
  197. data/lib/graphql/tracing/legacy_trace.rb +4 -61
  198. data/lib/graphql/tracing/monitor_trace.rb +283 -0
  199. data/lib/graphql/tracing/new_relic_trace.rb +47 -54
  200. data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
  201. data/lib/graphql/tracing/notifications_trace.rb +183 -37
  202. data/lib/graphql/tracing/notifications_tracing.rb +2 -0
  203. data/lib/graphql/tracing/null_trace.rb +9 -0
  204. data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
  205. data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
  206. data/lib/graphql/tracing/perfetto_trace.rb +818 -0
  207. data/lib/graphql/tracing/platform_tracing.rb +1 -1
  208. data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +2 -0
  209. data/lib/graphql/tracing/prometheus_trace.rb +73 -73
  210. data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
  211. data/lib/graphql/tracing/scout_trace.rb +32 -58
  212. data/lib/graphql/tracing/scout_tracing.rb +2 -0
  213. data/lib/graphql/tracing/sentry_trace.rb +64 -98
  214. data/lib/graphql/tracing/statsd_trace.rb +33 -45
  215. data/lib/graphql/tracing/statsd_tracing.rb +2 -0
  216. data/lib/graphql/tracing/trace.rb +111 -1
  217. data/lib/graphql/tracing.rb +31 -30
  218. data/lib/graphql/type_kinds.rb +2 -1
  219. data/lib/graphql/types/relay/connection_behaviors.rb +12 -2
  220. data/lib/graphql/types/relay/edge_behaviors.rb +11 -1
  221. data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
  222. data/lib/graphql/types.rb +18 -11
  223. data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
  224. data/lib/graphql/version.rb +1 -1
  225. data/lib/graphql.rb +64 -54
  226. metadata +197 -22
  227. data/lib/graphql/analysis/ast/analyzer.rb +0 -91
  228. data/lib/graphql/analysis/ast/field_usage.rb +0 -82
  229. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
  230. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  231. data/lib/graphql/analysis/ast/query_complexity.rb +0 -182
  232. data/lib/graphql/analysis/ast/visitor.rb +0 -276
  233. data/lib/graphql/analysis/ast.rb +0 -94
  234. data/lib/graphql/backtrace/inspect_result.rb +0 -50
  235. data/lib/graphql/backtrace/trace.rb +0 -93
  236. data/lib/graphql/backtrace/tracer.rb +0 -80
  237. data/lib/graphql/language/token.rb +0 -34
  238. data/lib/graphql/schema/invalid_type_error.rb +0 -7
  239. data/lib/graphql/schema/null_mask.rb +0 -11
  240. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
@@ -18,21 +18,15 @@ module GraphQL
18
18
  include_built_in_directives: false, include_built_in_scalars: false, always_include_schema: false
19
19
  )
20
20
  @schema = schema
21
+ @context = context
21
22
  @always_include_schema = always_include_schema
22
23
  @include_introspection_types = include_introspection_types
23
24
  @include_built_in_scalars = include_built_in_scalars
24
25
  @include_built_in_directives = include_built_in_directives
25
26
  @include_one_of = false
26
27
 
27
- schema_context = schema.context_class.new(query: nil, object: nil, schema: schema, values: context)
28
-
29
-
30
- @warden = @schema.warden_class.new(
31
- schema: @schema,
32
- context: schema_context,
33
- )
34
-
35
- schema_context.warden = @warden
28
+ dummy_query = @schema.query_class.new(@schema, "{ __typename }", validate: false, context: context)
29
+ @types = dummy_query.types # rubocop:disable Development/ContextIsPassedCop
36
30
  end
37
31
 
38
32
  def document
@@ -44,9 +38,9 @@ module GraphQL
44
38
  def build_schema_node
45
39
  if !schema_respects_root_name_conventions?(@schema)
46
40
  GraphQL::Language::Nodes::SchemaDefinition.new(
47
- query: (q = warden.root_type_for_operation("query")) && q.graphql_name,
48
- mutation: (m = warden.root_type_for_operation("mutation")) && m.graphql_name,
49
- subscription: (s = warden.root_type_for_operation("subscription")) && s.graphql_name,
41
+ query: @types.query_root&.graphql_name,
42
+ mutation: @types.mutation_root&.graphql_name,
43
+ subscription: @types.subscription_root&.graphql_name,
50
44
  directives: definition_directives(@schema, :schema_directives)
51
45
  )
52
46
  else
@@ -57,16 +51,18 @@ module GraphQL
57
51
  end
58
52
 
59
53
  def build_object_type_node(object_type)
60
- ints = warden.interfaces(object_type)
61
- if ints.any?
62
- ints.sort_by!(&:graphql_name)
54
+ ints = @types.interfaces(object_type)
55
+
56
+ if !ints.empty?
57
+ ints = ints.sort_by(&:graphql_name)
63
58
  ints.map! { |iface| build_type_name_node(iface) }
64
59
  end
65
60
 
66
61
  GraphQL::Language::Nodes::ObjectTypeDefinition.new(
67
62
  name: object_type.graphql_name,
63
+ comment: object_type.comment,
68
64
  interfaces: ints,
69
- fields: build_field_nodes(warden.fields(object_type)),
65
+ fields: build_field_nodes(@types.fields(object_type)),
70
66
  description: object_type.description,
71
67
  directives: directives(object_type),
72
68
  )
@@ -75,7 +71,8 @@ module GraphQL
75
71
  def build_field_node(field)
76
72
  GraphQL::Language::Nodes::FieldDefinition.new(
77
73
  name: field.graphql_name,
78
- arguments: build_argument_nodes(warden.arguments(field)),
74
+ comment: field.comment,
75
+ arguments: build_argument_nodes(@types.arguments(field)),
79
76
  type: build_type_name_node(field.type),
80
77
  description: field.description,
81
78
  directives: directives(field),
@@ -85,8 +82,9 @@ module GraphQL
85
82
  def build_union_type_node(union_type)
86
83
  GraphQL::Language::Nodes::UnionTypeDefinition.new(
87
84
  name: union_type.graphql_name,
85
+ comment: union_type.comment,
88
86
  description: union_type.description,
89
- types: warden.possible_types(union_type).sort_by(&:graphql_name).map { |type| build_type_name_node(type) },
87
+ types: @types.possible_types(union_type).sort_by(&:graphql_name).map { |type| build_type_name_node(type) },
90
88
  directives: directives(union_type),
91
89
  )
92
90
  end
@@ -94,9 +92,10 @@ module GraphQL
94
92
  def build_interface_type_node(interface_type)
95
93
  GraphQL::Language::Nodes::InterfaceTypeDefinition.new(
96
94
  name: interface_type.graphql_name,
97
- interfaces: warden.interfaces(interface_type).sort_by(&:graphql_name).map { |type| build_type_name_node(type) },
95
+ comment: interface_type.comment,
96
+ interfaces: @types.interfaces(interface_type).sort_by(&:graphql_name).map { |type| build_type_name_node(type) },
98
97
  description: interface_type.description,
99
- fields: build_field_nodes(warden.fields(interface_type)),
98
+ fields: build_field_nodes(@types.fields(interface_type)),
100
99
  directives: directives(interface_type),
101
100
  )
102
101
  end
@@ -104,7 +103,8 @@ module GraphQL
104
103
  def build_enum_type_node(enum_type)
105
104
  GraphQL::Language::Nodes::EnumTypeDefinition.new(
106
105
  name: enum_type.graphql_name,
107
- values: warden.enum_values(enum_type).sort_by(&:graphql_name).map do |enum_value|
106
+ comment: enum_type.comment,
107
+ values: @types.enum_values(enum_type).sort_by(&:graphql_name).map do |enum_value|
108
108
  build_enum_value_node(enum_value)
109
109
  end,
110
110
  description: enum_type.description,
@@ -115,6 +115,7 @@ module GraphQL
115
115
  def build_enum_value_node(enum_value)
116
116
  GraphQL::Language::Nodes::EnumValueDefinition.new(
117
117
  name: enum_value.graphql_name,
118
+ comment: enum_value.comment,
118
119
  description: enum_value.description,
119
120
  directives: directives(enum_value),
120
121
  )
@@ -123,6 +124,7 @@ module GraphQL
123
124
  def build_scalar_type_node(scalar_type)
124
125
  GraphQL::Language::Nodes::ScalarTypeDefinition.new(
125
126
  name: scalar_type.graphql_name,
127
+ comment: scalar_type.comment,
126
128
  description: scalar_type.description,
127
129
  directives: directives(scalar_type),
128
130
  )
@@ -137,6 +139,7 @@ module GraphQL
137
139
 
138
140
  argument_node = GraphQL::Language::Nodes::InputValueDefinition.new(
139
141
  name: argument.graphql_name,
142
+ comment: argument.comment,
140
143
  description: argument.description,
141
144
  type: build_type_name_node(argument.type),
142
145
  default_value: default_value,
@@ -149,7 +152,8 @@ module GraphQL
149
152
  def build_input_object_node(input_object)
150
153
  GraphQL::Language::Nodes::InputObjectTypeDefinition.new(
151
154
  name: input_object.graphql_name,
152
- fields: build_argument_nodes(warden.arguments(input_object)),
155
+ comment: input_object.comment,
156
+ fields: build_argument_nodes(@types.arguments(input_object)),
153
157
  description: input_object.description,
154
158
  directives: directives(input_object),
155
159
  )
@@ -159,7 +163,7 @@ module GraphQL
159
163
  GraphQL::Language::Nodes::DirectiveDefinition.new(
160
164
  name: directive.graphql_name,
161
165
  repeatable: directive.repeatable?,
162
- arguments: build_argument_nodes(warden.arguments(directive)),
166
+ arguments: build_argument_nodes(@types.arguments(directive)),
163
167
  locations: build_directive_location_nodes(directive.locations),
164
168
  description: directive.description,
165
169
  )
@@ -204,7 +208,7 @@ module GraphQL
204
208
  when "INPUT_OBJECT"
205
209
  GraphQL::Language::Nodes::InputObject.new(
206
210
  arguments: default_value.to_h.map do |arg_name, arg_value|
207
- args = @warden.arguments(type)
211
+ args = @types.arguments(type)
208
212
  arg = args.find { |a| a.keyword.to_s == arg_name.to_s }
209
213
  if arg.nil?
210
214
  raise ArgumentError, "No argument definition on #{type.graphql_name} for argument: #{arg_name.inspect} (expected one of: #{args.map(&:keyword)})"
@@ -244,7 +248,7 @@ module GraphQL
244
248
  end
245
249
 
246
250
  def build_argument_nodes(arguments)
247
- if arguments.any?
251
+ if !arguments.empty?
248
252
  nodes = arguments.map { |arg| build_argument_node(arg) }
249
253
  nodes.sort_by!(&:name)
250
254
  nodes
@@ -260,13 +264,39 @@ module GraphQL
260
264
  end
261
265
 
262
266
  def build_definition_nodes
263
- dirs_to_build = warden.directives
267
+ dirs_to_build = @types.directives
264
268
  if !include_built_in_directives
265
269
  dirs_to_build = dirs_to_build.reject { |directive| directive.default_directive? }
266
270
  end
267
271
  definitions = build_directive_nodes(dirs_to_build)
272
+ all_types = @types.all_types
273
+ type_nodes = build_type_definition_nodes(all_types)
274
+
275
+ if !(ex_t = schema.extra_types).empty?
276
+ dummy_query = Class.new(GraphQL::Schema::Object) do
277
+ graphql_name "DummyQuery"
278
+ (all_types + ex_t).each_with_index do |type, idx|
279
+ if !type.kind.input_object? && !type.introspection?
280
+ field "f#{idx}", type
281
+ end
282
+ end
283
+ end
284
+
285
+ extra_types_schema = Class.new(GraphQL::Schema) do
286
+ query(dummy_query)
287
+ end
288
+
289
+ extra_types_types = GraphQL::Query.new(extra_types_schema, "{ __typename }", context: @context).types # rubocop:disable Development/ContextIsPassedCop
290
+ # Temporarily replace `@types` with something from this example schema.
291
+ # It'd be much nicer to pass this in, but that would be a big refactor :S
292
+ prev_types = @types
293
+ @types = extra_types_types
294
+ type_nodes += build_type_definition_nodes(ex_t)
295
+ @types = prev_types
296
+ end
297
+
298
+ type_nodes.sort_by!(&:name)
268
299
 
269
- type_nodes = build_type_definition_nodes(warden.reachable_types + schema.extra_types)
270
300
  if @include_one_of
271
301
  # This may have been set to true when iterating over all types
272
302
  definitions.concat(build_directive_nodes([GraphQL::Schema::Directive::OneOf]))
@@ -289,9 +319,7 @@ module GraphQL
289
319
  types = types.reject { |type| type.kind.scalar? && type.default_scalar? }
290
320
  end
291
321
 
292
- types
293
- .map { |type| build_type_definition_node(type) }
294
- .sort_by(&:name)
322
+ types.map { |type| build_type_definition_node(type) }
295
323
  end
296
324
 
297
325
  def build_field_nodes(fields)
@@ -319,10 +347,11 @@ module GraphQL
319
347
  end
320
348
 
321
349
  def definition_directives(member, directives_method)
322
- dirs = if !member.respond_to?(directives_method) || member.directives.empty?
350
+ if !member.respond_to?(directives_method) || member.directives.empty?
323
351
  EmptyObjects::EMPTY_ARRAY
324
352
  else
325
- member.public_send(directives_method).map do |dir|
353
+ visible_directives = member.public_send(directives_method).select { |dir| @types.directive_exists?(dir.graphql_name) }
354
+ visible_directives.map! do |dir|
326
355
  args = []
327
356
  dir.arguments.argument_values.each_value do |arg_value| # rubocop:disable Development/ContextIsPassedCop -- directive instance method
328
357
  arg_defn = arg_value.definition
@@ -346,12 +375,12 @@ module GraphQL
346
375
  arguments: args
347
376
  )
348
377
  end
349
- end
350
378
 
351
- dirs
379
+ visible_directives
380
+ end
352
381
  end
353
382
 
354
- attr_reader :schema, :warden, :always_include_schema,
383
+ attr_reader :schema, :always_include_schema,
355
384
  :include_introspection_types, :include_built_in_directives, :include_built_in_scalars
356
385
  end
357
386
  end
@@ -3,7 +3,7 @@ module GraphQL
3
3
  module Language
4
4
 
5
5
  class Lexer
6
- def initialize(graphql_str, filename: nil)
6
+ def initialize(graphql_str, filename: nil, max_tokens: nil)
7
7
  if !(graphql_str.encoding == Encoding::UTF_8 || graphql_str.ascii_only?)
8
8
  graphql_str = graphql_str.dup.force_encoding(Encoding::UTF_8)
9
9
  end
@@ -11,17 +11,32 @@ module GraphQL
11
11
  @filename = filename
12
12
  @scanner = StringScanner.new(graphql_str)
13
13
  @pos = nil
14
+ @max_tokens = max_tokens || Float::INFINITY
15
+ @tokens_count = 0
16
+ @finished = false
14
17
  end
15
18
 
16
- def eos?
17
- @scanner.eos?
19
+ def finished?
20
+ @finished
18
21
  end
19
22
 
20
- attr_reader :pos
23
+ def freeze
24
+ @scanner = nil
25
+ super
26
+ end
27
+
28
+ attr_reader :pos, :tokens_count
21
29
 
22
30
  def advance
23
31
  @scanner.skip(IGNORE_REGEXP)
24
- return false if @scanner.eos?
32
+ if @scanner.eos?
33
+ @finished = true
34
+ return false
35
+ end
36
+ @tokens_count += 1
37
+ if @tokens_count > @max_tokens
38
+ raise_parse_error("This query is too large to execute.")
39
+ end
25
40
  @pos = @scanner.pos
26
41
  next_byte = @string.getbyte(@pos)
27
42
  next_byte_is_for = FIRST_BYTES[next_byte]
@@ -51,9 +66,26 @@ module GraphQL
51
66
  @scanner.skip(IDENTIFIER_REGEXP)
52
67
  :IDENTIFIER
53
68
  when ByteFor::NUMBER
54
- @scanner.skip(NUMERIC_REGEXP)
55
- # Check for a matched decimal:
56
- @scanner[1] ? :FLOAT : :INT
69
+ if len = @scanner.skip(NUMERIC_REGEXP)
70
+
71
+ if GraphQL.reject_numbers_followed_by_names
72
+ new_pos = @scanner.pos
73
+ peek_byte = @string.getbyte(new_pos)
74
+ next_first_byte = FIRST_BYTES[peek_byte]
75
+ if next_first_byte == ByteFor::NAME || next_first_byte == ByteFor::IDENTIFIER
76
+ number_part = token_value
77
+ name_part = @scanner.scan(IDENTIFIER_REGEXP)
78
+ raise_parse_error("Name after number is not allowed (in `#{number_part}#{name_part}`)")
79
+ end
80
+ end
81
+ # Check for a matched decimal:
82
+ @scanner[1] ? :FLOAT : :INT
83
+ else
84
+ # Attempt to find the part after the `-`
85
+ value = @scanner.scan(/-\s?[a-z0-9]*/i)
86
+ invalid_byte_for_number_error_message = "Expected type 'number', but it was malformed#{value.nil? ? "" : ": #{value.inspect}"}."
87
+ raise_parse_error(invalid_byte_for_number_error_message)
88
+ end
57
89
  when ByteFor::ELLIPSIS
58
90
  if @string.getbyte(@pos + 1) != 46 || @string.getbyte(@pos + 2) != 46
59
91
  raise_parse_error("Expected `...`, actual: #{@string[@pos..@pos + 2].inspect}")
@@ -109,29 +141,27 @@ module GraphQL
109
141
  }
110
142
  UTF_8 = /\\u(?:([\dAa-f]{4})|\{([\da-f]{4,})\})(?:\\u([\dAa-f]{4}))?/i
111
143
  VALID_STRING = /\A(?:[^\\]|#{ESCAPES}|#{UTF_8})*\z/o
144
+ ESCAPED = /(?:#{ESCAPES}|#{UTF_8})/o
112
145
 
113
146
  def string_value
114
147
  str = token_value
115
148
  is_block = str.start_with?('"""')
116
149
  if is_block
117
150
  str.gsub!(/\A"""|"""\z/, '')
151
+ return Language::BlockString.trim_whitespace(str)
118
152
  else
119
153
  str.gsub!(/\A"|"\z/, '')
120
- end
121
154
 
122
- if is_block
123
- str = Language::BlockString.trim_whitespace(str)
124
- end
125
-
126
- if !str.valid_encoding? || !str.match?(VALID_STRING)
127
- raise_parse_error("Bad unicode escape in #{str.inspect}")
128
- else
129
- Lexer.replace_escaped_characters_in_place(str)
130
-
131
- if !str.valid_encoding?
155
+ if !str.valid_encoding? || !str.match?(VALID_STRING)
132
156
  raise_parse_error("Bad unicode escape in #{str.inspect}")
133
157
  else
134
- str
158
+ Lexer.replace_escaped_characters_in_place(str)
159
+
160
+ if !str.valid_encoding?
161
+ raise_parse_error("Bad unicode escape in #{str.inspect}")
162
+ else
163
+ str
164
+ end
135
165
  end
136
166
  end
137
167
  end
@@ -158,6 +188,7 @@ module GraphQL
158
188
  INT_REGEXP = /-?(?:[0]|[1-9][0-9]*)/
159
189
  FLOAT_DECIMAL_REGEXP = /[.][0-9]+/
160
190
  FLOAT_EXP_REGEXP = /[eE][+-]?[0-9]+/
191
+ # TODO: FLOAT_EXP_REGEXP should not be allowed to follow INT_REGEXP, integers are not allowed to have exponent parts.
161
192
  NUMERIC_REGEXP = /#{INT_REGEXP}(#{FLOAT_DECIMAL_REGEXP}#{FLOAT_EXP_REGEXP}|#{FLOAT_DECIMAL_REGEXP}|#{FLOAT_EXP_REGEXP})?/
162
193
 
163
194
  KEYWORDS = [
@@ -216,7 +247,7 @@ module GraphQL
216
247
  :SCALAR,
217
248
  nil,
218
249
  :FRAGMENT
219
- ]
250
+ ].freeze
220
251
 
221
252
  # This produces a unique integer for bytes 2 and 3 of each keyword string
222
253
  # See https://tenderlovemaking.com/2023/09/02/fast-tokenizers-with-stringscanner.html
@@ -245,18 +276,18 @@ module GraphQL
245
276
  PUNCTUATION_NAME_FOR_BYTE = Punctuation.constants.each_with_object([]) { |name, arr|
246
277
  punct = Punctuation.const_get(name)
247
278
  arr[punct.ord] = name
248
- }
279
+ }.freeze
280
+
249
281
 
250
282
  QUOTE = '"'
251
283
  UNICODE_DIGIT = /[0-9A-Za-z]/
252
284
  FOUR_DIGIT_UNICODE = /#{UNICODE_DIGIT}{4}/
253
285
  N_DIGIT_UNICODE = %r{#{Punctuation::LCURLY}#{UNICODE_DIGIT}{4,}#{Punctuation::RCURLY}}x
254
286
  UNICODE_ESCAPE = %r{\\u(?:#{FOUR_DIGIT_UNICODE}|#{N_DIGIT_UNICODE})}
255
- # # https://graphql.github.io/graphql-spec/June2018/#sec-String-Value
256
287
  STRING_ESCAPE = %r{[\\][\\/bfnrt]}
257
288
  BLOCK_QUOTE = '"""'
258
289
  ESCAPED_QUOTE = /\\"/;
259
- STRING_CHAR = /#{ESCAPED_QUOTE}|[^"\\]|#{UNICODE_ESCAPE}|#{STRING_ESCAPE}/
290
+ STRING_CHAR = /#{ESCAPED_QUOTE}|[^"\\\n\r]|#{UNICODE_ESCAPE}|#{STRING_ESCAPE}/
260
291
  QUOTED_STRING_REGEXP = %r{#{QUOTE} (?:#{STRING_CHAR})* #{QUOTE}}x
261
292
  BLOCK_STRING_REGEXP = %r{
262
293
  #{BLOCK_QUOTE}
@@ -296,29 +327,31 @@ module GraphQL
296
327
  punct = Punctuation.const_get(punct_name)
297
328
  FIRST_BYTES[punct.ord] = ByteFor::PUNCTUATION
298
329
  end
330
+ FIRST_BYTES.freeze
299
331
 
300
332
 
301
333
  # Replace any escaped unicode or whitespace with the _actual_ characters
302
334
  # To avoid allocating more strings, this modifies the string passed into it
303
335
  def self.replace_escaped_characters_in_place(raw_string)
304
- raw_string.gsub!(ESCAPES, ESCAPES_REPLACE)
305
- raw_string.gsub!(UTF_8) do |_matched_str|
306
- codepoint_1 = ($1 || $2).to_i(16)
307
- codepoint_2 = $3
308
-
309
- if codepoint_2
310
- codepoint_2 = codepoint_2.to_i(16)
311
- if (codepoint_1 >= 0xD800 && codepoint_1 <= 0xDBFF) && # leading surrogate
312
- (codepoint_2 >= 0xDC00 && codepoint_2 <= 0xDFFF) # trailing surrogate
313
- # A surrogate pair
314
- combined = ((codepoint_1 - 0xD800) * 0x400) + (codepoint_2 - 0xDC00) + 0x10000
315
- [combined].pack('U'.freeze)
336
+ raw_string.gsub!(ESCAPED) do |matched_str|
337
+ if (point_str_1 = $1 || $2)
338
+ codepoint_1 = point_str_1.to_i(16)
339
+ if (codepoint_2 = $3)
340
+ codepoint_2 = codepoint_2.to_i(16)
341
+ if (codepoint_1 >= 0xD800 && codepoint_1 <= 0xDBFF) && # leading surrogate
342
+ (codepoint_2 >= 0xDC00 && codepoint_2 <= 0xDFFF) # trailing surrogate
343
+ # A surrogate pair
344
+ combined = ((codepoint_1 - 0xD800) * 0x400) + (codepoint_2 - 0xDC00) + 0x10000
345
+ [combined].pack('U'.freeze)
346
+ else
347
+ # Two separate code points
348
+ [codepoint_1].pack('U'.freeze) + [codepoint_2].pack('U'.freeze)
349
+ end
316
350
  else
317
- # Two separate code points
318
- [codepoint_1].pack('U'.freeze) + [codepoint_2].pack('U'.freeze)
351
+ [codepoint_1].pack('U'.freeze)
319
352
  end
320
353
  else
321
- [codepoint_1].pack('U'.freeze)
354
+ ESCAPES_REPLACE[matched_str]
322
355
  end
323
356
  end
324
357
  nil
@@ -329,17 +362,14 @@ module GraphQL
329
362
  def self.tokenize(string)
330
363
  lexer = GraphQL::Language::Lexer.new(string)
331
364
  tokens = []
332
- prev_token = nil
333
365
  while (token_name = lexer.advance)
334
366
  new_token = [
335
367
  token_name,
336
368
  lexer.line_number,
337
369
  lexer.column_number,
338
370
  lexer.debug_token_value(token_name),
339
- prev_token,
340
371
  ]
341
372
  tokens << new_token
342
- prev_token = new_token
343
373
  end
344
374
  tokens
345
375
  end