Module: GraphQL::Doctor::Runtime::Dump

Defined in:
lib/graphql/doctor/runtime/dump.rb

Class Method Summary collapse

Class Method Details

.callback_locations?(field) ⇒ Boolean

Returns:

  • (Boolean)


107
108
109
110
111
# File 'lib/graphql/doctor/runtime/dump.rb', line 107

def callback_locations?(field)
  callbacks = field.fetch("callback_source_locations", {})
  callbacks.is_a?(Hash) && callbacks.keys.all? { |name| %w[ready? authorized?].include?(name) } &&
    callbacks.values.all? { |location| source_location?(location) }
end

.callback_signatures?(field) ⇒ Boolean

Returns:

  • (Boolean)


113
114
115
116
117
# File 'lib/graphql/doctor/runtime/dump.rb', line 113

def callback_signatures?(field)
  callbacks = field.fetch("callback_signatures", {})
  callbacks.is_a?(Hash) && callbacks.keys.all? { |name| %w[ready? authorized?].include?(name) } &&
    callbacks.values.all? { |signature| method_signature?(signature) }
end

.method_signature?(signature) ⇒ Boolean

Returns:

  • (Boolean)


119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/graphql/doctor/runtime/dump.rb', line 119

def method_signature?(signature)
  return true if signature.nil?
  return false unless signature.is_a?(Hash)
  return false unless %w[public protected private].include?(signature["visibility"])
  return false unless %w[required_keywords optional_keywords].all? do |key|
    signature[key].is_a?(Array) && signature[key].all?(String)
  end
  return false unless %w[accepts_keyword_rest accepts_positional_rest].all? do |key|
    [true, false].include?(signature[key])
  end

  %w[required_positionals optional_positionals].all? do |key|
    signature[key].is_a?(Integer) && signature[key] >= 0
  end
end

.optional_boolean?(value, key) ⇒ Boolean

Returns:

  • (Boolean)


99
100
101
# File 'lib/graphql/doctor/runtime/dump.rb', line 99

def optional_boolean?(value, key)
  !value.key?(key) || value[key].nil? || value[key] == true || value[key] == false
end

.optional_string?(value, key) ⇒ Boolean

Returns:

  • (Boolean)


95
96
97
# File 'lib/graphql/doctor/runtime/dump.rb', line 95

def optional_string?(value, key)
  !value.key?(key) || value[key].nil? || value[key].is_a?(String)
end

.read(path) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/graphql/doctor/runtime/dump.rb', line 16

def read(path)
  value = JSON.parse(File.read(path))
  raise Error, "Schema dump must be an object" unless value.is_a?(Hash)
  raise Error, "Unsupported schema dump version: #{value['version']}" unless value["version"] == 1
  raise Error, "Schema dump types must be an array" unless value["types"].is_a?(Array)

  validate_types(value["types"])
  orphans = value.fetch("orphan_members", [])
  unless orphans.is_a?(Array) && orphans.all?(String)
    raise Error, "Schema dump orphan_members must be an array of strings"
  end

  value
rescue JSON::ParserError, SystemCallError => e
  raise Error, "Invalid schema dump: #{e.message}"
end

.source_location?(value) ⇒ Boolean

Returns:

  • (Boolean)


103
104
105
# File 'lib/graphql/doctor/runtime/dump.rb', line 103

def source_location?(value)
  value.nil? || (value.is_a?(Array) && value.length == 2 && value[0].is_a?(String) && value[1].is_a?(Integer))
end

.valid_argument?(argument) ⇒ Boolean

Returns:

  • (Boolean)


82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/graphql/doctor/runtime/dump.rb', line 82

def valid_argument?(argument)
  return false unless argument.is_a?(Hash)
  return false unless %w[graphql_name keyword].all? { |key| argument[key].is_a?(String) }
  return false unless %w[type loads as prepare].all? { |key| optional_string?(argument, key) }
  return false unless source_location?(argument["prepare_source_location"])
  return false unless optional_boolean?(argument, "prepare_method_valid")
  return false unless [nil, "object", "resolver"].include?(argument["prepare_method_dispatch"])

  %w[non_null required has_default].all? do |key|
    !argument.key?(key) || argument[key] == true || argument[key] == false
  end
end

.validate_field(field) ⇒ Object

Raises:



46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/graphql/doctor/runtime/dump.rb', line 46

def validate_field(field)
  keys = %w[owner graphql_name method_sym resolver_method]
  valid = field.is_a?(Hash) && keys.all? { |key| field[key].is_a?(String) }
  raise Error, "Schema dump field is invalid" unless valid

  validate_field_values(field)

  arguments = field.fetch("arguments", [])
  validate_field_collections(arguments, field.fetch("extras", []), field.fetch("extensions", []))
  return if arguments.all? { |argument| valid_argument?(argument) }

  raise Error, "Schema dump argument is invalid"
end

.validate_field_collections(arguments, extras, extensions) ⇒ Object



74
75
76
77
78
79
80
# File 'lib/graphql/doctor/runtime/dump.rb', line 74

def validate_field_collections(arguments, extras, extensions)
  unless arguments.is_a?(Array) && [extras, extensions].all? do |items|
    items.is_a?(Array) && items.all?(String)
  end
    raise Error, "Schema dump field collections must be arrays"
  end
end

.validate_field_values(field) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/graphql/doctor/runtime/dump.rb', line 60

def validate_field_values(field)
  unless %w[resolver_class type hash_key underlying_object_class].all? do |key|
    optional_string?(field, key)
  end
    raise Error, "Schema dump field values are invalid"
  end
  unless source_location?(field["resolver_source_location"]) &&
         optional_boolean?(field, "underlying_method_defined") &&
         method_signature?(field["resolver_signature"]) &&
         callback_locations?(field) && callback_signatures?(field)
    raise Error, "Schema dump field values are invalid"
  end
end

.validate_type(type) ⇒ Object

Raises:



37
38
39
40
41
42
43
44
# File 'lib/graphql/doctor/runtime/dump.rb', line 37

def validate_type(type)
  raise Error, "Schema dump type must be an object" unless type.is_a?(Hash)

  fields = type.fetch("fields", [])
  raise Error, "Schema dump fields must be an array" unless fields.is_a?(Array)

  fields.each { |field| validate_field(field) }
end

.validate_types(types) ⇒ Object



33
34
35
# File 'lib/graphql/doctor/runtime/dump.rb', line 33

def validate_types(types)
  types.each { |type| validate_type(type) }
end

.write(runtime_ir, io) ⇒ Object



11
12
13
14
# File 'lib/graphql/doctor/runtime/dump.rb', line 11

def write(runtime_ir, io)
  io.write(JSON.pretty_generate(runtime_ir))
  io.write("\n")
end