lib/graphql/schema/printer.rb in graphql-1.3.0 vs lib/graphql/schema/printer.rb in graphql-1.4.0

- old
+ new

@@ -9,75 +9,96 @@ # module Printer extend self # Return a GraphQL schema string for the defined types in the schema + # @param context [Hash] + # @param only [<#call(member, ctx)>] + # @param except [<#call(member, ctx)>] # @param schema [GraphQL::Schema] - def print_schema(schema) - print_filtered_schema(schema, lambda { |n| !is_spec_directive(n) }, method(:is_defined_type)) + def print_schema(schema, context: nil, only: nil, except: nil) + blacklist = if only + ->(m, ctx) { !(IS_USER_DEFINED_MEMBER.call(m) && only.call(m, ctx)) } + elsif except + ->(m, ctx) { !IS_USER_DEFINED_MEMBER.call(m) || except.call(m, ctx) } + else + ->(m, ctx) { !IS_USER_DEFINED_MEMBER.call(m) } + end + + warden = GraphQL::Schema::Warden.new(blacklist, schema: schema, context: context) + + print_filtered_schema(schema, warden: warden) end # Return the GraphQL schema string for the introspection type system def print_introspection_schema - query_root = ObjectType.define do - name "Root" - end + query_root = ObjectType.define(name: "Root") schema = GraphQL::Schema.define(query: query_root) - print_filtered_schema(schema, method(:is_spec_directive), method(:is_introspection_type)) + blacklist = ->(m, ctx) { m == query_root } + + warden = GraphQL::Schema::Warden.new(blacklist, schema: schema, context: nil) + + print_filtered_schema(schema, warden: warden) end private - def print_filtered_schema(schema, directive_filter, type_filter) - directives = schema.directives.values.select{ |directive| directive_filter.call(directive) } - directive_definitions = directives.map{ |directive| print_directive(directive) } + # By default, these are included in a schema printout + IS_USER_DEFINED_MEMBER = ->(member) { + case member + when GraphQL::BaseType + !member.introspection? + when GraphQL::Directive + !member.default_directive? + else + true + end + } - types = schema.types.values.select{ |type| type_filter.call(type) }.sort_by(&:name) - type_definitions = types.map{ |type| print_type(type) } + private_constant :IS_USER_DEFINED_MEMBER - [print_schema_definition(schema)].compact + def print_filtered_schema(schema, warden:) + directive_definitions = warden.directives.map { |directive| print_directive(warden, directive) } + + printable_types = warden.types.reject(&:default_scalar?) + + type_definitions = printable_types + .sort_by(&:name) + .map { |type| print_type(warden, type) } + + [print_schema_definition(warden, schema)].compact .concat(directive_definitions) .concat(type_definitions).join("\n\n") end - def print_schema_definition(schema) + def print_schema_definition(warden, schema) if (schema.query.nil? || schema.query.name == 'Query') && (schema.mutation.nil? || schema.mutation.name == 'Mutation') && (schema.subscription.nil? || schema.subscription.name == 'Subscription') return end operations = [:query, :mutation, :subscription].map do |operation_type| object_type = schema.public_send(operation_type) - " #{operation_type}: #{object_type.name}\n" if object_type + # Special treatment for the introspection schema, which prints `{ query: "Root" }` + if object_type && (warden.get_type(object_type.name) || (object_type.name == "Root" && schema.query == object_type)) + " #{operation_type}: #{object_type.name}\n" + else + nil + end end.compact.join "schema {\n#{operations}}" end - BUILTIN_SCALARS = Set.new(["String", "Boolean", "Int", "Float", "ID"]) - private_constant :BUILTIN_SCALARS - - def is_spec_directive(directive) - ['skip', 'include', 'deprecated'].include?(directive.name) + def print_type(warden, type) + TypeKindPrinters::STRATEGIES.fetch(type.kind).print(warden, type) end - def is_introspection_type(type) - type.name.start_with?("__") + def print_directive(warden, directive) + TypeKindPrinters::DirectivePrinter.print(warden, directive) end - def is_defined_type(type) - !is_introspection_type(type) && !BUILTIN_SCALARS.include?(type.name) - end - - def print_type(type) - TypeKindPrinters::STRATEGIES.fetch(type.kind).print(type) - end - - def print_directive(directive) - TypeKindPrinters::DirectivePrinter.print(directive) - end - module TypeKindPrinters module DeprecatedPrinter def print_deprecated(field_or_enum_value) return unless field_or_enum_value.deprecation_reason @@ -101,21 +122,20 @@ end end module ArgsPrinter include DescriptionPrinter - def print_args(field, indentation = '') - return if field.arguments.empty? + def print_args(warden, field, indentation = '') + arguments = warden.arguments(field) + return if arguments.empty? - field_arguments = field.arguments.values - - if field_arguments.all?{ |arg| !arg.description } - return "(#{field_arguments.map{ |arg| print_input_value(arg) }.join(", ")})" + if arguments.all?{ |arg| !arg.description } + return "(#{arguments.map{ |arg| print_input_value(arg) }.join(", ")})" end out = "(\n".dup - out << field_arguments.map.with_index{ |arg, i| + out << arguments.map.with_index{ |arg, i| "#{print_description(arg, " #{indentation}", i == 0)} #{indentation}"\ "#{print_input_value(arg)}" }.join("\n") out << "\n#{indentation})" end @@ -167,88 +187,94 @@ module FieldPrinter include DeprecatedPrinter include ArgsPrinter include DescriptionPrinter - def print_fields(type) - type.all_fields.map.with_index { |field, i| + def print_fields(warden, type) + fields = warden.fields(type) + fields.map.with_index { |field, i| "#{print_description(field, ' ', i == 0)}"\ - " #{field.name}#{print_args(field, ' ')}: #{field.type}#{print_deprecated(field)}" + " #{field.name}#{print_args(warden, field, ' ')}: #{field.type}#{print_deprecated(field)}" }.join("\n") end end class DirectivePrinter extend ArgsPrinter extend DescriptionPrinter - def self.print(directive) + def self.print(warden, directive) "#{print_description(directive)}"\ - "directive @#{directive.name}#{print_args(directive)} "\ + "directive @#{directive.name}#{print_args(warden, directive)} "\ "on #{directive.locations.join(' | ')}" end end class ScalarPrinter extend DescriptionPrinter - def self.print(type) + def self.print(warden, type) "#{print_description(type)}"\ "scalar #{type.name}" end end class ObjectPrinter extend FieldPrinter extend DescriptionPrinter - def self.print(type) - if type.interfaces.any? - implementations = " implements #{type.interfaces.map(&:to_s).join(", ")}" + def self.print(warden, type) + interfaces = warden.interfaces(type) + if interfaces.any? + implementations = " implements #{interfaces.map(&:to_s).join(", ")}" else implementations = nil end "#{print_description(type)}"\ "type #{type.name}#{implementations} {\n"\ - "#{print_fields(type)}\n"\ + "#{print_fields(warden, type)}\n"\ "}" end end class InterfacePrinter extend FieldPrinter extend DescriptionPrinter - def self.print(type) + def self.print(warden, type) "#{print_description(type)}"\ - "interface #{type.name} {\n#{print_fields(type)}\n}" + "interface #{type.name} {\n#{print_fields(warden, type)}\n}" end end class UnionPrinter extend DescriptionPrinter - def self.print(type) + def self.print(warden, type) + possible_types = warden.possible_types(type) "#{print_description(type)}"\ - "union #{type.name} = #{type.possible_types.map(&:to_s).join(" | ")}" + "union #{type.name} = #{possible_types.map(&:to_s).join(" | ")}" end end class EnumPrinter extend DeprecatedPrinter extend DescriptionPrinter - def self.print(type) - values = type.values.values.map{ |v| " #{v.name}#{print_deprecated(v)}" }.join("\n") - values = type.values.values.map.with_index { |v, i| + def self.print(warden, type) + enum_values = warden.enum_values(type) + + values = enum_values.map.with_index { |v, i| "#{print_description(v, ' ', i == 0)}"\ " #{v.name}#{print_deprecated(v)}" }.join("\n") + "#{print_description(type)}"\ "enum #{type.name} {\n#{values}\n}" end end class InputObjectPrinter extend FieldPrinter extend DescriptionPrinter - def self.print(type) - fields = type.input_fields.values.map.with_index{ |field, i| + def self.print(warden, type) + arguments = warden.arguments(type) + fields = arguments.map.with_index{ |field, i| "#{print_description(field, " ", i == 0)}"\ " #{print_input_value(field)}" }.join("\n") "#{print_description(type)}"\ "input #{type.name} {\n#{fields}\n}"