lib/graphql/language/printer.rb in graphql-2.0.31 vs lib/graphql/language/printer.rb in graphql-2.1.0
- old
+ new
@@ -1,9 +1,35 @@
# frozen_string_literal: true
module GraphQL
module Language
class Printer
+ OMISSION = "... (truncated)"
+
+ class TruncatableBuffer
+ class TruncateSizeReached < StandardError; end
+
+ DEFAULT_INIT_CAPACITY = 500
+
+ def initialize(truncate_size: nil)
+ @out = String.new(capacity: truncate_size || DEFAULT_INIT_CAPACITY)
+ @truncate_size = truncate_size
+ end
+
+ def append(other)
+ if @truncate_size && (@out.size + other.size) > @truncate_size
+ @out << other.slice(0, @truncate_size - @out.size)
+ raise(TruncateSizeReached, "Truncate size reached")
+ else
+ @out << other
+ end
+ end
+
+ def to_string
+ @out
+ end
+ end
+
# Turn an arbitrary AST node back into a string.
#
# @example Turning a document into a query string
# document = GraphQL.parse(query_string)
# GraphQL::Language::Printer.new.print(document)
@@ -12,125 +38,162 @@
#
# @example Building a custom printer
#
# class MyPrinter < GraphQL::Language::Printer
# def print_argument(arg)
- # "#{arg.name}: <HIDDEN>"
+ # print_string("#{arg.name}: <HIDDEN>")
# end
# end
#
# MyPrinter.new.print(document)
# # => "mutation { pay(creditCard: <HIDDEN>) { success } }"
#
- #
+ # @param node [Nodes::AbstractNode]
# @param indent [String] Whitespace to add to the printed node
+ # @param truncate_size [Integer, nil] The size to truncate to.
# @return [String] Valid GraphQL for `node`
- def print(node, indent: "")
+ def print(node, indent: "", truncate_size: nil)
+ truncate_size = truncate_size ? [truncate_size - OMISSION.size, 0].max : nil
+ @out = TruncatableBuffer.new(truncate_size: truncate_size)
print_node(node, indent: indent)
+ @out.to_string
+ rescue TruncatableBuffer::TruncateSizeReached
+ @out.to_string << OMISSION
end
protected
+ def print_string(str)
+ @out.append(str)
+ end
+
def print_document(document)
- document.definitions.map { |d| print_node(d) }.join("\n\n")
+ document.definitions.each_with_index do |d, i|
+ print_node(d)
+ print_string("\n\n") if i < document.definitions.size - 1
+ end
end
def print_argument(argument)
- "#{argument.name}: #{print_node(argument.value)}".dup
+ print_string("#{argument.name}: ")
+ print_node(argument.value)
end
+ def print_input_object(input_object)
+ print_string("{")
+ input_object.arguments.each_with_index do |a, i|
+ print_argument(a)
+ print_string(", ") if i < input_object.arguments.size - 1
+ end
+ print_string("}")
+ end
+
def print_directive(directive)
- out = "@#{directive.name}".dup
+ print_string("@#{directive.name}")
if directive.arguments.any?
- out << "(#{directive.arguments.map { |a| print_argument(a) }.join(", ")})"
+ print_string("(")
+ directive.arguments.each_with_index do |a, i|
+ print_argument(a)
+ print_string(", ") if i < directive.arguments.size - 1
+ end
+ print_string(")")
end
-
- out
end
def print_enum(enum)
- "#{enum.name}".dup
+ print_string(enum.name)
end
def print_null_value
- "null".dup
+ print_string("null")
end
def print_field(field, indent: "")
- out = "#{indent}".dup
- out << "#{field.alias}: " if field.alias
- out << "#{field.name}"
- out << "(#{field.arguments.map { |a| print_argument(a) }.join(", ")})" if field.arguments.any?
- out << print_directives(field.directives)
- out << print_selections(field.selections, indent: indent)
- out
+ print_string(indent)
+ print_string("#{field.alias}: ") if field.alias
+ print_string(field.name)
+ if field.arguments.any?
+ print_string("(")
+ field.arguments.each_with_index do |a, i|
+ print_argument(a)
+ print_string(", ") if i < field.arguments.size - 1
+ end
+ print_string(")")
+ end
+ print_directives(field.directives)
+ print_selections(field.selections, indent: indent)
end
def print_fragment_definition(fragment_def, indent: "")
- out = "#{indent}fragment #{fragment_def.name}".dup
+ print_string("#{indent}fragment #{fragment_def.name}")
if fragment_def.type
- out << " on #{print_node(fragment_def.type)}"
+ print_string(" on ")
+ print_node(fragment_def.type)
end
- out << print_directives(fragment_def.directives)
- out << print_selections(fragment_def.selections, indent: indent)
- out
+ print_directives(fragment_def.directives)
+ print_selections(fragment_def.selections, indent: indent)
end
def print_fragment_spread(fragment_spread, indent: "")
- out = "#{indent}...#{fragment_spread.name}".dup
- out << print_directives(fragment_spread.directives)
- out
+ print_string("#{indent}...#{fragment_spread.name}")
+ print_directives(fragment_spread.directives)
end
def print_inline_fragment(inline_fragment, indent: "")
- out = "#{indent}...".dup
+ print_string("#{indent}...")
if inline_fragment.type
- out << " on #{print_node(inline_fragment.type)}"
+ print_string(" on ")
+ print_node(inline_fragment.type)
end
- out << print_directives(inline_fragment.directives)
- out << print_selections(inline_fragment.selections, indent: indent)
- out
+ print_directives(inline_fragment.directives)
+ print_selections(inline_fragment.selections, indent: indent)
end
- def print_input_object(input_object)
- "{#{input_object.arguments.map { |a| print_argument(a) }.join(", ")}}"
- end
-
def print_list_type(list_type)
- "[#{print_node(list_type.of_type)}]".dup
+ print_string("[")
+ print_node(list_type.of_type)
+ print_string("]")
end
def print_non_null_type(non_null_type)
- "#{print_node(non_null_type.of_type)}!".dup
+ print_node(non_null_type.of_type)
+ print_string("!")
end
def print_operation_definition(operation_definition, indent: "")
- out = "#{indent}#{operation_definition.operation_type}".dup
- out << " #{operation_definition.name}" if operation_definition.name
+ print_string("#{indent}#{operation_definition.operation_type}")
+ print_string(" #{operation_definition.name}") if operation_definition.name
if operation_definition.variables.any?
- out << "(#{operation_definition.variables.map { |v| print_variable_definition(v) }.join(", ")})"
+ print_string("(")
+ operation_definition.variables.each_with_index do |v, i|
+ print_variable_definition(v)
+ print_string(", ") if i < operation_definition.variables.size - 1
+ end
+ print_string(")")
end
- out << print_directives(operation_definition.directives)
- out << print_selections(operation_definition.selections, indent: indent)
- out
+ print_directives(operation_definition.directives)
+ print_selections(operation_definition.selections, indent: indent)
end
def print_type_name(type_name)
- "#{type_name.name}".dup
+ print_string(type_name.name)
end
def print_variable_definition(variable_definition)
- out = "$#{variable_definition.name}: #{print_node(variable_definition.type)}".dup
- out << " = #{print_node(variable_definition.default_value)}" unless variable_definition.default_value.nil?
- out
+ print_string("$#{variable_definition.name}: ")
+ print_node(variable_definition.type)
+ unless variable_definition.default_value.nil?
+ print_string(" = ")
+ print_node(variable_definition.default_value)
+ end
end
def print_variable_identifier(variable_identifier)
- "$#{variable_identifier.name}".dup
+ print_string("$#{variable_identifier.name}")
end
def print_schema_definition(schema, extension: false)
has_conventional_names = (schema.query.nil? || schema.query == 'Query') &&
(schema.mutation.nil? || schema.mutation == 'Mutation') &&
@@ -138,179 +201,197 @@
if has_conventional_names && schema.directives.empty?
return
end
- out = extension ? "extend schema".dup : "schema".dup
+ extension ? print_string("extend schema") : print_string("schema")
+
if schema.directives.any?
schema.directives.each do |dir|
- out << "\n "
- out << print_node(dir)
+ print_string("\n ")
+ print_node(dir)
end
+
if !has_conventional_names
- out << "\n"
+ print_string("\n")
end
end
if !has_conventional_names
if schema.directives.empty?
- out << " "
+ print_string(" ")
end
- out << "{\n"
- out << " query: #{schema.query}\n" if schema.query
- out << " mutation: #{schema.mutation}\n" if schema.mutation
- out << " subscription: #{schema.subscription}\n" if schema.subscription
- out << "}"
+ print_string("{\n")
+ print_string(" query: #{schema.query}\n") if schema.query
+ print_string(" mutation: #{schema.mutation}\n") if schema.mutation
+ print_string(" subscription: #{schema.subscription}\n") if schema.subscription
+ print_string("}")
end
- out
end
+
def print_scalar_type_definition(scalar_type, extension: false)
- out = extension ? "extend ".dup : print_description(scalar_type)
- out << "scalar #{scalar_type.name}"
- out << print_directives(scalar_type.directives)
+ extension ? print_string("extend ") : print_description(scalar_type)
+ print_string("scalar #{scalar_type.name}")
+ print_directives(scalar_type.directives)
end
def print_object_type_definition(object_type, extension: false)
- out = extension ? "extend ".dup : print_description(object_type)
- out << "type #{object_type.name}"
- out << print_implements(object_type) unless object_type.interfaces.empty?
- out << print_directives(object_type.directives)
- out << print_field_definitions(object_type.fields)
+ extension ? print_string("extend ") : print_description(object_type)
+ print_string("type #{object_type.name}")
+ print_implements(object_type) unless object_type.interfaces.empty?
+ print_directives(object_type.directives)
+ print_field_definitions(object_type.fields)
end
def print_implements(type)
- " implements #{type.interfaces.map(&:name).join(" & ")}"
+ print_string(" implements #{type.interfaces.map(&:name).join(" & ")}")
end
def print_input_value_definition(input_value)
- out = "#{input_value.name}: #{print_node(input_value.type)}".dup
- out << " = #{print_node(input_value.default_value)}" unless input_value.default_value.nil?
- out << print_directives(input_value.directives)
+ print_string("#{input_value.name}: ")
+ print_node(input_value.type)
+ unless input_value.default_value.nil?
+ print_string(" = ")
+ print_node(input_value.default_value)
+ end
+ print_directives(input_value.directives)
end
def print_arguments(arguments, indent: "")
- if arguments.all?{ |arg| !arg.description }
- return "(#{arguments.map{ |arg| print_input_value_definition(arg) }.join(", ")})"
+ if arguments.all? { |arg| !arg.description }
+ print_string("(")
+ arguments.each_with_index do |arg, i|
+ print_input_value_definition(arg)
+ print_string(", ") if i < arguments.size - 1
+ end
+ print_string(")")
+ return
end
- out = "(\n".dup
- out << arguments.map.with_index{ |arg, i|
- "#{print_description(arg, indent: " " + indent, first_in_block: i == 0)} #{indent}"\
- "#{print_input_value_definition(arg)}"
- }.join("\n")
- out << "\n#{indent})"
+ print_string("(\n")
+ arguments.each_with_index do |arg, i|
+ print_description(arg, indent: " " + indent, first_in_block: i == 0)
+ print_string(" #{indent}")
+ print_input_value_definition(arg)
+ print_string("\n") if i < arguments.size - 1
+ end
+ print_string("\n#{indent})")
end
def print_field_definition(field)
- out = field.name.dup
+ print_string(field.name)
unless field.arguments.empty?
- out << print_arguments(field.arguments, indent: " ")
+ print_arguments(field.arguments, indent: " ")
end
- out << ": #{print_node(field.type)}"
- out << print_directives(field.directives)
+ print_string(": ")
+ print_node(field.type)
+ print_directives(field.directives)
end
def print_interface_type_definition(interface_type, extension: false)
- out = extension ? "extend ".dup : print_description(interface_type)
- out << "interface #{interface_type.name}"
- out << print_implements(interface_type) if interface_type.interfaces.any?
- out << print_directives(interface_type.directives)
- out << print_field_definitions(interface_type.fields)
+ extension ? print_string("extend ") : print_description(interface_type)
+ print_string("interface #{interface_type.name}")
+ print_implements(interface_type) if interface_type.interfaces.any?
+ print_directives(interface_type.directives)
+ print_field_definitions(interface_type.fields)
end
def print_union_type_definition(union_type, extension: false)
- out = extension ? "extend ".dup : print_description(union_type)
- out << "union #{union_type.name}"
- out << print_directives(union_type.directives)
- out << " = " + union_type.types.map(&:name).join(" | ")
+ extension ? print_string("extend ") : print_description(union_type)
+ print_string("union #{union_type.name}")
+ print_directives(union_type.directives)
+ print_string(" = #{union_type.types.map(&:name).join(" | ")}")
end
def print_enum_type_definition(enum_type, extension: false)
- out = extension ? "extend ".dup : print_description(enum_type)
- out << "enum #{enum_type.name}#{print_directives(enum_type.directives)} {\n"
+ extension ? print_string("extend ") : print_description(enum_type)
+ print_string("enum #{enum_type.name}")
+ print_directives(enum_type.directives)
+ print_string(" {\n")
enum_type.values.each.with_index do |value, i|
- out << print_description(value, indent: ' ', first_in_block: i == 0)
- out << print_enum_value_definition(value)
+ print_description(value, indent: " ", first_in_block: i == 0)
+ print_enum_value_definition(value)
end
- out << "}"
+ print_string("}")
end
def print_enum_value_definition(enum_value)
- out = " #{enum_value.name}".dup
- out << print_directives(enum_value.directives)
- out << "\n"
+ print_string(" #{enum_value.name}")
+ print_directives(enum_value.directives)
+ print_string("\n")
end
def print_input_object_type_definition(input_object_type, extension: false)
- out = extension ? "extend ".dup : print_description(input_object_type)
- out << "input #{input_object_type.name}"
- out << print_directives(input_object_type.directives)
+ extension ? print_string("extend ") : print_description(input_object_type)
+ print_string("input #{input_object_type.name}")
+ print_directives(input_object_type.directives)
if !input_object_type.fields.empty?
- out << " {\n"
+ print_string(" {\n")
input_object_type.fields.each.with_index do |field, i|
- out << print_description(field, indent: ' ', first_in_block: i == 0)
- out << " #{print_input_value_definition(field)}\n"
+ print_description(field, indent: " ", first_in_block: i == 0)
+ print_string(" ")
+ print_input_value_definition(field)
+ print_string("\n")
end
- out << "}"
+ print_string("}")
end
- out
end
def print_directive_definition(directive)
- out = print_description(directive)
- out << "directive @#{directive.name}"
+ print_description(directive)
+ print_string("directive @#{directive.name}")
if directive.arguments.any?
- out << print_arguments(directive.arguments)
+ print_arguments(directive.arguments)
end
if directive.repeatable
- out << " repeatable"
+ print_string(" repeatable")
end
- out << " on #{directive.locations.map(&:name).join(' | ')}"
+ print_string(" on #{directive.locations.map(&:name).join(" | ")}")
end
def print_description(node, indent: "", first_in_block: true)
- return ''.dup unless node.description
+ return unless node.description
- description = indent != '' && !first_in_block ? "\n".dup : "".dup
- description << GraphQL::Language::BlockString.print(node.description, indent: indent)
+ print_string("\n") if indent != "" && !first_in_block
+ print_string(GraphQL::Language::BlockString.print(node.description, indent: indent))
end
def print_field_definitions(fields)
- if fields.empty?
- ""
- else
- out = " {\n".dup
- fields.each.with_index do |field, i|
- out << print_description(field, indent: ' ', first_in_block: i == 0)
- out << " #{print_field_definition(field)}\n"
- end
- out << "}"
+ return if fields.empty?
+
+ print_string(" {\n")
+ fields.each.with_index do |field, i|
+ print_description(field, indent: " ", first_in_block: i == 0)
+ print_string(" ")
+ print_field_definition(field)
+ print_string("\n")
end
+ print_string("}")
end
def print_directives(directives)
- if directives.any?
- directives.map { |d| " #{print_directive(d)}" }.join
- else
- ""
+ return if directives.empty?
+
+ directives.each do |d|
+ print_string(" ")
+ print_directive(d)
end
end
def print_selections(selections, indent: "")
- if selections.any?
- out = " {\n".dup
- selections.each do |selection|
- out << print_node(selection, indent: indent + " ") << "\n"
- end
- out << "#{indent}}"
- else
- ""
+ return if selections.empty?
+
+ print_string(" {\n")
+ selections.each do |selection|
+ print_node(selection, indent: indent + " ")
+ print_string("\n")
end
+ print_string("#{indent}}")
end
def print_node(node, indent: "")
case node
when Nodes::Document
@@ -380,21 +461,28 @@
when Nodes::InputObjectTypeExtension
print_input_object_type_definition(node, extension: true)
when Nodes::DirectiveDefinition
print_directive_definition(node)
when FalseClass, Float, Integer, NilClass, String, TrueClass, Symbol
- GraphQL::Language.serialize(node)
+ print_string(GraphQL::Language.serialize(node))
when Array
- "[#{node.map { |v| print_node(v) }.join(", ")}]".dup
+ print_string("[")
+ node.each_with_index do |v, i|
+ print_node(v)
+ print_string(", ") if i < node.length - 1
+ end
+ print_string("]")
when Hash
- "{#{node.map { |k, v| "#{k}: #{print_node(v)}" }.join(", ")}}".dup
+ print_string("{")
+ node.each_with_index do |(k, v), i|
+ print_string("#{k}: ")
+ print_node(v)
+ print_string(", ") if i < node.length - 1
+ end
+ print_string("}")
else
- GraphQL::Language.serialize(node.to_s)
+ print_string(GraphQL::Language.serialize(node.to_s))
end
end
-
- private
-
- attr_reader :node
end
end
end