32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
# File 'lib/graphql/schema/visibility/visit.rb', line 32
def visit_each(types: entry_point_types, directives: entry_point_directives)
@unvisited_types && raise("Can't re-enter `visit_each` on this Visit (another visit is already in progress)")
@unvisited_types = types
@late_bound_types = []
directives_to_visit = directives
while @unvisited_types.any? || @late_bound_types.any?
while (type = @unvisited_types.pop)
if @visited_types.add?(type) && @visit_block.call(type)
directives_to_visit.concat(type.directives)
case type.kind.name
when "OBJECT", "INTERFACE"
type.interface_type_memberships.each do |itm|
append_unvisited_type(type, itm.abstract_type)
end
if type.kind.interface?
type.orphan_types.each do |orphan_type|
append_unvisited_type(type, orphan_type)
end
end
type.all_field_definitions.each do |field|
field.ensure_loaded
if @visit_block.call(field)
directives_to_visit.concat(field.directives)
append_unvisited_type(type, field.type.unwrap)
field.all_argument_definitions.each do |argument|
if @visit_block.call(argument)
directives_to_visit.concat(argument.directives)
append_unvisited_type(field, argument.type.unwrap)
end
end
end
end
when "INPUT_OBJECT"
type.all_argument_definitions.each do |argument|
if @visit_block.call(argument)
directives_to_visit.concat(argument.directives)
append_unvisited_type(type, argument.type.unwrap)
end
end
when "UNION"
type.type_memberships.each do |tm|
append_unvisited_type(type, tm.object_type)
end
when "ENUM"
type.all_enum_value_definitions.each do |val|
if @visit_block.call(val)
directives_to_visit.concat(val.directives)
end
end
when "SCALAR"
else
raise "Invariant: unhandled type kind: #{type.kind.inspect}"
end
end
end
directives_to_visit.each do |dir|
dir_class = dir.is_a?(Class) ? dir : dir.class
if @visited_directives.add?(dir_class) && @visit_block.call(dir_class)
dir_class.all_argument_definitions.each do |arg_defn|
if @visit_block.call(arg_defn)
directives_to_visit.concat(arg_defn.directives)
append_unvisited_type(dir_class, arg_defn.type.unwrap)
end
end
end
end
missed_late_types_streak = 0
while (owner, late_type = @late_bound_types.shift)
if (late_type.is_a?(String) && (type = Member::BuildType.constantize(type))) ||
(late_type.is_a?(LateBoundType) && (type = @visited_types.find { |t| t.graphql_name == late_type.graphql_name }))
missed_late_types_streak = 0 update_type_owner(owner, type)
append_unvisited_type(owner, type)
else
missed_late_types_streak += 1
@late_bound_types << [owner, late_type]
if missed_late_types_streak == @late_bound_types.size
raise UnresolvedLateBoundTypeError.new(type: late_type)
end
end
end
end
@unvisited_types = nil
nil
end
|