Skip to content

Commit 3675d3c

Browse files
committed
Improve deprecated argument detection for list and non-null types, and enum values
1 parent a8661fb commit 3675d3c

File tree

4 files changed

+65
-18
lines changed

4 files changed

+65
-18
lines changed

CHANGELOG.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,6 @@
1010

1111
### Bug fixes
1212

13-
# Unreleased
14-
15-
### New features
16-
17-
- `GraphQL::Analysis::AST::FieldUsage`: detects use of deprecated enum value in an argument
18-
1913
# 2.2.5 (10 Jan 2024)
2014

2115
### Bug fixes

lib/graphql/analysis/ast/field_usage.rb

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ def initialize(query)
88
@used_fields = Set.new
99
@used_deprecated_fields = Set.new
1010
@used_deprecated_arguments = Set.new
11+
@used_deprecated_enum_values = Set.new
1112
end
1213

1314
def on_leave_field(node, parent, visitor)
1415
field_defn = visitor.field_definition
1516
field = "#{visitor.parent_type_definition.graphql_name}.#{field_defn.graphql_name}"
1617
@used_fields << field
1718
@used_deprecated_fields << field if field_defn.deprecation_reason
18-
arguments = visitor.query.arguments_for(node, visitor.field_definition)
19+
arguments = visitor.query.arguments_for(node, field_defn)
1920
# If there was an error when preparing this argument object,
2021
# then this might be an error or something:
2122
if arguments.respond_to?(:argument_values)
@@ -28,6 +29,7 @@ def result
2829
used_fields: @used_fields.to_a,
2930
used_deprecated_fields: @used_deprecated_fields.to_a,
3031
used_deprecated_arguments: @used_deprecated_arguments.to_a,
32+
used_deprecated_enum_values: @used_deprecated_enum_values.to_a,
3133
}
3234
end
3335

@@ -41,19 +43,39 @@ def extract_deprecated_arguments(argument_values)
4143

4244
next if argument.value.nil?
4345

44-
if argument.definition.type.kind.input_object?
46+
argument_type = argument.definition.type
47+
if argument_type.non_null?
48+
argument_type = argument_type.of_type
49+
end
50+
51+
if argument_type.kind.input_object?
4552
extract_deprecated_arguments(argument.value.arguments.argument_values) # rubocop:disable Development/ContextIsPassedCop -- runtime args instance
46-
elsif argument.definition.type.kind.enum?
47-
enum_value = argument.definition.type.values[argument.value]
48-
@used_deprecated_arguments << argument.definition.path if enum_value.deprecation_reason
49-
elsif argument.definition.type.list?
50-
argument
51-
.value
52-
.select { |value| value.respond_to?(:arguments) }
53-
.each { |value| extract_deprecated_arguments(value.arguments.argument_values) } # rubocop:disable Development/ContextIsPassedCop -- runtime args instance
53+
elsif argument_type.kind.enum?
54+
extract_deprecated_enum_value(argument_type, argument.value)
55+
elsif argument_type.list?
56+
inner_type = argument_type.unwrap
57+
case inner_type.kind
58+
when TypeKinds::INPUT_OBJECT
59+
argument.value.each do |value|
60+
extract_deprecated_arguments(value.arguments.argument_values) # rubocop:disable Development/ContextIsPassedCop -- runtime args instance
61+
end
62+
when TypeKinds::ENUM
63+
argument.value.each do |value|
64+
extract_deprecated_enum_value(inner_type, value)
65+
end
66+
else
67+
# Not a kind of input that we track
68+
end
5469
end
5570
end
5671
end
72+
73+
def extract_deprecated_enum_value(enum_type, value)
74+
enum_value = @query.warden.enum_values(enum_type).find { |ev| ev.value == value }
75+
if enum_value&.deprecation_reason
76+
@used_deprecated_enum_values << enum_value.path
77+
end
78+
end
5779
end
5880
end
5981
end

spec/graphql/analysis/ast/field_usage_spec.rb

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,23 @@
148148
|}
149149

150150
it "keeps track of deprecated arguments" do
151-
assert_equal ['Query.fromSource.source'], result[:used_deprecated_arguments]
151+
assert_equal ['DairyAnimal.YAK'], result[:used_deprecated_enum_values]
152+
end
153+
154+
describe "tracks non-null/list enums" do
155+
let(:query_string) {%|
156+
query {
157+
cheese(id: 1) {
158+
similarCheese(source: [YAK]) {
159+
id
160+
}
161+
}
162+
}
163+
|}
164+
165+
it "keeps track of deprecated arguments" do
166+
assert_equal ['DairyAnimal.YAK'], result[:used_deprecated_enum_values]
167+
end
152168
end
153169
end
154170

@@ -225,6 +241,20 @@
225241
end
226242
end
227243

244+
245+
describe "mutation with deprecated argument" do
246+
let(:query_string) {%|
247+
mutation {
248+
pushValue(deprecatedTestInput: { oldSource: "deprecated" })
249+
}
250+
|}
251+
252+
it "keeps track of nested deprecated arguments" do
253+
assert_equal ['DairyProductInput.oldSource'], result[:used_deprecated_arguments]
254+
end
255+
end
256+
257+
228258
describe "when an argument prepare raises a GraphQL::ExecutionError" do
229259
class ArgumentErrorFieldUsageSchema < GraphQL::Schema
230260
class FieldUsage < GraphQL::Analysis::AST::FieldUsage
@@ -248,7 +278,7 @@ class Query < GraphQL::Schema::Object
248278
it "skips analysis of those arguments" do
249279
res = ArgumentErrorFieldUsageSchema.execute("{ f(i: 1) }")
250280
assert_equal ["boom!"], res["errors"].map { |e| e["message"] }
251-
assert_equal({used_fields: ["Query.f"], used_deprecated_arguments: [], used_deprecated_fields: []}, res.context[:field_usage])
281+
assert_equal({used_fields: ["Query.f"], used_deprecated_arguments: [], used_deprecated_fields: [], used_deprecated_enum_values: []}, res.context[:field_usage])
252282
end
253283
end
254284
end

spec/support/dummy/schema.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,7 @@ class DairyAppMutation < BaseObject
489489
description "The root for mutations in this schema"
490490
field :push_value, [Integer], null: false, description: "Push a value onto a global array :D" do
491491
argument :value, Integer, as: :val
492+
argument :deprecated_test_input, DairyProductInput
492493
end
493494
def push_value(val:)
494495
GLOBAL_VALUES << val

0 commit comments

Comments
 (0)