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.
Files changed (428) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +3 -8
  3. data/lib/generators/graphql/enum_generator.rb +4 -10
  4. data/lib/generators/graphql/field_extractor.rb +31 -0
  5. data/lib/generators/graphql/input_generator.rb +50 -0
  6. data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
  7. data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +2 -0
  8. data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +2 -0
  9. data/lib/generators/graphql/install_generator.rb +60 -4
  10. data/lib/generators/graphql/interface_generator.rb +7 -7
  11. data/lib/generators/graphql/mutation_create_generator.rb +22 -0
  12. data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
  13. data/lib/generators/graphql/mutation_generator.rb +5 -30
  14. data/lib/generators/graphql/mutation_update_generator.rb +22 -0
  15. data/lib/generators/graphql/object_generator.rb +10 -38
  16. data/lib/generators/graphql/orm_mutations_base.rb +40 -0
  17. data/lib/generators/graphql/relay.rb +23 -12
  18. data/lib/generators/graphql/scalar_generator.rb +4 -2
  19. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  20. data/lib/generators/graphql/templates/base_connection.erb +2 -0
  21. data/lib/generators/graphql/templates/base_edge.erb +2 -0
  22. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  23. data/lib/generators/graphql/templates/base_field.erb +2 -0
  24. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  25. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  26. data/lib/generators/graphql/templates/base_object.erb +2 -0
  27. data/lib/generators/graphql/templates/base_resolver.erb +8 -0
  28. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  29. data/lib/generators/graphql/templates/base_union.erb +2 -0
  30. data/lib/generators/graphql/templates/enum.erb +5 -1
  31. data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
  32. data/lib/generators/graphql/templates/input.erb +9 -0
  33. data/lib/generators/graphql/templates/interface.erb +4 -2
  34. data/lib/generators/graphql/templates/loader.erb +2 -0
  35. data/lib/generators/graphql/templates/mutation.erb +3 -1
  36. data/lib/generators/graphql/templates/mutation_create.erb +20 -0
  37. data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
  38. data/lib/generators/graphql/templates/mutation_update.erb +21 -0
  39. data/lib/generators/graphql/templates/node_type.erb +2 -0
  40. data/lib/generators/graphql/templates/object.erb +4 -2
  41. data/lib/generators/graphql/templates/query_type.erb +2 -0
  42. data/lib/generators/graphql/templates/scalar.erb +3 -1
  43. data/lib/generators/graphql/templates/schema.erb +22 -2
  44. data/lib/generators/graphql/templates/union.erb +4 -2
  45. data/lib/generators/graphql/type_generator.rb +46 -10
  46. data/lib/generators/graphql/union_generator.rb +5 -5
  47. data/lib/graphql/analysis/analyzer.rb +89 -0
  48. data/lib/graphql/analysis/field_usage.rb +65 -28
  49. data/lib/graphql/analysis/max_query_complexity.rb +11 -17
  50. data/lib/graphql/analysis/max_query_depth.rb +13 -19
  51. data/lib/graphql/analysis/query_complexity.rb +156 -61
  52. data/lib/graphql/analysis/query_depth.rb +38 -23
  53. data/lib/graphql/analysis/visitor.rb +283 -0
  54. data/lib/graphql/analysis.rb +90 -6
  55. data/lib/graphql/autoload.rb +38 -0
  56. data/lib/graphql/backtrace/inspect_result.rb +0 -12
  57. data/lib/graphql/backtrace/table.rb +4 -22
  58. data/lib/graphql/backtrace/trace.rb +93 -0
  59. data/lib/graphql/backtrace/tracer.rb +8 -6
  60. data/lib/graphql/backtrace.rb +3 -8
  61. data/lib/graphql/coercion_error.rb +1 -9
  62. data/lib/graphql/current.rb +52 -0
  63. data/lib/graphql/dataloader/async_dataloader.rb +89 -0
  64. data/lib/graphql/dataloader/null_dataloader.rb +4 -2
  65. data/lib/graphql/dataloader/request.rb +5 -0
  66. data/lib/graphql/dataloader/source.rb +125 -33
  67. data/lib/graphql/dataloader.rb +193 -143
  68. data/lib/graphql/date_encoding_error.rb +16 -0
  69. data/lib/graphql/dig.rb +1 -1
  70. data/lib/graphql/duration_encoding_error.rb +16 -0
  71. data/lib/graphql/execution/errors.rb +12 -81
  72. data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
  73. data/lib/graphql/execution/interpreter/arguments.rb +2 -2
  74. data/lib/graphql/execution/interpreter/arguments_cache.rb +33 -36
  75. data/lib/graphql/execution/interpreter/resolve.rb +38 -4
  76. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +175 -0
  77. data/lib/graphql/execution/interpreter/runtime.rb +447 -403
  78. data/lib/graphql/execution/interpreter.rb +126 -80
  79. data/lib/graphql/execution/lazy.rb +11 -21
  80. data/lib/graphql/execution/lookahead.rb +133 -55
  81. data/lib/graphql/execution/multiplex.rb +4 -172
  82. data/lib/graphql/execution.rb +11 -4
  83. data/lib/graphql/integer_encoding_error.rb +18 -2
  84. data/lib/graphql/introspection/directive_location_enum.rb +2 -2
  85. data/lib/graphql/introspection/directive_type.rb +6 -4
  86. data/lib/graphql/introspection/dynamic_fields.rb +3 -8
  87. data/lib/graphql/introspection/entry_points.rb +11 -18
  88. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  89. data/lib/graphql/introspection/field_type.rb +4 -4
  90. data/lib/graphql/introspection/input_value_type.rb +10 -4
  91. data/lib/graphql/introspection/schema_type.rb +17 -15
  92. data/lib/graphql/introspection/type_type.rb +29 -16
  93. data/lib/graphql/introspection.rb +6 -2
  94. data/lib/graphql/invalid_null_error.rb +1 -1
  95. data/lib/graphql/language/block_string.rb +37 -25
  96. data/lib/graphql/language/cache.rb +13 -0
  97. data/lib/graphql/language/comment.rb +18 -0
  98. data/lib/graphql/language/definition_slice.rb +1 -1
  99. data/lib/graphql/language/document_from_schema_definition.rb +122 -81
  100. data/lib/graphql/language/lexer.rb +364 -1467
  101. data/lib/graphql/language/nodes.rb +197 -106
  102. data/lib/graphql/language/parser.rb +799 -1920
  103. data/lib/graphql/language/printer.rb +372 -160
  104. data/lib/graphql/language/sanitized_printer.rb +25 -27
  105. data/lib/graphql/language/static_visitor.rb +167 -0
  106. data/lib/graphql/language/visitor.rb +188 -141
  107. data/lib/graphql/language.rb +62 -1
  108. data/lib/graphql/load_application_object_failed_error.rb +5 -1
  109. data/lib/graphql/name_validator.rb +0 -4
  110. data/lib/graphql/pagination/active_record_relation_connection.rb +37 -8
  111. data/lib/graphql/pagination/array_connection.rb +8 -6
  112. data/lib/graphql/pagination/connection.rb +61 -7
  113. data/lib/graphql/pagination/connections.rb +22 -23
  114. data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
  115. data/lib/graphql/pagination/relation_connection.rb +60 -28
  116. data/lib/graphql/query/context/scoped_context.rb +101 -0
  117. data/lib/graphql/query/context.rb +146 -222
  118. data/lib/graphql/query/input_validation_result.rb +10 -1
  119. data/lib/graphql/query/null_context.rb +15 -32
  120. data/lib/graphql/query/validation_pipeline.rb +15 -39
  121. data/lib/graphql/query/variable_validation_error.rb +3 -3
  122. data/lib/graphql/query/variables.rb +35 -17
  123. data/lib/graphql/query.rb +149 -82
  124. data/lib/graphql/railtie.rb +15 -109
  125. data/lib/graphql/rake_task/validate.rb +1 -1
  126. data/lib/graphql/rake_task.rb +30 -11
  127. data/lib/graphql/relay/range_add.rb +9 -16
  128. data/lib/graphql/relay.rb +0 -15
  129. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  130. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  131. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  132. data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
  133. data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
  134. data/lib/graphql/rubocop.rb +6 -0
  135. data/lib/graphql/schema/addition.rb +98 -54
  136. data/lib/graphql/schema/always_visible.rb +14 -0
  137. data/lib/graphql/schema/argument.rb +179 -82
  138. data/lib/graphql/schema/base_64_encoder.rb +3 -5
  139. data/lib/graphql/schema/build_from_definition.rb +77 -39
  140. data/lib/graphql/schema/directive/feature.rb +1 -1
  141. data/lib/graphql/schema/directive/flagged.rb +4 -4
  142. data/lib/graphql/schema/directive/include.rb +1 -1
  143. data/lib/graphql/schema/directive/one_of.rb +24 -0
  144. data/lib/graphql/schema/directive/skip.rb +1 -1
  145. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  146. data/lib/graphql/schema/directive/transform.rb +2 -2
  147. data/lib/graphql/schema/directive.rb +36 -22
  148. data/lib/graphql/schema/enum.rb +158 -63
  149. data/lib/graphql/schema/enum_value.rb +12 -21
  150. data/lib/graphql/schema/field/connection_extension.rb +7 -17
  151. data/lib/graphql/schema/field/scope_extension.rb +8 -1
  152. data/lib/graphql/schema/field.rb +521 -359
  153. data/lib/graphql/schema/field_extension.rb +86 -2
  154. data/lib/graphql/schema/find_inherited_value.rb +3 -7
  155. data/lib/graphql/schema/finder.rb +5 -5
  156. data/lib/graphql/schema/has_single_input_argument.rb +160 -0
  157. data/lib/graphql/schema/input_object.rb +148 -99
  158. data/lib/graphql/schema/interface.rb +41 -64
  159. data/lib/graphql/schema/introspection_system.rb +12 -26
  160. data/lib/graphql/schema/late_bound_type.rb +12 -2
  161. data/lib/graphql/schema/list.rb +18 -7
  162. data/lib/graphql/schema/loader.rb +6 -5
  163. data/lib/graphql/schema/member/base_dsl_methods.rb +32 -18
  164. data/lib/graphql/schema/member/build_type.rb +16 -13
  165. data/lib/graphql/schema/member/has_arguments.rb +270 -86
  166. data/lib/graphql/schema/member/has_ast_node.rb +12 -0
  167. data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
  168. data/lib/graphql/schema/member/has_directives.rb +81 -61
  169. data/lib/graphql/schema/member/has_fields.rb +169 -31
  170. data/lib/graphql/schema/member/has_interfaces.rb +143 -0
  171. data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
  172. data/lib/graphql/schema/member/has_validators.rb +32 -6
  173. data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
  174. data/lib/graphql/schema/member/scoped.rb +19 -0
  175. data/lib/graphql/schema/member/type_system_helpers.rb +16 -0
  176. data/lib/graphql/schema/member/validates_input.rb +6 -6
  177. data/lib/graphql/schema/member.rb +1 -6
  178. data/lib/graphql/schema/mutation.rb +7 -9
  179. data/lib/graphql/schema/non_null.rb +7 -7
  180. data/lib/graphql/schema/object.rb +38 -119
  181. data/lib/graphql/schema/printer.rb +24 -25
  182. data/lib/graphql/schema/relay_classic_mutation.rb +13 -91
  183. data/lib/graphql/schema/resolver/has_payload_type.rb +46 -11
  184. data/lib/graphql/schema/resolver.rb +118 -115
  185. data/lib/graphql/schema/scalar.rb +20 -21
  186. data/lib/graphql/schema/subscription.rb +95 -21
  187. data/lib/graphql/schema/timeout.rb +25 -29
  188. data/lib/graphql/schema/type_expression.rb +2 -2
  189. data/lib/graphql/schema/type_membership.rb +21 -4
  190. data/lib/graphql/schema/union.rb +16 -16
  191. data/lib/graphql/schema/unique_within_type.rb +1 -1
  192. data/lib/graphql/schema/validator/all_validator.rb +62 -0
  193. data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
  194. data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
  195. data/lib/graphql/schema/validator/exclusion_validator.rb +3 -1
  196. data/lib/graphql/schema/validator/format_validator.rb +4 -5
  197. data/lib/graphql/schema/validator/inclusion_validator.rb +3 -1
  198. data/lib/graphql/schema/validator/length_validator.rb +5 -3
  199. data/lib/graphql/schema/validator/numericality_validator.rb +13 -2
  200. data/lib/graphql/schema/validator/required_validator.rb +56 -18
  201. data/lib/graphql/schema/validator.rb +38 -28
  202. data/lib/graphql/schema/visibility/migration.rb +188 -0
  203. data/lib/graphql/schema/visibility/profile.rb +359 -0
  204. data/lib/graphql/schema/visibility/visit.rb +190 -0
  205. data/lib/graphql/schema/visibility.rb +294 -0
  206. data/lib/graphql/schema/warden.rb +423 -134
  207. data/lib/graphql/schema/wrapper.rb +0 -5
  208. data/lib/graphql/schema.rb +1015 -1057
  209. data/lib/graphql/static_validation/all_rules.rb +3 -1
  210. data/lib/graphql/static_validation/base_visitor.rb +15 -28
  211. data/lib/graphql/static_validation/definition_dependencies.rb +7 -2
  212. data/lib/graphql/static_validation/error.rb +3 -1
  213. data/lib/graphql/static_validation/literal_validator.rb +24 -7
  214. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  215. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
  216. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +4 -3
  217. data/lib/graphql/static_validation/rules/directives_are_defined.rb +13 -7
  218. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +15 -13
  219. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
  220. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +13 -5
  221. data/lib/graphql/static_validation/rules/fields_will_merge.rb +62 -35
  222. data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
  223. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  224. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
  225. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
  226. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  227. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  228. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
  229. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
  230. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
  231. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  232. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  233. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +7 -5
  234. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
  235. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
  236. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +14 -8
  237. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
  238. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
  239. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +14 -8
  240. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
  241. data/lib/graphql/static_validation/validation_context.rb +32 -6
  242. data/lib/graphql/static_validation/validator.rb +11 -27
  243. data/lib/graphql/static_validation.rb +0 -3
  244. data/lib/graphql/string_encoding_error.rb +13 -3
  245. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +49 -11
  246. data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
  247. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +40 -1
  248. data/lib/graphql/subscriptions/event.rb +87 -38
  249. data/lib/graphql/subscriptions/serialize.rb +27 -3
  250. data/lib/graphql/subscriptions.rb +63 -49
  251. data/lib/graphql/testing/helpers.rb +155 -0
  252. data/lib/graphql/testing.rb +2 -0
  253. data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
  254. data/lib/graphql/tracing/active_support_notifications_tracing.rb +6 -20
  255. data/lib/graphql/tracing/appoptics_trace.rb +253 -0
  256. data/lib/graphql/tracing/appoptics_tracing.rb +4 -2
  257. data/lib/graphql/tracing/appsignal_trace.rb +79 -0
  258. data/lib/graphql/tracing/appsignal_tracing.rb +17 -0
  259. data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
  260. data/lib/graphql/tracing/data_dog_trace.rb +185 -0
  261. data/lib/graphql/tracing/data_dog_tracing.rb +27 -15
  262. data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +11 -28
  263. data/lib/graphql/tracing/legacy_trace.rb +12 -0
  264. data/lib/graphql/tracing/new_relic_trace.rb +77 -0
  265. data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
  266. data/lib/graphql/tracing/notifications_trace.rb +45 -0
  267. data/lib/graphql/tracing/notifications_tracing.rb +61 -0
  268. data/lib/graphql/tracing/null_trace.rb +9 -0
  269. data/lib/graphql/tracing/platform_trace.rb +118 -0
  270. data/lib/graphql/tracing/platform_tracing.rb +46 -49
  271. data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +6 -2
  272. data/lib/graphql/tracing/prometheus_trace.rb +94 -0
  273. data/lib/graphql/tracing/prometheus_tracing.rb +5 -3
  274. data/lib/graphql/tracing/scout_trace.rb +74 -0
  275. data/lib/graphql/tracing/scout_tracing.rb +2 -0
  276. data/lib/graphql/tracing/sentry_trace.rb +114 -0
  277. data/lib/graphql/tracing/statsd_trace.rb +58 -0
  278. data/lib/graphql/tracing/statsd_tracing.rb +2 -0
  279. data/lib/graphql/tracing/trace.rb +79 -0
  280. data/lib/graphql/tracing.rb +29 -52
  281. data/lib/graphql/type_kinds.rb +7 -4
  282. data/lib/graphql/types/big_int.rb +5 -1
  283. data/lib/graphql/types/int.rb +1 -1
  284. data/lib/graphql/types/iso_8601_date.rb +17 -6
  285. data/lib/graphql/types/iso_8601_date_time.rb +12 -1
  286. data/lib/graphql/types/iso_8601_duration.rb +77 -0
  287. data/lib/graphql/types/relay/base_connection.rb +16 -6
  288. data/lib/graphql/types/relay/connection_behaviors.rb +92 -32
  289. data/lib/graphql/types/relay/edge_behaviors.rb +46 -7
  290. data/lib/graphql/types/relay/has_node_field.rb +2 -2
  291. data/lib/graphql/types/relay/has_nodes_field.rb +2 -2
  292. data/lib/graphql/types/relay/node_behaviors.rb +12 -2
  293. data/lib/graphql/types/relay/page_info_behaviors.rb +11 -2
  294. data/lib/graphql/types/relay.rb +0 -3
  295. data/lib/graphql/types/string.rb +2 -2
  296. data/lib/graphql/types.rb +18 -10
  297. data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
  298. data/lib/graphql/unauthorized_error.rb +1 -1
  299. data/lib/graphql/version.rb +1 -1
  300. data/lib/graphql.rb +82 -137
  301. data/readme.md +13 -6
  302. metadata +127 -186
  303. data/lib/graphql/analysis/analyze_query.rb +0 -98
  304. data/lib/graphql/analysis/ast/analyzer.rb +0 -84
  305. data/lib/graphql/analysis/ast/field_usage.rb +0 -28
  306. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -23
  307. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  308. data/lib/graphql/analysis/ast/query_complexity.rb +0 -234
  309. data/lib/graphql/analysis/ast/query_depth.rb +0 -56
  310. data/lib/graphql/analysis/ast/visitor.rb +0 -268
  311. data/lib/graphql/analysis/ast.rb +0 -91
  312. data/lib/graphql/analysis/reducer_state.rb +0 -48
  313. data/lib/graphql/argument.rb +0 -131
  314. data/lib/graphql/authorization.rb +0 -82
  315. data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
  316. data/lib/graphql/backwards_compatibility.rb +0 -61
  317. data/lib/graphql/base_type.rb +0 -230
  318. data/lib/graphql/boolean_type.rb +0 -2
  319. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
  320. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
  321. data/lib/graphql/compatibility/execution_specification.rb +0 -436
  322. data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
  323. data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
  324. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
  325. data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
  326. data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
  327. data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
  328. data/lib/graphql/compatibility.rb +0 -5
  329. data/lib/graphql/define/assign_argument.rb +0 -12
  330. data/lib/graphql/define/assign_connection.rb +0 -13
  331. data/lib/graphql/define/assign_enum_value.rb +0 -18
  332. data/lib/graphql/define/assign_global_id_field.rb +0 -11
  333. data/lib/graphql/define/assign_mutation_function.rb +0 -34
  334. data/lib/graphql/define/assign_object_field.rb +0 -42
  335. data/lib/graphql/define/defined_object_proxy.rb +0 -53
  336. data/lib/graphql/define/instance_definable.rb +0 -240
  337. data/lib/graphql/define/no_definition_error.rb +0 -7
  338. data/lib/graphql/define/non_null_with_bang.rb +0 -16
  339. data/lib/graphql/define/type_definer.rb +0 -31
  340. data/lib/graphql/define.rb +0 -31
  341. data/lib/graphql/deprecated_dsl.rb +0 -47
  342. data/lib/graphql/deprecation.rb +0 -13
  343. data/lib/graphql/directive/deprecated_directive.rb +0 -2
  344. data/lib/graphql/directive/include_directive.rb +0 -2
  345. data/lib/graphql/directive/skip_directive.rb +0 -2
  346. data/lib/graphql/directive.rb +0 -111
  347. data/lib/graphql/enum_type.rb +0 -129
  348. data/lib/graphql/execution/execute.rb +0 -333
  349. data/lib/graphql/execution/flatten.rb +0 -40
  350. data/lib/graphql/execution/lazy/resolve.rb +0 -91
  351. data/lib/graphql/execution/typecast.rb +0 -50
  352. data/lib/graphql/field/resolve.rb +0 -59
  353. data/lib/graphql/field.rb +0 -226
  354. data/lib/graphql/filter.rb +0 -53
  355. data/lib/graphql/float_type.rb +0 -2
  356. data/lib/graphql/function.rb +0 -128
  357. data/lib/graphql/id_type.rb +0 -2
  358. data/lib/graphql/input_object_type.rb +0 -138
  359. data/lib/graphql/int_type.rb +0 -2
  360. data/lib/graphql/interface_type.rb +0 -72
  361. data/lib/graphql/internal_representation/document.rb +0 -27
  362. data/lib/graphql/internal_representation/node.rb +0 -206
  363. data/lib/graphql/internal_representation/print.rb +0 -51
  364. data/lib/graphql/internal_representation/rewrite.rb +0 -184
  365. data/lib/graphql/internal_representation/scope.rb +0 -88
  366. data/lib/graphql/internal_representation/visit.rb +0 -36
  367. data/lib/graphql/internal_representation.rb +0 -7
  368. data/lib/graphql/language/lexer.rl +0 -262
  369. data/lib/graphql/language/parser.y +0 -543
  370. data/lib/graphql/language/token.rb +0 -38
  371. data/lib/graphql/list_type.rb +0 -80
  372. data/lib/graphql/non_null_type.rb +0 -71
  373. data/lib/graphql/object_type.rb +0 -130
  374. data/lib/graphql/query/arguments.rb +0 -189
  375. data/lib/graphql/query/arguments_cache.rb +0 -24
  376. data/lib/graphql/query/executor.rb +0 -52
  377. data/lib/graphql/query/literal_input.rb +0 -136
  378. data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
  379. data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
  380. data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
  381. data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
  382. data/lib/graphql/query/serial_execution.rb +0 -40
  383. data/lib/graphql/relay/array_connection.rb +0 -83
  384. data/lib/graphql/relay/base_connection.rb +0 -189
  385. data/lib/graphql/relay/connection_instrumentation.rb +0 -54
  386. data/lib/graphql/relay/connection_resolve.rb +0 -43
  387. data/lib/graphql/relay/connection_type.rb +0 -41
  388. data/lib/graphql/relay/edge.rb +0 -27
  389. data/lib/graphql/relay/edge_type.rb +0 -19
  390. data/lib/graphql/relay/edges_instrumentation.rb +0 -40
  391. data/lib/graphql/relay/global_id_resolve.rb +0 -18
  392. data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
  393. data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
  394. data/lib/graphql/relay/mutation/resolve.rb +0 -56
  395. data/lib/graphql/relay/mutation/result.rb +0 -38
  396. data/lib/graphql/relay/mutation.rb +0 -106
  397. data/lib/graphql/relay/node.rb +0 -39
  398. data/lib/graphql/relay/page_info.rb +0 -7
  399. data/lib/graphql/relay/relation_connection.rb +0 -188
  400. data/lib/graphql/relay/type_extensions.rb +0 -32
  401. data/lib/graphql/scalar_type.rb +0 -91
  402. data/lib/graphql/schema/base_64_bp.rb +0 -26
  403. data/lib/graphql/schema/catchall_middleware.rb +0 -35
  404. data/lib/graphql/schema/default_parse_error.rb +0 -10
  405. data/lib/graphql/schema/default_type_error.rb +0 -17
  406. data/lib/graphql/schema/invalid_type_error.rb +0 -7
  407. data/lib/graphql/schema/member/accepts_definition.rb +0 -152
  408. data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -31
  409. data/lib/graphql/schema/member/instrumentation.rb +0 -131
  410. data/lib/graphql/schema/middleware_chain.rb +0 -82
  411. data/lib/graphql/schema/possible_types.rb +0 -44
  412. data/lib/graphql/schema/rescue_middleware.rb +0 -60
  413. data/lib/graphql/schema/timeout_middleware.rb +0 -88
  414. data/lib/graphql/schema/traversal.rb +0 -228
  415. data/lib/graphql/schema/validation.rb +0 -313
  416. data/lib/graphql/static_validation/default_visitor.rb +0 -15
  417. data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
  418. data/lib/graphql/static_validation/type_stack.rb +0 -216
  419. data/lib/graphql/string_type.rb +0 -2
  420. data/lib/graphql/subscriptions/instrumentation.rb +0 -79
  421. data/lib/graphql/subscriptions/subscription_root.rb +0 -76
  422. data/lib/graphql/tracing/skylight_tracing.rb +0 -70
  423. data/lib/graphql/types/relay/default_relay.rb +0 -27
  424. data/lib/graphql/types/relay/node_field.rb +0 -25
  425. data/lib/graphql/types/relay/nodes_field.rb +0 -27
  426. data/lib/graphql/union_type.rb +0 -115
  427. data/lib/graphql/upgrader/member.rb +0 -937
  428. 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